From 256cd06460b7bb745a7c60b6ab92aa2ddde03553 Mon Sep 17 00:00:00 2001 From: Manu Sridharan Date: Tue, 4 Sep 2012 15:56:05 -0700 Subject: [PATCH] Convert all Java source files to use Unix line endings; no semantic change --- .../demandpa/driver/DemandCastChecker.java | 606 +- .../polyglot/PolyglotIdentityMapper.java | 458 +- .../com/ibm/wala/cast/java/test/IRTests.java | 894 +- .../ibm/wala/cast/java/test/JavaIRTests.java | 1218 +-- .../java/client/JavaSourceAnalysisEngine.java | 330 +- .../AstJavaZeroOneContainerCFABuilder.java | 150 +- .../cast/java/ipa/slicer/AstJavaSlicer.java | 230 +- .../java/ssa/EnclosingObjectReference.java | 148 +- .../ibm/wala/cast/js/vis/JsViewerDriver.java | 142 +- .../cast/js/html/DefaultSourceExtractor.java | 370 +- .../cast/js/html/DomLessSourceExtractor.java | 558 +- .../ibm/wala/cast/js/html/IHtmlCallback.java | 62 +- .../ibm/wala/cast/js/html/IHtmlParser.java | 62 +- .../com/ibm/wala/cast/js/html/ITag.java | 90 +- .../ibm/wala/cast/js/html/IUrlResolver.java | 72 +- .../cast/js/html/IdentityUrlResolver.java | 50 +- .../wala/cast/js/html/JSSourceExtractor.java | 64 +- .../ibm/wala/cast/js/html/SourceRegion.java | 200 +- .../ibm/wala/cast/js/html/UnicodeReader.java | 244 +- .../ibm/wala/cast/js/html/UrlManipulator.java | 156 +- .../js/html/jericho/JerichoHtmlParser.java | 156 +- .../wala/cast/js/html/jericho/JerichoTag.java | 294 +- .../wala/cast/ipa/callgraph/AstCallGraph.java | 396 +- .../ipa/callgraph/CrossLanguageCallGraph.java | 336 +- .../cast/ir/ssa/AbstractLexicalInvoke.java | 324 +- .../cast/ir/ssa/analysis/LiveAnalysis.java | 634 +- .../cast/ir/translator/ArrayOpHandler.java | 20 +- .../cast/ir/translator/AstTranslator.java | 8540 ++++++++--------- .../cast/loader/CAstAbstractModuleLoader.java | 392 +- .../cast/tree/impl/CAstRewriterFactory.java | 24 +- .../cast/tree/impl/CAstSymbolImplBase.java | 118 +- .../src/annotations/AnnotatedClass1.java | 28 +- .../src/annotations/AnnotatedClass2.java | 18 +- .../annotations/DefaultVisableAnnotation.java | 10 +- .../RuntimeInvisableAnnotation.java | 18 +- .../RuntimeInvisableAnnotation2.java | 18 +- .../RuntimeInvisableAnnotationForMethod.java | 24 +- .../annotations/RuntimeVisableAnnotation.java | 18 +- .../RuntimeVisableAnnotation2.java | 18 +- .../RuntimeVisableAnnotationForMethod.java | 24 +- com.ibm.wala.core.testdata/src/cell/Cell.java | 48 +- .../src/classConstant/ClassConstant.java | 20 +- .../src/cornerCases/Abstract1.java | 40 +- .../src/cornerCases/Abstract2.java | 40 +- .../src/cornerCases/AliasNames.java | 38 +- .../src/cornerCases/Concrete2.java | 38 +- .../src/cornerCases/Locals.java | 50 +- .../src/cornerCases/Main.java | 106 +- .../src/cornerCases/TryFinally.java | 66 +- .../src/cornerCases/YuckyInterface.java | 48 +- .../src/demandpa/A.java | 110 +- .../src/demandpa/ArraySet.java | 132 +- .../src/demandpa/B.java | 90 +- .../src/demandpa/DemandPATestUtil.java | 110 +- .../src/demandpa/Iter.java | 88 +- .../src/demandpa/TestArrayList.java | 118 +- .../src/demandpa/TestArraySet.java | 108 +- .../src/demandpa/TestArraySetIter.java | 104 +- .../src/demandpa/TestArrays.java | 104 +- .../src/demandpa/TestClone.java | 136 +- .../src/demandpa/TestCond.java | 106 +- .../src/demandpa/TestException.java | 112 +- .../src/demandpa/TestFactory.java | 112 +- .../src/demandpa/TestFields.java | 116 +- .../src/demandpa/TestFieldsHarder.java | 96 +- .../src/demandpa/TestGetterSetter.java | 118 +- .../src/demandpa/TestGlobal.java | 112 +- .../src/demandpa/TestHashMapGet.java | 112 +- .../src/demandpa/TestHashSet.java | 106 +- .../src/demandpa/TestHashtableEnum.java | 120 +- .../src/demandpa/TestId.java | 116 +- .../src/demandpa/TestLinkedList.java | 116 +- .../src/demandpa/TestLinkedListIter.java | 116 +- .../src/demandpa/TestLocals.java | 100 +- .../src/demandpa/TestMethodRecursion.java | 136 +- .../src/demandpa/TestMultiDim.java | 106 +- .../src/demandpa/TestNastyPtrs.java | 210 +- .../src/demandpa/TestOnTheFlyCS.java | 134 +- .../src/demandpa/TestOnTheFlySimple.java | 122 +- .../src/demandpa/TestWithinMethodCall.java | 106 +- .../src/hello/Hello.java | 44 +- .../messageFormatTest/MessageFormatBench.java | 46 +- .../src/multiDim/TestMultiDim.java | 42 +- .../src/multiTypes/Foo.java | 70 +- .../src/pi/PiNodeCallGraphTestCase.java | 144 +- .../src/recurse/NList.java | 284 +- .../src/reflection/Helper.java | 106 +- .../src/reflection/Reflect1.java | 40 +- .../src/reflection/Reflect10.java | 32 +- .../src/reflection/Reflect11.java | 32 +- .../src/reflection/Reflect12.java | 32 +- .../src/reflection/Reflect13.java | 34 +- .../src/reflection/Reflect14.java | 44 +- .../src/reflection/Reflect15.java | 44 +- .../src/reflection/Reflect16.java | 34 +- .../src/reflection/Reflect17.java | 32 +- .../src/reflection/Reflect18.java | 36 +- .../src/reflection/Reflect19.java | 34 +- .../src/reflection/Reflect2.java | 36 +- .../src/reflection/Reflect20.java | 44 +- .../src/reflection/Reflect21.java | 42 +- .../src/reflection/Reflect22.java | 56 +- .../src/reflection/Reflect23.java | 60 +- .../src/reflection/Reflect3.java | 34 +- .../src/reflection/Reflect4.java | 24 +- .../src/reflection/Reflect5.java | 38 +- .../src/reflection/Reflect6.java | 38 +- .../src/reflection/Reflect7.java | 46 +- .../src/reflection/Reflect8.java | 34 +- .../src/reflection/Reflect9.java | 32 +- com.ibm.wala.core.testdata/src/slice/A.java | 38 +- com.ibm.wala.core.testdata/src/slice/B.java | 14 +- .../src/slice/Slice1.java | 62 +- .../src/slice/Slice2.java | 66 +- .../src/slice/Slice3.java | 64 +- .../src/slice/Slice4.java | 60 +- .../src/slice/Slice5.java | 62 +- .../src/slice/Slice6.java | 62 +- .../src/slice/Slice7.java | 40 +- .../src/slice/TestArrays.java | 62 +- .../src/slice/TestCD1.java | 68 +- .../src/slice/TestCD2.java | 68 +- .../src/slice/TestCD3.java | 72 +- .../src/slice/TestCD4.java | 86 +- .../src/slice/TestCD5.java | 66 +- .../src/slice/TestCD6.java | 70 +- .../src/slice/TestFields.java | 66 +- .../src/slice/TestGlobal.java | 74 +- .../src/slice/TestId.java | 70 +- .../src/slice/TestMessageFormat.java | 40 +- .../src/slice/TestMultiTarget.java | 70 +- .../src/slice/TestPrimGetterSetter.java | 80 +- .../src/slice/TestRecursion.java | 80 +- .../src/slice/TestThin1.java | 64 +- .../src/typeInference/TI.java | 82 +- .../core/tests/basic/GraphDataflowTest.java | 418 +- .../wala/core/tests/basic/OrdinalSetTest.java | 52 +- .../wala/core/tests/basic/PrimitivesTest.java | 2682 +++--- .../core/tests/callGraph/CallGraphTest.java | 1124 +-- .../tests/callGraph/CallGraphTestUtil.java | 332 +- .../tests/callGraph/ClassConstantTest.java | 152 +- .../wala/core/tests/callGraph/CloneTest.java | 148 +- .../DebuggingBitsetCallGraphTest.java | 148 +- .../tests/callGraph/PiNodeCallGraphTest.java | 228 +- .../core/tests/callGraph/ReflectionTest.java | 1282 +-- .../core/tests/callGraph/SyntheticTest.java | 134 +- .../wala/core/tests/cha/GetTargetsTest.java | 196 +- .../wala/core/tests/cha/InnerClassesTest.java | 196 +- .../wala/core/tests/cha/InterfaceTest.java | 202 +- .../core/tests/cha/LibraryVersionTest.java | 84 +- .../wala/core/tests/cha/SourceMapTest.java | 122 +- .../SemiSparseMutableIntSetTest.java | 70 +- .../tests/collections/TwoLevelVectorTest.java | 74 +- .../core/tests/demandpa/AbstractPtrTest.java | 566 +- .../tests/demandpa/ContextSensitiveTest.java | 370 +- .../core/tests/demandpa/IntraprocTest.java | 130 +- .../core/tests/demandpa/NoRefinePtrTest.java | 308 +- .../core/tests/demandpa/OnTheFlyPtrTest.java | 142 +- .../tests/demandpa/RefineFieldsPtrTest.java | 244 +- .../wala/core/tests/demandpa/TestInfo.java | 216 +- .../tests/demandpa/TunedRefinementTest.java | 302 +- .../wala/core/tests/ir/AnnotationTest.java | 290 +- .../wala/core/tests/ir/CFGSanitizerTest.java | 166 +- .../com/ibm/wala/core/tests/ir/CFGTest.java | 356 +- .../wala/core/tests/ir/CornerCasesTest.java | 174 +- .../core/tests/ir/DeterministicIRTest.java | 346 +- .../wala/core/tests/ir/LocalNamesTest.java | 380 +- .../core/tests/plugin/CoreTestsPlugin.java | 120 +- .../core/tests/ptrs/MultiDimArrayTest.java | 174 +- .../tests/ptrs/TypeBasedArrayAliasTest.java | 192 +- .../wala/core/tests/slicer/SlicerTest.java | 1858 ++-- .../typeInference/TypeInferenceTest.java | 296 +- .../wala/core/tests/util/TestConstants.java | 280 +- .../wala/core/tests/util/WalaTestCase.java | 150 +- .../driver/CompareToZeroOneCFADriver.java | 454 +- .../driver/TestAgainstSimpleDriver.java | 328 +- .../ibm/wala/demandpa/driver/WalaUtil.java | 182 +- .../examples/analysis/CountParameters.java | 126 +- .../examples/analysis/GetLoadedFields.java | 136 +- .../analysis/SimpleThreadEscapeAnalysis.java | 700 +- .../examples/drivers/JavaViewerDriver.java | 124 +- .../wala/examples/drivers/PDFCallGraph.java | 422 +- .../drivers/PDFControlDependenceGraph.java | 324 +- .../com/ibm/wala/examples/drivers/PDFSDG.java | 452 +- .../ibm/wala/examples/drivers/PDFSlice.java | 644 +- .../examples/drivers/PDFTypeHierarchy.java | 296 +- .../ibm/wala/examples/drivers/PDFWalaIR.java | 306 +- .../properties/WalaExamplesProperties.java | 96 +- .../analysis/pointers/BasicHeapGraph.java | 1024 +- .../ibm/wala/analysis/pointers/HeapGraph.java | 154 +- .../AbstractReflectionInterpreter.java | 538 +- .../ClassFactoryContextInterpreter.java | 290 +- .../ClassFactoryContextSelector.java | 256 +- .../ClassNewInstanceContextInterpreter.java | 346 +- .../ClassNewInstanceContextSelector.java | 134 +- .../analysis/reflection/CloneInterpreter.java | 518 +- .../reflection/FactoryBypassInterpreter.java | 1248 +-- .../reflection/FactoryContextSelector.java | 106 +- .../reflection/GetClassContextInterpeter.java | 246 +- .../reflection/GetClassContextSelector.java | 116 +- .../IllegalArgumentExceptionContext.java | 46 +- .../reflection/InstanceKeyWithNode.java | 50 +- .../JavaLangClassContextInterpreter.java | 852 +- .../JavaLangClassContextSelector.java | 192 +- .../analysis/reflection/JavaTypeContext.java | 154 +- .../ReflectionContextInterpreter.java | 222 +- .../reflection/ReflectionContextSelector.java | 114 +- .../ReflectiveInvocationInterpreter.java | 448 +- .../ReflectiveInvocationSelector.java | 270 +- .../stackMachine/AbstractIntStackMachine.java | 2288 ++--- .../wala/analysis/typeInference/ConeType.java | 232 +- .../analysis/typeInference/PointType.java | 228 +- .../analysis/typeInference/PrimitiveType.java | 180 +- .../wala/analysis/typeInference/SetType.java | 202 +- .../typeInference/TypeAbstraction.java | 164 +- .../analysis/typeInference/TypeInference.java | 1608 ++-- .../analysis/typeInference/TypeVariable.java | 98 +- .../src/com/ibm/wala/cfg/AbstractCFG.java | 1334 +-- .../src/com/ibm/wala/cfg/CFGSanitizer.java | 362 +- .../com/ibm/wala/cfg/ControlFlowGraph.java | 184 +- .../src/com/ibm/wala/cfg/IBasicBlock.java | 148 +- .../src/com/ibm/wala/cfg/ShrikeCFG.java | 1102 +-- .../src/com/ibm/wala/cfg/Util.java | 452 +- .../wala/cfg/cdg/ControlDependenceGraph.java | 528 +- .../wala/classLoader/AbstractURLModule.java | 152 +- .../com/ibm/wala/classLoader/ArrayClass.java | 664 +- .../wala/classLoader/ArrayClassLoader.java | 178 +- .../BinaryDirectoryTreeModule.java | 98 +- .../ibm/wala/classLoader/BytecodeClass.java | 1132 +-- .../wala/classLoader/CallSiteReference.java | 414 +- .../ibm/wala/classLoader/ClassFileModule.java | 102 +- .../wala/classLoader/ClassLoaderFactory.java | 64 +- .../classLoader/ClassLoaderFactoryImpl.java | 292 +- .../ibm/wala/classLoader/ClassLoaderImpl.java | 1310 +-- .../com/ibm/wala/classLoader/CodeScanner.java | 926 +- .../wala/classLoader/DirectoryTreeModule.java | 212 +- .../com/ibm/wala/classLoader/FieldImpl.java | 264 +- .../com/ibm/wala/classLoader/FileModule.java | 220 +- .../src/com/ibm/wala/classLoader/IClass.java | 362 +- .../ibm/wala/classLoader/IClassLoader.java | 256 +- .../src/com/ibm/wala/classLoader/IField.java | 92 +- .../src/com/ibm/wala/classLoader/IMember.java | 82 +- .../src/com/ibm/wala/classLoader/IMethod.java | 282 +- .../ibm/wala/classLoader/JarFileEntry.java | 248 +- .../ibm/wala/classLoader/JarFileModule.java | 236 +- .../ibm/wala/classLoader/JavaLanguage.java | 1298 +-- .../com/ibm/wala/classLoader/Language.java | 274 +- .../ibm/wala/classLoader/LanguageImpl.java | 130 +- .../src/com/ibm/wala/classLoader/Module.java | 54 +- .../com/ibm/wala/classLoader/ModuleEntry.java | 122 +- .../wala/classLoader/NestedJarFileModule.java | 542 +- .../wala/classLoader/NewSiteReference.java | 106 +- .../ibm/wala/classLoader/ProgramCounter.java | 144 +- .../ibm/wala/classLoader/ShrikeBTMethod.java | 1622 ++-- .../ibm/wala/classLoader/ShrikeCTMethod.java | 750 +- .../com/ibm/wala/classLoader/ShrikeClass.java | 802 +- .../ibm/wala/classLoader/ShrikeIRFactory.java | 242 +- .../SourceDirectoryTreeModule.java | 118 +- .../wala/classLoader/SourceFileModule.java | 156 +- .../ibm/wala/classLoader/SourceURLModule.java | 70 +- .../ibm/wala/classLoader/SyntheticClass.java | 264 +- .../ibm/wala/classLoader/SyntheticMethod.java | 734 +- .../wala/client/AbstractAnalysisEngine.java | 634 +- .../wala/client/AbstractEngineStopwatch.java | 136 +- .../com/ibm/wala/client/AnalysisEngine.java | 126 +- .../com/ibm/wala/client/EngineStopwatch.java | 80 +- .../dataflow/IFDS/BackwardsSupergraph.java | 698 +- .../IFDS/BoundedPartiallyBalancedSolver.java | 128 +- .../IFDS/BoundedTabulationSolver.java | 116 +- .../ibm/wala/dataflow/IFDS/CallFlowEdges.java | 316 +- .../IFDS/IBinaryReturnFlowFunction.java | 64 +- .../ibm/wala/dataflow/IFDS/IFlowFunction.java | 38 +- .../wala/dataflow/IFDS/IFlowFunctionMap.java | 116 +- .../wala/dataflow/IFDS/IMergeFunction.java | 60 +- .../IFDS/IReversibleFlowFunction.java | 56 +- .../ibm/wala/dataflow/IFDS/ISupergraph.java | 270 +- .../dataflow/IFDS/ITabulationWorklist.java | 52 +- .../dataflow/IFDS/IUnaryFlowFunction.java | 56 +- .../dataflow/IFDS/IdentityFlowFunction.java | 76 +- .../dataflow/IFDS/IdentityFlowFunctions.java | 134 +- .../wala/dataflow/IFDS/LocalPathEdges.java | 904 +- .../wala/dataflow/IFDS/LocalSummaryEdges.java | 316 +- .../PartiallyBalancedTabulationProblem.java | 60 +- .../PartiallyBalancedTabulationSolver.java | 182 +- .../com/ibm/wala/dataflow/IFDS/PathEdge.java | 218 +- .../dataflow/IFDS/SingletonFlowFunction.java | 96 +- .../IFDS/TabulationCancelException.java | 66 +- .../wala/dataflow/IFDS/TabulationDomain.java | 68 +- .../wala/dataflow/IFDS/TabulationProblem.java | 102 +- .../wala/dataflow/IFDS/TabulationResult.java | 114 +- .../wala/dataflow/IFDS/TabulationSolver.java | 2100 ++-- .../wala/dataflow/IFDS/UnorderedDomain.java | 54 +- .../dataflow/IFDS/VectorGenFlowFunction.java | 106 +- .../dataflow/IFDS/VectorKillFlowFunction.java | 98 +- .../ibm/wala/dataflow/ssa/SSAInference.java | 334 +- .../demandpa/alg/AbstractDemandPointsTo.java | 234 +- .../demandpa/alg/BudgetExceededException.java | 102 +- .../com/ibm/wala/demandpa/alg/CallStack.java | 162 +- .../alg/ContextSensitiveStateMachine.java | 586 +- .../alg/DemandRefinementPointsTo.java | 5062 +++++----- .../demandpa/alg/IDemandPointerAnalysis.java | 126 +- .../alg/InstanceFieldKeyAndState.java | 110 +- .../demandpa/alg/InstanceKeyAndState.java | 118 +- .../wala/demandpa/alg/IntraProcFilter.java | 220 +- .../wala/demandpa/alg/PointerKeyAndState.java | 118 +- .../demandpa/alg/SimpleDemandPointsTo.java | 212 +- .../com/ibm/wala/demandpa/alg/WithState.java | 210 +- .../refinepolicy/AlwaysRefineCGPolicy.java | 110 +- .../AlwaysRefineFieldsPolicy.java | 126 +- .../refinepolicy/CallGraphRefinePolicy.java | 118 +- .../alg/refinepolicy/FieldRefinePolicy.java | 142 +- .../refinepolicy/ManualCGRefinePolicy.java | 132 +- .../alg/refinepolicy/ManualFieldPolicy.java | 320 +- .../refinepolicy/ManualRefinementPolicy.java | 130 +- .../alg/refinepolicy/NeverRefineCGPolicy.java | 104 +- .../refinepolicy/NeverRefineFieldsPolicy.java | 110 +- .../alg/refinepolicy/RefinementPolicy.java | 166 +- .../refinepolicy/RefinementPolicyFactory.java | 88 +- .../SinglePassRefinementPolicy.java | 162 +- .../refinepolicy/TunedRefinementPolicy.java | 136 +- .../alg/statemachine/DummyStateMachine.java | 158 +- .../alg/statemachine/StateMachine.java | 134 +- .../alg/statemachine/StateMachineFactory.java | 88 +- .../statemachine/StatesMergedException.java | 104 +- .../flowgraph/AbstractDemandFlowGraph.java | 780 +- .../demandpa/flowgraph/AbstractFlowGraph.java | 988 +- .../flowgraph/AbstractFlowLabelVisitor.java | 228 +- .../demandpa/flowgraph/AssignBarLabel.java | 230 +- .../flowgraph/AssignGlobalBarLabel.java | 172 +- .../demandpa/flowgraph/AssignGlobalLabel.java | 138 +- .../wala/demandpa/flowgraph/AssignLabel.java | 216 +- .../wala/demandpa/flowgraph/CallLabel.java | 158 +- .../flowgraph/DemandPointerFlowGraph.java | 1124 +-- .../flowgraph/DemandValueFlowGraph.java | 916 +- .../demandpa/flowgraph/GetFieldBarLabel.java | 228 +- .../demandpa/flowgraph/GetFieldLabel.java | 208 +- .../wala/demandpa/flowgraph/IFlowLabel.java | 196 +- .../demandpa/flowgraph/MatchBarLabel.java | 154 +- .../wala/demandpa/flowgraph/MatchLabel.java | 140 +- .../wala/demandpa/flowgraph/NewBarLabel.java | 154 +- .../ibm/wala/demandpa/flowgraph/NewLabel.java | 140 +- .../demandpa/flowgraph/ParamBarLabel.java | 162 +- .../wala/demandpa/flowgraph/ParamLabel.java | 144 +- .../flowgraph/PointerKeyAndCallSite.java | 182 +- .../demandpa/flowgraph/PutFieldBarLabel.java | 230 +- .../demandpa/flowgraph/PutFieldLabel.java | 208 +- .../demandpa/flowgraph/ReturnBarLabel.java | 162 +- .../wala/demandpa/flowgraph/ReturnLabel.java | 144 +- .../SimpleDemandPointerFlowGraph.java | 2632 ++--- .../ibm/wala/demandpa/util/ArrayContents.java | 244 +- .../wala/demandpa/util/CallGraphMapUtil.java | 318 +- .../ibm/wala/demandpa/util/MemoryAccess.java | 174 +- .../util/PointerParamValueNumIterator.java | 234 +- .../demandpa/util/SimpleMemoryAccessMap.java | 910 +- .../ibm/wala/escape/FILiveObjectAnalysis.java | 406 +- .../ibm/wala/escape/ILiveObjectAnalysis.java | 106 +- .../wala/escape/IMethodEscapeAnalysis.java | 60 +- .../ibm/wala/escape/INodeEscapeAnalysis.java | 62 +- .../wala/escape/LocalLiveRangeAnalysis.java | 312 +- .../ibm/wala/escape/TrivialMethodEscape.java | 292 +- .../ibm/wala/ipa/callgraph/AnalysisCache.java | 152 +- .../wala/ipa/callgraph/AnalysisOptions.java | 810 +- .../ibm/wala/ipa/callgraph/AnalysisScope.java | 982 +- .../com/ibm/wala/ipa/callgraph/CGNode.java | 146 +- .../com/ibm/wala/ipa/callgraph/CallGraph.java | 148 +- .../wala/ipa/callgraph/CallGraphBuilder.java | 80 +- .../CallGraphBuilderCancelException.java | 124 +- .../wala/ipa/callgraph/CallGraphStats.java | 356 +- .../ipa/callgraph/ClassTargetSelector.java | 82 +- .../com/ibm/wala/ipa/callgraph/Context.java | 52 +- .../ibm/wala/ipa/callgraph/ContextItem.java | 114 +- .../ibm/wala/ipa/callgraph/ContextKey.java | 214 +- .../wala/ipa/callgraph/ContextSelector.java | 84 +- .../ibm/wala/ipa/callgraph/ContextUtil.java | 96 +- .../ibm/wala/ipa/callgraph/Entrypoint.java | 422 +- .../ipa/callgraph/MethodTargetSelector.java | 84 +- .../ipa/callgraph/ShallowAnalysisScope.java | 148 +- .../callgraph/impl/AbstractRootMethod.java | 806 +- .../impl/AllApplicationEntrypoints.java | 124 +- .../impl/ArgumentTypeEntrypoint.java | 224 +- .../ipa/callgraph/impl/BasicCallGraph.java | 776 +- .../ClassHierarchyClassTargetSelector.java | 90 +- .../ClassHierarchyMethodTargetSelector.java | 172 +- .../callgraph/impl/ComposedEntrypoints.java | 92 +- .../impl/ContextInsensitiveSelector.java | 72 +- .../impl/DefaultContextSelector.java | 104 +- .../ipa/callgraph/impl/DefaultEntrypoint.java | 218 +- .../impl/DelegatingContextSelector.java | 130 +- .../wala/ipa/callgraph/impl/Everywhere.java | 102 +- .../ipa/callgraph/impl/ExplicitCallGraph.java | 950 +- .../ipa/callgraph/impl/FakeRootClass.java | 496 +- .../ipa/callgraph/impl/FakeRootMethod.java | 134 +- .../callgraph/impl/FakeWorldClinitMethod.java | 70 +- .../ipa/callgraph/impl/PartialCallGraph.java | 364 +- .../wala/ipa/callgraph/impl/SetOfClasses.java | 108 +- .../callgraph/impl/SubtypesEntrypoint.java | 126 +- .../com/ibm/wala/ipa/callgraph/impl/Util.java | 920 +- .../propagation/AbstractFieldPointerKey.java | 60 +- .../propagation/AbstractLocalPointerKey.java | 46 +- .../propagation/AbstractPointerAnalysis.java | 128 +- .../propagation/AbstractPointerKey.java | 46 +- .../propagation/AbstractPointsToSolver.java | 112 +- .../propagation/AbstractTypeInNode.java | 120 +- .../callgraph/propagation/AllocationSite.java | 168 +- .../propagation/AllocationSiteInNode.java | 90 +- .../AllocationSiteInNodeFactory.java | 246 +- .../propagation/ArrayContentsKey.java | 98 +- .../callgraph/propagation/AssignEquation.java | 78 +- .../callgraph/propagation/AssignOperator.java | 136 +- .../propagation/ClassBasedInstanceKeys.java | 284 +- .../propagation/CloneContextSelector.java | 118 +- .../propagation/ConcreteTypeKey.java | 188 +- .../callgraph/propagation/ConstantKey.java | 122 +- .../callgraph/propagation/ContainerUtil.java | 154 +- .../propagation/FilteredPointerKey.java | 580 +- .../ipa/callgraph/propagation/HeapModel.java | 66 +- .../propagation/IPointerOperator.java | 44 +- .../propagation/IPointsToSolver.java | 46 +- .../propagation/InstanceFieldKey.java | 124 +- .../InstanceFieldKeyWithFilter.java | 100 +- .../propagation/InstanceFieldPointerKey.java | 40 +- .../callgraph/propagation/InstanceKey.java | 72 +- .../propagation/InstanceKeyFactory.java | 104 +- .../propagation/LocalPointerKey.java | 134 +- .../LocalPointerKeyWithFilter.java | 66 +- .../propagation/MultiNewArrayInNode.java | 148 +- .../ipa/callgraph/propagation/NodeKey.java | 102 +- .../propagation/NormalAllocationInNode.java | 82 +- .../propagation/PointerAnalysis.java | 134 +- .../propagation/PointerAnalysisImpl.java | 1096 +-- .../ipa/callgraph/propagation/PointerKey.java | 58 +- .../propagation/PointerKeyComparator.java | 522 +- .../propagation/PointerKeyFactory.java | 124 +- .../callgraph/propagation/PointsToMap.java | 620 +- .../propagation/PointsToSetVariable.java | 332 +- .../PropagationCallGraphBuilder.java | 2924 +++--- .../propagation/PropagationGraph.java | 2176 ++--- .../propagation/PropagationSystem.java | 1830 ++-- .../propagation/ReceiverInstanceContext.java | 154 +- .../ReceiverTypeContextSelector.java | 110 +- .../propagation/ReflectionHandler.java | 260 +- .../callgraph/propagation/ReturnValueKey.java | 72 +- .../propagation/ReturnValueKeyWithFilter.java | 70 +- .../propagation/SSAContextInterpreter.java | 86 +- .../SSAPropagationCallGraphBuilder.java | 4534 ++++----- .../SmushedAllocationSiteInNode.java | 94 +- .../SmushedAllocationSiteInstanceKeys.java | 192 +- .../callgraph/propagation/StandardSolver.java | 158 +- .../callgraph/propagation/StaticFieldKey.java | 98 +- .../propagation/StringConstantCharArray.java | 136 +- .../TargetMethodContextSelector.java | 168 +- .../propagation/UnarySideEffect.java | 146 +- .../callgraph/propagation/cfa/CallString.java | 172 +- .../propagation/cfa/CallStringContext.java | 96 +- .../cfa/CallStringContextSelector.java | 236 +- .../propagation/cfa/CallerContext.java | 146 +- .../propagation/cfa/CallerContextPair.java | 146 +- .../propagation/cfa/CallerSiteContext.java | 124 +- .../cfa/CallerSiteContextPair.java | 154 +- .../cfa/ContainerContextSelector.java | 688 +- .../cfa/ContextInsensitiveSSAInterpreter.java | 150 +- .../cfa/DefaultPointerKeyFactory.java | 150 +- .../cfa/DefaultSSAInterpreter.java | 172 +- .../cfa/DelegatingSSAContextInterpreter.java | 202 +- .../cfa/ExceptionReturnValueKey.java | 80 +- .../cfa/OneLevelSiteContextSelector.java | 106 +- .../propagation/cfa/ZeroXCFABuilder.java | 188 +- .../cfa/ZeroXContainerCFABuilder.java | 98 +- .../propagation/cfa/ZeroXInstanceKeys.java | 700 +- .../propagation/cfa/nCFABuilder.java | 102 +- .../propagation/cfa/nCFAContextSelector.java | 62 +- .../propagation/rta/AbstractRTABuilder.java | 848 +- .../propagation/rta/BasicRTABuilder.java | 462 +- .../callgraph/propagation/rta/CallSite.java | 94 +- .../rta/ContextInsensitiveRTAInterpreter.java | 204 +- .../rta/DefaultRTAInterpreter.java | 182 +- .../rta/DelegatingExplicitCallGraph.java | 538 +- .../rta/DelegatingRTAContextInterpreter.java | 198 +- .../rta/RTAContextInterpreter.java | 118 +- .../propagation/rta/RTASelectorKey.java | 124 +- .../propagation/rta/TypeBasedHeapModel.java | 564 +- .../rta/TypeBasedPointerAnalysis.java | 376 +- .../ipa/cfg/AbstractInterproceduralCFG.java | 1772 ++-- .../ibm/wala/ipa/cfg/BasicBlockInContext.java | 312 +- .../src/com/ibm/wala/ipa/cfg/EdgeFilter.java | 64 +- .../ipa/cfg/ExplodedInterproceduralCFG.java | 144 +- .../ibm/wala/ipa/cfg/InterproceduralCFG.java | 110 +- .../src/com/ibm/wala/ipa/cfg/PrunedCFG.java | 716 +- .../cha/CancelCHAConstructionException.java | 50 +- .../com/ibm/wala/ipa/cha/ClassHierarchy.java | 2576 ++--- .../wala/ipa/cha/ClassHierarchyException.java | 52 +- .../ibm/wala/ipa/cha/ClassHierarchyStats.java | 68 +- .../ibm/wala/ipa/cha/ClassHierarchyUtil.java | 116 +- .../wala/ipa/cha/ClassHierarchyWarning.java | 68 +- .../wala/ipa/cha/IClassHierarchyDweller.java | 36 +- .../ibm/wala/ipa/modref/ArrayLengthKey.java | 98 +- .../modref/DelegatingExtendedHeapModel.java | 218 +- .../wala/ipa/modref/ExtendedHeapModel.java | 52 +- .../src/com/ibm/wala/ipa/modref/GenReach.java | 198 +- .../src/com/ibm/wala/ipa/modref/ModRef.java | 796 +- .../ipa/slicer/ExceptionalReturnCallee.java | 56 +- .../ipa/slicer/ExceptionalReturnCaller.java | 76 +- .../slicer/GetCaughtExceptionStatement.java | 118 +- .../ibm/wala/ipa/slicer/HeapExclusions.java | 240 +- .../ibm/wala/ipa/slicer/HeapReachingDefs.java | 1324 +-- .../ibm/wala/ipa/slicer/HeapStatement.java | 376 +- .../src/com/ibm/wala/ipa/slicer/ISDG.java | 82 +- .../wala/ipa/slicer/MethodEntryStatement.java | 108 +- .../wala/ipa/slicer/MethodExitStatement.java | 106 +- .../wala/ipa/slicer/NormalReturnCallee.java | 56 +- .../wala/ipa/slicer/NormalReturnCaller.java | 76 +- .../ibm/wala/ipa/slicer/NormalStatement.java | 92 +- .../src/com/ibm/wala/ipa/slicer/PDG.java | 2450 ++--- .../com/ibm/wala/ipa/slicer/ParamCallee.java | 130 +- .../com/ibm/wala/ipa/slicer/ParamCaller.java | 142 +- .../com/ibm/wala/ipa/slicer/PhiStatement.java | 118 +- .../com/ibm/wala/ipa/slicer/PiStatement.java | 118 +- .../ipa/slicer/ReachabilityFunctions.java | 146 +- .../src/com/ibm/wala/ipa/slicer/SDG.java | 1620 ++-- .../ibm/wala/ipa/slicer/SDGSupergraph.java | 848 +- .../ibm/wala/ipa/slicer/SliceFunctions.java | 168 +- .../src/com/ibm/wala/ipa/slicer/Slicer.java | 616 +- .../com/ibm/wala/ipa/slicer/Statement.java | 138 +- .../slicer/StatementWithInstructionIndex.java | 128 +- .../wala/ipa/slicer/ValueNumberCarrier.java | 32 +- .../com/ibm/wala/ipa/slicer/thin/CISDG.java | 478 +- .../ibm/wala/ipa/slicer/thin/CISlicer.java | 346 +- .../ibm/wala/ipa/slicer/thin/ThinSlicer.java | 78 +- .../summaries/BypassClassTargetSelector.java | 222 +- .../summaries/BypassMethodTargetSelector.java | 556 +- .../ipa/summaries/BypassSyntheticClass.java | 494 +- .../summaries/BypassSyntheticClassLoader.java | 402 +- .../ibm/wala/ipa/summaries/MethodBypass.java | 436 +- .../ibm/wala/ipa/summaries/MethodSummary.java | 408 +- .../wala/ipa/summaries/ReflectionSummary.java | 146 +- .../wala/ipa/summaries/SummarizedMethod.java | 236 +- .../ibm/wala/ipa/summaries/SyntheticIR.java | 270 +- .../ipa/summaries/SyntheticIRFactory.java | 80 +- .../ipa/summaries/XMLMethodSummaryReader.java | 1760 ++-- .../com/ibm/wala/model/SyntheticFactory.java | 48 +- .../com/ibm/wala/model/java/lang/System.java | 146 +- .../com/ibm/wala/model/java/lang/Thread.java | 48 +- .../wala/model/java/lang/reflect/Array.java | 118 +- .../properties/DefaultPropertiesValues.java | 40 +- .../ibm/wala/properties/WalaProperties.java | 292 +- .../src/com/ibm/wala/ssa/AuxiliaryCache.java | 260 +- .../com/ibm/wala/ssa/CompoundPiPolicy.java | 206 +- .../src/com/ibm/wala/ssa/ConstantValue.java | 218 +- .../src/com/ibm/wala/ssa/DefUse.java | 372 +- .../com/ibm/wala/ssa/DefaultIRFactory.java | 176 +- .../src/com/ibm/wala/ssa/IR.java | 1428 +-- .../src/com/ibm/wala/ssa/IRFactory.java | 72 +- .../src/com/ibm/wala/ssa/ISSABasicBlock.java | 116 +- .../ibm/wala/ssa/IVisitorWithAddresses.java | 62 +- .../com/ibm/wala/ssa/InstanceOfPiPolicy.java | 152 +- .../com/ibm/wala/ssa/NullTestPiPolicy.java | 118 +- .../src/com/ibm/wala/ssa/PhiValue.java | 116 +- .../ibm/wala/ssa/ReflectiveMemberAccess.java | 124 +- .../ssa/SSAAbstractInvokeInstruction.java | 440 +- .../wala/ssa/SSAAbstractThrowInstruction.java | 156 +- .../wala/ssa/SSAAbstractUnaryInstruction.java | 164 +- .../wala/ssa/SSAArrayLengthInstruction.java | 244 +- .../ibm/wala/ssa/SSAArrayLoadInstruction.java | 178 +- .../ssa/SSAArrayReferenceInstruction.java | 186 +- .../wala/ssa/SSAArrayStoreInstruction.java | 176 +- .../ibm/wala/ssa/SSABinaryOpInstruction.java | 258 +- .../src/com/ibm/wala/ssa/SSABuilder.java | 2128 ++-- .../src/com/ibm/wala/ssa/SSACFG.java | 2256 ++--- .../src/com/ibm/wala/ssa/SSACache.java | 306 +- .../ibm/wala/ssa/SSACheckCastInstruction.java | 382 +- .../wala/ssa/SSAComparisonInstruction.java | 240 +- .../ssa/SSAConditionalBranchInstruction.java | 230 +- .../wala/ssa/SSAConversionInstruction.java | 218 +- .../wala/ssa/SSAFieldAccessInstruction.java | 110 +- .../ssa/SSAGetCaughtExceptionInstruction.java | 212 +- .../com/ibm/wala/ssa/SSAGetInstruction.java | 224 +- .../com/ibm/wala/ssa/SSAGotoInstruction.java | 114 +- .../wala/ssa/SSAInstanceofInstruction.java | 236 +- .../src/com/ibm/wala/ssa/SSAInstruction.java | 522 +- .../ibm/wala/ssa/SSAInstructionFactory.java | 204 +- .../ibm/wala/ssa/SSAInvokeInstruction.java | 280 +- .../wala/ssa/SSALoadMetadataInstruction.java | 212 +- .../ibm/wala/ssa/SSAMonitorInstruction.java | 224 +- .../com/ibm/wala/ssa/SSANewInstruction.java | 344 +- .../src/com/ibm/wala/ssa/SSAOptions.java | 198 +- .../com/ibm/wala/ssa/SSAPhiInstruction.java | 322 +- .../com/ibm/wala/ssa/SSAPiInstruction.java | 198 +- .../src/com/ibm/wala/ssa/SSAPiNodePolicy.java | 94 +- .../com/ibm/wala/ssa/SSAPutInstruction.java | 190 +- .../ibm/wala/ssa/SSAReturnInstruction.java | 236 +- .../ibm/wala/ssa/SSASwitchInstruction.java | 280 +- .../com/ibm/wala/ssa/SSAThrowInstruction.java | 80 +- .../ibm/wala/ssa/SSAUnaryOpInstruction.java | 108 +- .../src/com/ibm/wala/ssa/SymbolTable.java | 918 +- .../src/com/ibm/wala/ssa/Value.java | 60 +- .../analysis/DeadAssignmentElimination.java | 390 +- .../analysis/ExplodedControlFlowGraph.java | 1194 +-- .../ibm/wala/types/ClassLoaderReference.java | 242 +- .../src/com/ibm/wala/types/Descriptor.java | 506 +- .../com/ibm/wala/types/FieldReference.java | 260 +- .../com/ibm/wala/types/MemberReference.java | 144 +- .../com/ibm/wala/types/MethodReference.java | 498 +- .../src/com/ibm/wala/types/Selector.java | 168 +- .../src/com/ibm/wala/types/TypeName.java | 742 +- .../src/com/ibm/wala/types/TypeReference.java | 1206 +-- .../wala/types/annotations/Annotation.java | 318 +- .../wala/types/annotations/Annotations.java | 172 +- .../types/generics/ArrayTypeSignature.java | 112 +- .../com/ibm/wala/types/generics/BaseType.java | 116 +- .../wala/types/generics/ClassSignature.java | 268 +- .../types/generics/ClassTypeSignature.java | 280 +- .../types/generics/FormalTypeParameter.java | 392 +- .../types/generics/MethodTypeSignature.java | 246 +- .../ibm/wala/types/generics/Signature.java | 132 +- .../ibm/wala/types/generics/TypeArgument.java | 378 +- .../wala/types/generics/TypeSignature.java | 382 +- .../types/generics/TypeVariableSignature.java | 210 +- .../ibm/wala/util/CancelRuntimeException.java | 62 +- .../wala/util/bytecode/BytecodeStream.java | 1052 +- .../wala/util/config/AnalysisScopeReader.java | 380 +- .../ibm/wala/util/config/FileOfClasses.java | 284 +- .../com/ibm/wala/util/io/FileProvider.java | 378 +- .../com/ibm/wala/util/io/FileSuffixes.java | 198 +- .../com/ibm/wala/util/ref/CacheReference.java | 136 +- .../ibm/wala/util/ref/ReferenceCleanser.java | 184 +- .../ibm/wala/util/scope/JUnitEntryPoints.java | 424 +- .../com/ibm/wala/util/shrike/Exceptions.java | 94 +- .../util/shrike/ShrikeClassReaderHandle.java | 228 +- .../com/ibm/wala/util/shrike/ShrikeUtil.java | 134 +- .../src/com/ibm/wala/util/strings/Atom.java | 862 +- .../wala/util/strings/ImmutableByteArray.java | 182 +- .../ibm/wala/util/strings/StringStuff.java | 1436 +-- .../ibm/wala/util/strings/UTF8Convert.java | 446 +- .../com/ibm/wala/util/warnings/Warning.java | 236 +- .../com/ibm/wala/util/warnings/Warnings.java | 98 +- .../src/com/ibm/wala/viz/PDFViewUtil.java | 358 +- .../jdt/JDTSourceModuleTranslator.java | 354 +- .../wala/ide/AbstractJavaAnalysisAction.java | 436 +- .../source/com/ibm/wala/ide/util/JdtUtil.java | 1194 +-- .../com/ibm/wala/eclipse/headless/Main.java | 90 +- .../wala/examples/drivers/SWTCallGraph.java | 280 +- .../wala/examples/drivers/SWTPointsTo.java | 200 +- .../examples/drivers/SWTTypeHierarchy.java | 278 +- .../wala/ide/tests/util/EclipseTestUtil.java | 270 +- .../classloader/EclipseSourceFileModule.java | 88 +- .../client/EclipseProjectAnalysisEngine.java | 128 +- .../com/ibm/wala/ide/plugin/CorePlugin.java | 192 +- .../ibm/wala/ide/ui/AbstractJFaceRunner.java | 114 +- .../src/com/ibm/wala/ide/ui/IFDSExplorer.java | 254 +- .../com/ibm/wala/ide/ui/SWTTreeViewer.java | 586 +- .../ibm/wala/ide/ui/ViewIFDSLocalAction.java | 464 +- .../src/com/ibm/wala/ide/ui/ViewIRAction.java | 274 +- .../ibm/wala/ide/util/EclipseProjectPath.java | 720 +- .../com/ibm/wala/ide/util/HeadlessUtil.java | 250 +- .../src/com/ibm/wala/shrike/bench/Bench.java | 392 +- .../com/ibm/wala/shrike/bench/Mangler.java | 424 +- .../wala/shrikeBT/BinaryOpInstruction.java | 268 +- .../ibm/wala/shrikeBT/BytecodeConstants.java | 1324 +-- .../wala/shrikeBT/ComparisonInstruction.java | 258 +- .../src/com/ibm/wala/shrikeBT/Compiler.java | 3658 +++---- .../ConditionalBranchInstruction.java | 248 +- .../src/com/ibm/wala/shrikeBT/Constants.java | 1146 +-- .../src/com/ibm/wala/shrikeBT/Decoder.java | 2194 ++--- .../ibm/wala/shrikeBT/IInvokeInstruction.java | 100 +- .../ibm/wala/shrikeBT/InvokeInstruction.java | 430 +- .../ibm/wala/shrikeBT/ShiftInstruction.java | 196 +- .../ibm/wala/shrikeBT/UnaryOpInstruction.java | 178 +- .../src/com/ibm/wala/shrikeBT/Util.java | 1228 +-- .../dataflow/graph/AbstractMeetOperator.java | 58 +- .../wala/dataflow/graph/BasicFramework.java | 84 +- .../wala/dataflow/graph/BitVectorFilter.java | 168 +- .../dataflow/graph/BitVectorFramework.java | 70 +- .../dataflow/graph/BitVectorIdentity.java | 130 +- .../wala/dataflow/graph/BitVectorKillGen.java | 160 +- .../dataflow/graph/BitVectorMinusVector.java | 140 +- .../ibm/wala/dataflow/graph/BitVectorOr.java | 140 +- .../wala/dataflow/graph/BitVectorSolver.java | 78 +- .../wala/dataflow/graph/BitVectorUnion.java | 142 +- .../graph/BitVectorUnionConstant.java | 134 +- .../dataflow/graph/BitVectorUnionVector.java | 136 +- .../wala/dataflow/graph/BooleanIdentity.java | 126 +- .../wala/dataflow/graph/BooleanSolver.java | 82 +- .../ibm/wala/dataflow/graph/BooleanUnion.java | 134 +- .../wala/dataflow/graph/DataflowSolver.java | 654 +- .../dataflow/graph/IKilldallFramework.java | 68 +- .../graph/ITransferFunctionProvider.java | 106 +- .../dataflow/graph/UnaryBitVectorUnion.java | 124 +- .../impl/AbstractFixedPointSolver.java | 1190 +-- .../impl/BasicNullaryStatement.java | 76 +- .../impl/DefaultFixedPointSolver.java | 80 +- .../impl/DefaultFixedPointSystem.java | 556 +- .../fixedpoint/impl/GeneralStatement.java | 430 +- .../wala/fixedpoint/impl/NullaryOperator.java | 70 +- .../fixedpoint/impl/NullaryStatement.java | 210 +- .../ibm/wala/fixedpoint/impl/Worklist.java | 98 +- .../ibm/wala/fixpoint/AbstractOperator.java | 82 +- .../ibm/wala/fixpoint/AbstractStatement.java | 116 +- .../ibm/wala/fixpoint/AbstractVariable.java | 122 +- .../wala/fixpoint/BasicUnaryStatement.java | 62 +- .../ibm/wala/fixpoint/BitVectorVariable.java | 316 +- .../ibm/wala/fixpoint/BooleanVariable.java | 154 +- .../wala/fixpoint/FixedPointConstants.java | 100 +- .../ibm/wala/fixpoint/IFixedPointSolver.java | 74 +- .../wala/fixpoint/IFixedPointStatement.java | 120 +- .../ibm/wala/fixpoint/IFixedPointSystem.java | 146 +- .../src/com/ibm/wala/fixpoint/IVariable.java | 92 +- .../com/ibm/wala/fixpoint/IntSetVariable.java | 364 +- .../com/ibm/wala/fixpoint/TrueOperator.java | 108 +- .../com/ibm/wala/fixpoint/UnaryOperator.java | 94 +- .../src/com/ibm/wala/fixpoint/UnaryOr.java | 104 +- .../com/ibm/wala/fixpoint/UnaryStatement.java | 318 +- .../com/ibm/wala/util/CancelException.java | 62 +- .../src/com/ibm/wala/util/MonitorUtil.java | 152 +- .../src/com/ibm/wala/util/Predicate.java | 280 +- .../src/com/ibm/wala/util/ProgressMaster.java | 266 +- .../src/com/ibm/wala/util/WalaException.java | 64 +- .../util/collections/AbstractMultiMap.java | 344 +- .../wala/util/collections/ArrayIterator.java | 186 +- .../collections/ArrayNonNullIterator.java | 98 +- .../ibm/wala/util/collections/ArraySet.java | 518 +- .../util/collections/ArraySetMultiMap.java | 174 +- .../ibm/wala/util/collections/BimodalMap.java | 372 +- .../util/collections/CollectionFilter.java | 76 +- .../util/collections/ComposedIterator.java | 112 +- .../util/collections/CompoundIntIterator.java | 120 +- .../util/collections/CompoundIterator.java | 98 +- .../util/collections/EmptyIntIterator.java | 84 +- .../wala/util/collections/EmptyIterator.java | 96 +- .../ibm/wala/util/collections/Factory.java | 28 +- .../ibm/wala/util/collections/FifoQueue.java | 376 +- .../collections/FifoQueueNoDuplicates.java | 214 +- .../com/ibm/wala/util/collections/Filter.java | 44 +- .../wala/util/collections/FilterIterator.java | 162 +- .../util/collections/FilterPredicate.java | 72 +- .../wala/util/collections/Filtersection.java | 74 +- .../util/collections/HashCodeComparator.java | 82 +- .../wala/util/collections/HashMapFactory.java | 120 +- .../wala/util/collections/HashSetFactory.java | 126 +- .../util/collections/HashSetMultiMap.java | 124 +- .../com/ibm/wala/util/collections/Heap.java | 340 +- .../ibm/wala/util/collections/IVector.java | 78 +- .../wala/util/collections/ImmutableStack.java | 550 +- .../collections/IndiscriminateFilter.java | 62 +- .../wala/util/collections/IntMapIterator.java | 106 +- .../ibm/wala/util/collections/IntStack.java | 140 +- .../util/collections/Iterator2Collection.java | 304 +- .../util/collections/IteratorPlusOne.java | 106 +- .../util/collections/IteratorPlusTwo.java | 110 +- .../wala/util/collections/IteratorUtil.java | 92 +- .../wala/util/collections/MapIterator.java | 98 +- .../ibm/wala/util/collections/MapUtil.java | 440 +- .../ibm/wala/util/collections/MultiMap.java | 130 +- .../collections/NonNullSingletonIterator.java | 112 +- .../util/collections/ObjectArrayMapping.java | 156 +- .../wala/util/collections/ObjectVisitor.java | 88 +- .../ibm/wala/util/collections/OrFilter.java | 74 +- .../com/ibm/wala/util/collections/Pair.java | 164 +- .../util/collections/ParanoidHashMap.java | 150 +- .../util/collections/ParanoidHashSet.java | 198 +- .../util/collections/ReverseIterator.java | 120 +- .../wala/util/collections/SimpleVector.java | 228 +- .../ibm/wala/util/collections/SmallMap.java | 460 +- .../wala/util/collections/SparseVector.java | 334 +- .../util/collections/ToStringComparator.java | 86 +- .../wala/util/collections/TwoLevelVector.java | 334 +- .../com/ibm/wala/util/collections/Util.java | 656 +- .../com/ibm/wala/util/debug/Assertions.java | 132 +- .../wala/util/debug/UnimplementedError.java | 58 +- .../ibm/wala/util/debug/VerboseAction.java | 44 +- .../com/ibm/wala/util/functions/Function.java | 38 +- .../ibm/wala/util/functions/IntFunction.java | 38 +- .../ibm/wala/util/graph/AbstractGraph.java | 394 +- .../util/graph/AbstractNumberedGraph.java | 154 +- .../src/com/ibm/wala/util/graph/Acyclic.java | 244 +- .../com/ibm/wala/util/graph/BasicTree.java | 116 +- .../com/ibm/wala/util/graph/EdgeManager.java | 132 +- .../src/com/ibm/wala/util/graph/Graph.java | 58 +- .../ibm/wala/util/graph/GraphIntegrity.java | 466 +- .../com/ibm/wala/util/graph/GraphPrint.java | 80 +- .../wala/util/graph/GraphReachability.java | 280 +- .../com/ibm/wala/util/graph/GraphSlicer.java | 632 +- .../ibm/wala/util/graph/INodeWithNumber.java | 70 +- .../util/graph/INodeWithNumberedEdges.java | 106 +- .../ibm/wala/util/graph/InferGraphRoots.java | 74 +- .../com/ibm/wala/util/graph/NodeManager.java | 98 +- .../wala/util/graph/NumberedEdgeManager.java | 60 +- .../ibm/wala/util/graph/NumberedGraph.java | 36 +- .../wala/util/graph/NumberedNodeManager.java | 70 +- .../wala/util/graph/OrderedMultiGraph.java | 56 +- .../src/com/ibm/wala/util/graph/Path.java | 176 +- .../graph/dominators/DominanceFrontiers.java | 186 +- .../util/graph/dominators/Dominators.java | 1170 +-- .../graph/dominators/GenericDominators.java | 98 +- .../util/graph/impl/BasicNodeManager.java | 118 +- .../graph/impl/BasicOrderedMultiGraph.java | 286 +- .../wala/util/graph/impl/DelegatingGraph.java | 200 +- .../impl/DelegatingNumberedEdgeManager.java | 376 +- .../graph/impl/DelegatingNumberedGraph.java | 84 +- .../impl/DelegatingNumberedNodeManager.java | 430 +- .../wala/util/graph/impl/GraphInverter.java | 66 +- .../wala/util/graph/impl/InvertedGraph.java | 84 +- .../graph/impl/InvertedNumberedGraph.java | 82 +- .../util/graph/impl/InvertingEdgeManager.java | 144 +- .../impl/InvertingNumberedEdgeManager.java | 160 +- .../wala/util/graph/impl/NodeWithNumber.java | 74 +- .../graph/impl/NodeWithNumberedEdges.java | 222 +- .../util/graph/impl/NumberedNodeIterator.java | 102 +- .../graph/impl/SlowNumberedNodeManager.java | 198 +- .../graph/impl/SlowSparseNumberedGraph.java | 174 +- .../graph/impl/SparseNumberedEdgeManager.java | 578 +- .../util/graph/impl/SparseNumberedGraph.java | 126 +- .../graph/labeled/AbstractLabeledGraph.java | 208 +- .../labeled/AbstractNumberedLabeledGraph.java | 156 +- .../graph/labeled/LabeledEdgeManager.java | 264 +- .../wala/util/graph/labeled/LabeledGraph.java | 116 +- .../labeled/NumberedLabeledEdgeManager.java | 44 +- .../SlowSparseNumberedLabeledGraph.java | 220 +- .../SparseNumberedLabeledEdgeManager.java | 584 +- .../wala/util/graph/traverse/BFSIterator.java | 322 +- .../util/graph/traverse/BFSPathFinder.java | 436 +- .../graph/traverse/BoundedBFSIterator.java | 386 +- .../com/ibm/wala/util/graph/traverse/DFS.java | 430 +- .../traverse/DFSDiscoverTimeIterator.java | 272 +- .../graph/traverse/DFSFinishTimeIterator.java | 258 +- .../util/graph/traverse/DFSPathFinder.java | 422 +- .../GraphDFSDiscoverTimeIterator.java | 72 +- .../NumberedDFSDiscoverTimeIterator.java | 212 +- .../NumberedDFSFinishTimeIterator.java | 196 +- .../wala/util/graph/traverse/SCCIterator.java | 170 +- .../traverse/SlowDFSDiscoverTimeIterator.java | 180 +- .../traverse/SlowDFSFinishTimeIterator.java | 166 +- .../ibm/wala/util/heapTrace/HeapTracer.java | 1628 ++-- .../util/intset/BasicNaturalRelation.java | 874 +- .../util/intset/BimodalMutableIntSet.java | 736 +- .../intset/BimodalMutableIntSetFactory.java | 110 +- .../src/com/ibm/wala/util/intset/BitSet.java | 470 +- .../com/ibm/wala/util/intset/BitVector.java | 838 +- .../ibm/wala/util/intset/BitVectorIntSet.java | 934 +- .../util/intset/BitVectorIntSetFactory.java | 148 +- .../wala/util/intset/BitVectorRepository.java | 198 +- .../src/com/ibm/wala/util/intset/Bits.java | 166 +- .../util/intset/DebuggingMutableIntSet.java | 680 +- .../intset/DebuggingMutableIntSetFactory.java | 192 +- .../wala/util/intset/FixedSizeBitVector.java | 716 +- .../util/intset/IBinaryNaturalRelation.java | 104 +- .../com/ibm/wala/util/intset/IntIterator.java | 56 +- .../src/com/ibm/wala/util/intset/IntPair.java | 132 +- .../src/com/ibm/wala/util/intset/IntSet.java | 162 +- .../ibm/wala/util/intset/IntSetAction.java | 36 +- .../com/ibm/wala/util/intset/IntSetUtil.java | 506 +- .../com/ibm/wala/util/intset/IntVector.java | 56 +- .../wala/util/intset/IntegerUnionFind.java | 264 +- .../ibm/wala/util/intset/LongIterator.java | 56 +- .../src/com/ibm/wala/util/intset/LongSet.java | 164 +- .../ibm/wala/util/intset/LongSetAction.java | 36 +- .../com/ibm/wala/util/intset/LongSetUtil.java | 414 +- .../wala/util/intset/MultiModalIntVector.java | 528 +- .../ibm/wala/util/intset/MutableIntSet.java | 122 +- .../util/intset/MutableIntSetFactory.java | 64 +- .../ibm/wala/util/intset/MutableLongSet.java | 92 +- .../util/intset/MutableLongSetFactory.java | 50 +- .../ibm/wala/util/intset/MutableMapping.java | 372 +- .../intset/MutableSharedBitVectorIntSet.java | 2190 ++--- .../MutableSharedBitVectorIntSetFactory.java | 136 +- .../wala/util/intset/MutableSparseIntSet.java | 1064 +- .../intset/MutableSparseIntSetFactory.java | 144 +- .../util/intset/MutableSparseLongSet.java | 724 +- .../intset/MutableSparseLongSetFactory.java | 144 +- .../ibm/wala/util/intset/NumberUtility.java | 60 +- .../ibm/wala/util/intset/OffsetBitVector.java | 1046 +- .../util/intset/OffsetOrdinalSetMapping.java | 146 +- .../com/ibm/wala/util/intset/OrdinalSet.java | 392 +- .../wala/util/intset/OrdinalSetMapping.java | 100 +- .../util/intset/SemiSparseMutableIntSet.java | 1480 +-- .../SemiSparseMutableIntSetFactory.java | 144 +- .../ibm/wala/util/intset/SimpleIntVector.java | 262 +- .../ibm/wala/util/intset/SparseIntSet.java | 1108 +-- .../ibm/wala/util/intset/SparseIntVector.java | 180 +- .../wala/util/intset/SparseLongIntVector.java | 176 +- .../ibm/wala/util/intset/SparseLongSet.java | 986 +- .../util/intset/TunedMutableSparseIntSet.java | 86 +- .../util/intset/TunedSimpleIntVector.java | 76 +- .../wala/util/intset/TwoLevelIntVector.java | 214 +- .../src/com/ibm/wala/util/io/CommandLine.java | 134 +- .../src/com/ibm/wala/util/io/FileUtil.java | 392 +- .../src/com/ibm/wala/util/io/Streams.java | 82 +- .../src/com/ibm/wala/util/math/Factorial.java | 178 +- .../src/com/ibm/wala/util/math/Logs.java | 196 +- .../src/com/ibm/wala/util/math/LongUtil.java | 40 +- .../src/com/ibm/wala/util/perf/Stopwatch.java | 126 +- .../com/ibm/wala/util/perf/StopwatchGC.java | 208 +- .../wala/util/processes/BasicLauncher.java | 156 +- .../ibm/wala/util/processes/JavaLauncher.java | 542 +- .../com/ibm/wala/util/processes/Launcher.java | 716 +- .../src/com/ibm/wala/util/tables/Query.java | 182 +- .../com/ibm/wala/util/tables/StringTable.java | 364 +- .../src/com/ibm/wala/util/tables/Table.java | 350 +- .../src/com/ibm/wala/viz/DotUtil.java | 580 +- .../src/com/ibm/wala/viz/NodeDecorator.java | 60 +- .../src/com/ibm/wala/viz/PDFViewLauncher.java | 190 +- 900 files changed, 137644 insertions(+), 137644 deletions(-) diff --git a/com.ibm.wala.cast.java.jdt.test/source/com/ibm/wala/demandpa/driver/DemandCastChecker.java b/com.ibm.wala.cast.java.jdt.test/source/com/ibm/wala/demandpa/driver/DemandCastChecker.java index c2561d023..a384c9be0 100644 --- a/com.ibm.wala.cast.java.jdt.test/source/com/ibm/wala/demandpa/driver/DemandCastChecker.java +++ b/com.ibm.wala.cast.java.jdt.test/source/com/ibm/wala/demandpa/driver/DemandCastChecker.java @@ -1,303 +1,303 @@ -/** - * Refinement Analysis Tools is Copyright (c) 2007 The Regents of the - * University of California (Regents). Provided that this notice and - * the following two paragraphs are included in any distribution of - * Refinement Analysis Tools or its derivative work, Regents agrees - * not to assert any of Regents' copyright rights in Refinement - * Analysis Tools against recipient for recipient's reproduction, - * preparation of derivative works, public display, public - * performance, distribution or sublicensing of Refinement Analysis - * Tools and derivative works, in source code and object code form. - * This agreement not to assert does not confer, by implication, - * estoppel, or otherwise any license or rights in any intellectual - * property of Regents, including, but not limited to, any patents - * of Regents or Regents' employees. - * - * IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, - * INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, - * INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE - * AND ITS DOCUMENTATION, EVEN IF REGENTS HAS BEEN ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE AND FURTHER DISCLAIMS ANY STATUTORY - * WARRANTY OF NON-INFRINGEMENT. THE SOFTWARE AND ACCOMPANYING - * DOCUMENTATION, IF ANY, PROVIDED HEREUNDER IS PROVIDED "AS - * IS". REGENTS HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, - * UPDATES, ENHANCEMENTS, OR MODIFICATIONS. - */ -package com.ibm.wala.demandpa.driver; - -import java.io.IOException; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Iterator; -import java.util.List; -import java.util.Properties; - -import com.ibm.wala.core.tests.callGraph.CallGraphTestUtil; -import com.ibm.wala.core.tests.util.TestConstants; -import com.ibm.wala.demandpa.alg.ContextSensitiveStateMachine; -import com.ibm.wala.demandpa.alg.DemandRefinementPointsTo; -import com.ibm.wala.demandpa.alg.DemandRefinementPointsTo.PointsToResult; -import com.ibm.wala.demandpa.alg.refinepolicy.FieldRefinePolicy; -import com.ibm.wala.demandpa.alg.refinepolicy.ManualFieldPolicy; -import com.ibm.wala.demandpa.alg.refinepolicy.ManualRefinementPolicy; -import com.ibm.wala.demandpa.alg.refinepolicy.RefinementPolicyFactory; -import com.ibm.wala.demandpa.alg.refinepolicy.TunedRefinementPolicy; -import com.ibm.wala.demandpa.alg.statemachine.StateMachineFactory; -import com.ibm.wala.demandpa.flowgraph.IFlowLabel; -import com.ibm.wala.demandpa.util.MemoryAccessMap; -import com.ibm.wala.demandpa.util.SimpleMemoryAccessMap; -import com.ibm.wala.ipa.callgraph.AnalysisCache; -import com.ibm.wala.ipa.callgraph.AnalysisOptions; -import com.ibm.wala.ipa.callgraph.AnalysisScope; -import com.ibm.wala.ipa.callgraph.CGNode; -import com.ibm.wala.ipa.callgraph.CallGraph; -import com.ibm.wala.ipa.callgraph.CallGraphBuilder; -import com.ibm.wala.ipa.callgraph.CallGraphBuilderCancelException; -import com.ibm.wala.ipa.callgraph.CallGraphStats; -import com.ibm.wala.ipa.callgraph.Entrypoint; -import com.ibm.wala.ipa.callgraph.impl.Util; -import com.ibm.wala.ipa.callgraph.propagation.HeapModel; -import com.ibm.wala.ipa.callgraph.propagation.InstanceKey; -import com.ibm.wala.ipa.callgraph.propagation.PointerAnalysis; -import com.ibm.wala.ipa.callgraph.propagation.PointerKey; -import com.ibm.wala.ipa.cha.ClassHierarchy; -import com.ibm.wala.ipa.cha.ClassHierarchyException; -import com.ibm.wala.ipa.cha.IClassHierarchy; -import com.ibm.wala.properties.WalaProperties; -import com.ibm.wala.ssa.IR; -import com.ibm.wala.ssa.SSACheckCastInstruction; -import com.ibm.wala.ssa.SSAInstruction; -import com.ibm.wala.types.ClassLoaderReference; -import com.ibm.wala.types.TypeReference; -import com.ibm.wala.util.CancelException; -import com.ibm.wala.util.NullProgressMonitor; -import com.ibm.wala.util.Predicate; -import com.ibm.wala.util.ProgressMaster; -import com.ibm.wala.util.WalaException; -import com.ibm.wala.util.collections.Pair; -import com.ibm.wala.util.debug.Assertions; - -/** - * Uses a demand-driven points-to analysis to check the safety of downcasts. - * - * @author Manu Sridharan - * - */ -public class DemandCastChecker { - - // maximum number of casts to check - private static final int MAX_CASTS = Integer.MAX_VALUE; - - /** - * @param args - * @throws CancelException - * @throws IllegalArgumentException - * @throws IOException - */ - public static void main(String[] args) throws IllegalArgumentException, CancelException, IOException { - try { - Properties p = new Properties(); - p.putAll(WalaProperties.loadProperties()); - } catch (WalaException e) { - e.printStackTrace(); - Assertions.UNREACHABLE(); - } - - runTestCase(TestConstants.JLEX_MAIN, TestConstants.JLEX, "JLex"); - // runTestCase(TestConstants.HELLO_MAIN, TestConstants.HELLO, "Hello"); - - } - - public static void runTestCase(String mainClass, String scopeFile, String benchName) throws IllegalArgumentException, - CancelException, IOException { - System.err.println("=====BENCHMARK " + benchName + "====="); - System.err.println("analyzing " + benchName); - DemandRefinementPointsTo dmp = null; - try { - dmp = makeDemandPointerAnalysis(scopeFile, mainClass, benchName); - findFailingCasts(dmp.getBaseCallGraph(), dmp); - } catch (ClassHierarchyException e) { - e.printStackTrace(); - } - System.err.println("=*=*=*=*=*=*=*=*=*=*=*=*=*=*"); - System.err.println(""); - System.err.println(""); - } - - private static DemandRefinementPointsTo makeDemandPointerAnalysis(String scopeFile, String mainClass, String benchName) - throws ClassHierarchyException, IllegalArgumentException, CancelException, IOException { - AnalysisScope scope = CallGraphTestUtil.makeJ2SEAnalysisScope(scopeFile, getExclusions(benchName)); - // build a type hierarchy - ClassHierarchy cha = ClassHierarchy.make(scope); - - // set up call graph construction options; mainly what should be considered - // entrypoints? - Iterable entrypoints = com.ibm.wala.ipa.callgraph.impl.Util.makeMainEntrypoints(scope, cha, mainClass); - AnalysisOptions options = CallGraphTestUtil.makeAnalysisOptions(scope, entrypoints); - - System.err.print("constructing call graph..."); - final Pair cgAndPA = buildCallGraph(scope, cha, options); - CallGraph cg = cgAndPA.fst; - System.err.println("done"); - System.err.println(CallGraphStats.getStats(cg)); - MemoryAccessMap fam = new SimpleMemoryAccessMap(cg, cgAndPA.snd.getHeapModel(), false); - DemandRefinementPointsTo fullDemandPointsTo = DemandRefinementPointsTo.makeWithDefaultFlowGraph(cg, heapModel, fam, cha, options, makeStateMachineFactory()); - fullDemandPointsTo.setRefinementPolicyFactory(chooseRefinePolicyFactory(cha)); - return fullDemandPointsTo; - } - - private static String getExclusions(String benchName) { - return CallGraphTestUtil.REGRESSION_EXCLUSIONS; - } - - // if true, construct up-front call graph cheaply (0-CFA) - private static final boolean CHEAP_CG = true; - - private static HeapModel heapModel; - - /** - * builds a call graph, and sets the corresponding heap model for analysis - * - * @param scope - * @param cha - * @param options - * @return - * @throws CancelException - * @throws IllegalArgumentException - */ - private static Pair buildCallGraph(AnalysisScope scope, ClassHierarchy cha, AnalysisOptions options) - throws IllegalArgumentException, CancelException { - CallGraph retCG = null; - PointerAnalysis retPA = null; - final AnalysisCache cache = new AnalysisCache(); - CallGraphBuilder builder; - if (CHEAP_CG) { - builder = Util.makeZeroCFABuilder(options, cache, cha, scope); - // we want vanilla 0-1 CFA, which has one abstract loc per allocation - heapModel = Util.makeVanillaZeroOneCFABuilder(options, cache, cha, scope); - } else { - builder = Util.makeZeroOneContainerCFABuilder(options, cache, cha, scope); - heapModel = (HeapModel) builder; - } - ProgressMaster master = ProgressMaster.make(new NullProgressMonitor()); - master.setMillisPerWorkItem(360000); - master.beginTask("runSolver", 1); - try { - retCG = builder.makeCallGraph(options, master); - retPA = builder.getPointerAnalysis(); - } catch (CallGraphBuilderCancelException e) { - System.err.println("TIMED OUT!!"); - retCG = e.getPartialCallGraph(); - retPA = e.getPartialPointerAnalysis(); - } - return Pair.make(retCG, retPA); - } - - private static RefinementPolicyFactory chooseRefinePolicyFactory(ClassHierarchy cha) { - if (true) { - return new TunedRefinementPolicy.Factory(cha); - } else { - return new ManualRefinementPolicy.Factory(cha); - } - } - - private static StateMachineFactory makeStateMachineFactory() { - return new ContextSensitiveStateMachine.Factory(); - } - - private static List> findFailingCasts(CallGraph cg, DemandRefinementPointsTo dmp) { - final IClassHierarchy cha = dmp.getClassHierarchy(); - List> failing = new ArrayList>(); - - int numSafe = 0, numMightFail = 0; - outer: for (Iterator nodeIter = cg.iterator(); nodeIter.hasNext();) { - CGNode node = nodeIter.next(); - TypeReference declaringClass = node.getMethod().getReference().getDeclaringClass(); - // skip library classes - if (declaringClass.getClassLoader().equals(ClassLoaderReference.Primordial)) { - continue; - } - IR ir = node.getIR(); - if (ir == null) - continue; - SSAInstruction[] instrs = ir.getInstructions(); - for (int i = 0; i < instrs.length; i++) { - if (numSafe + numMightFail > MAX_CASTS) - break outer; - SSAInstruction instruction = instrs[i]; - if (instruction instanceof SSACheckCastInstruction) { - SSACheckCastInstruction castInstr = (SSACheckCastInstruction) instruction; - final TypeReference[] declaredResultTypes = castInstr.getDeclaredResultTypes(); - - boolean primOnly = true; - for (TypeReference t : declaredResultTypes) { - if (! t.isPrimitiveType()) { - primOnly = false; - } - } - if (primOnly) { - continue; - } - - System.err.println("CHECKING " + castInstr + " in " + node.getMethod()); - PointerKey castedPk = heapModel.getPointerKeyForLocal(node, castInstr.getUse(0)); - Predicate castPred = new Predicate() { - - @Override - public boolean test(InstanceKey ik) { - TypeReference ikTypeRef = ik.getConcreteType().getReference(); - for (TypeReference t : declaredResultTypes) { - if (cha.isAssignableFrom(cha.lookupClass(t), cha.lookupClass(ikTypeRef))) { - return true; - } - } - return false; - } - - }; - long startTime = System.currentTimeMillis(); - Pair> queryResult = dmp.getPointsTo(castedPk, castPred); - long runningTime = System.currentTimeMillis() - startTime; - System.err.println("running time: " + runningTime + "ms"); - final FieldRefinePolicy fieldRefinePolicy = dmp.getRefinementPolicy().getFieldRefinePolicy(); - switch (queryResult.fst) { - case SUCCESS: - System.err.println("SAFE: " + castInstr + " in " + node.getMethod()); - if (fieldRefinePolicy instanceof ManualFieldPolicy) { - ManualFieldPolicy hackedFieldPolicy = (ManualFieldPolicy) fieldRefinePolicy; - System.err.println(hackedFieldPolicy.getHistory()); - } - System.err.println("TRAVERSED " + dmp.getNumNodesTraversed() + " nodes"); - numSafe++; - break; - case NOMOREREFINE: - if (queryResult.snd != null) { - System.err.println("MIGHT FAIL: no more refinement possible for " + castInstr + " in " + node.getMethod()); - } else { - System.err.println("MIGHT FAIL: exceeded budget for " + castInstr + " in " + node.getMethod()); - } - failing.add(Pair.make(node, castInstr)); - numMightFail++; - break; - case BUDGETEXCEEDED: - System.err.println("MIGHT FAIL: exceeded budget for " + castInstr + " in " + node.getMethod()); - failing.add(Pair.make(node, castInstr)); - numMightFail++; - break; - default: - Assertions.UNREACHABLE(); - } - } - } - // break outer; - } - System.err.println("TOTAL SAFE: " + numSafe); - System.err.println("TOTAL MIGHT FAIL: " + numMightFail); - return failing; - } - -} +/** + * Refinement Analysis Tools is Copyright (c) 2007 The Regents of the + * University of California (Regents). Provided that this notice and + * the following two paragraphs are included in any distribution of + * Refinement Analysis Tools or its derivative work, Regents agrees + * not to assert any of Regents' copyright rights in Refinement + * Analysis Tools against recipient for recipient's reproduction, + * preparation of derivative works, public display, public + * performance, distribution or sublicensing of Refinement Analysis + * Tools and derivative works, in source code and object code form. + * This agreement not to assert does not confer, by implication, + * estoppel, or otherwise any license or rights in any intellectual + * property of Regents, including, but not limited to, any patents + * of Regents or Regents' employees. + * + * IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, + * INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, + * INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE + * AND ITS DOCUMENTATION, EVEN IF REGENTS HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE AND FURTHER DISCLAIMS ANY STATUTORY + * WARRANTY OF NON-INFRINGEMENT. THE SOFTWARE AND ACCOMPANYING + * DOCUMENTATION, IF ANY, PROVIDED HEREUNDER IS PROVIDED "AS + * IS". REGENTS HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, + * UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + */ +package com.ibm.wala.demandpa.driver; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Iterator; +import java.util.List; +import java.util.Properties; + +import com.ibm.wala.core.tests.callGraph.CallGraphTestUtil; +import com.ibm.wala.core.tests.util.TestConstants; +import com.ibm.wala.demandpa.alg.ContextSensitiveStateMachine; +import com.ibm.wala.demandpa.alg.DemandRefinementPointsTo; +import com.ibm.wala.demandpa.alg.DemandRefinementPointsTo.PointsToResult; +import com.ibm.wala.demandpa.alg.refinepolicy.FieldRefinePolicy; +import com.ibm.wala.demandpa.alg.refinepolicy.ManualFieldPolicy; +import com.ibm.wala.demandpa.alg.refinepolicy.ManualRefinementPolicy; +import com.ibm.wala.demandpa.alg.refinepolicy.RefinementPolicyFactory; +import com.ibm.wala.demandpa.alg.refinepolicy.TunedRefinementPolicy; +import com.ibm.wala.demandpa.alg.statemachine.StateMachineFactory; +import com.ibm.wala.demandpa.flowgraph.IFlowLabel; +import com.ibm.wala.demandpa.util.MemoryAccessMap; +import com.ibm.wala.demandpa.util.SimpleMemoryAccessMap; +import com.ibm.wala.ipa.callgraph.AnalysisCache; +import com.ibm.wala.ipa.callgraph.AnalysisOptions; +import com.ibm.wala.ipa.callgraph.AnalysisScope; +import com.ibm.wala.ipa.callgraph.CGNode; +import com.ibm.wala.ipa.callgraph.CallGraph; +import com.ibm.wala.ipa.callgraph.CallGraphBuilder; +import com.ibm.wala.ipa.callgraph.CallGraphBuilderCancelException; +import com.ibm.wala.ipa.callgraph.CallGraphStats; +import com.ibm.wala.ipa.callgraph.Entrypoint; +import com.ibm.wala.ipa.callgraph.impl.Util; +import com.ibm.wala.ipa.callgraph.propagation.HeapModel; +import com.ibm.wala.ipa.callgraph.propagation.InstanceKey; +import com.ibm.wala.ipa.callgraph.propagation.PointerAnalysis; +import com.ibm.wala.ipa.callgraph.propagation.PointerKey; +import com.ibm.wala.ipa.cha.ClassHierarchy; +import com.ibm.wala.ipa.cha.ClassHierarchyException; +import com.ibm.wala.ipa.cha.IClassHierarchy; +import com.ibm.wala.properties.WalaProperties; +import com.ibm.wala.ssa.IR; +import com.ibm.wala.ssa.SSACheckCastInstruction; +import com.ibm.wala.ssa.SSAInstruction; +import com.ibm.wala.types.ClassLoaderReference; +import com.ibm.wala.types.TypeReference; +import com.ibm.wala.util.CancelException; +import com.ibm.wala.util.NullProgressMonitor; +import com.ibm.wala.util.Predicate; +import com.ibm.wala.util.ProgressMaster; +import com.ibm.wala.util.WalaException; +import com.ibm.wala.util.collections.Pair; +import com.ibm.wala.util.debug.Assertions; + +/** + * Uses a demand-driven points-to analysis to check the safety of downcasts. + * + * @author Manu Sridharan + * + */ +public class DemandCastChecker { + + // maximum number of casts to check + private static final int MAX_CASTS = Integer.MAX_VALUE; + + /** + * @param args + * @throws CancelException + * @throws IllegalArgumentException + * @throws IOException + */ + public static void main(String[] args) throws IllegalArgumentException, CancelException, IOException { + try { + Properties p = new Properties(); + p.putAll(WalaProperties.loadProperties()); + } catch (WalaException e) { + e.printStackTrace(); + Assertions.UNREACHABLE(); + } + + runTestCase(TestConstants.JLEX_MAIN, TestConstants.JLEX, "JLex"); + // runTestCase(TestConstants.HELLO_MAIN, TestConstants.HELLO, "Hello"); + + } + + public static void runTestCase(String mainClass, String scopeFile, String benchName) throws IllegalArgumentException, + CancelException, IOException { + System.err.println("=====BENCHMARK " + benchName + "====="); + System.err.println("analyzing " + benchName); + DemandRefinementPointsTo dmp = null; + try { + dmp = makeDemandPointerAnalysis(scopeFile, mainClass, benchName); + findFailingCasts(dmp.getBaseCallGraph(), dmp); + } catch (ClassHierarchyException e) { + e.printStackTrace(); + } + System.err.println("=*=*=*=*=*=*=*=*=*=*=*=*=*=*"); + System.err.println(""); + System.err.println(""); + } + + private static DemandRefinementPointsTo makeDemandPointerAnalysis(String scopeFile, String mainClass, String benchName) + throws ClassHierarchyException, IllegalArgumentException, CancelException, IOException { + AnalysisScope scope = CallGraphTestUtil.makeJ2SEAnalysisScope(scopeFile, getExclusions(benchName)); + // build a type hierarchy + ClassHierarchy cha = ClassHierarchy.make(scope); + + // set up call graph construction options; mainly what should be considered + // entrypoints? + Iterable entrypoints = com.ibm.wala.ipa.callgraph.impl.Util.makeMainEntrypoints(scope, cha, mainClass); + AnalysisOptions options = CallGraphTestUtil.makeAnalysisOptions(scope, entrypoints); + + System.err.print("constructing call graph..."); + final Pair cgAndPA = buildCallGraph(scope, cha, options); + CallGraph cg = cgAndPA.fst; + System.err.println("done"); + System.err.println(CallGraphStats.getStats(cg)); + MemoryAccessMap fam = new SimpleMemoryAccessMap(cg, cgAndPA.snd.getHeapModel(), false); + DemandRefinementPointsTo fullDemandPointsTo = DemandRefinementPointsTo.makeWithDefaultFlowGraph(cg, heapModel, fam, cha, options, makeStateMachineFactory()); + fullDemandPointsTo.setRefinementPolicyFactory(chooseRefinePolicyFactory(cha)); + return fullDemandPointsTo; + } + + private static String getExclusions(String benchName) { + return CallGraphTestUtil.REGRESSION_EXCLUSIONS; + } + + // if true, construct up-front call graph cheaply (0-CFA) + private static final boolean CHEAP_CG = true; + + private static HeapModel heapModel; + + /** + * builds a call graph, and sets the corresponding heap model for analysis + * + * @param scope + * @param cha + * @param options + * @return + * @throws CancelException + * @throws IllegalArgumentException + */ + private static Pair buildCallGraph(AnalysisScope scope, ClassHierarchy cha, AnalysisOptions options) + throws IllegalArgumentException, CancelException { + CallGraph retCG = null; + PointerAnalysis retPA = null; + final AnalysisCache cache = new AnalysisCache(); + CallGraphBuilder builder; + if (CHEAP_CG) { + builder = Util.makeZeroCFABuilder(options, cache, cha, scope); + // we want vanilla 0-1 CFA, which has one abstract loc per allocation + heapModel = Util.makeVanillaZeroOneCFABuilder(options, cache, cha, scope); + } else { + builder = Util.makeZeroOneContainerCFABuilder(options, cache, cha, scope); + heapModel = (HeapModel) builder; + } + ProgressMaster master = ProgressMaster.make(new NullProgressMonitor()); + master.setMillisPerWorkItem(360000); + master.beginTask("runSolver", 1); + try { + retCG = builder.makeCallGraph(options, master); + retPA = builder.getPointerAnalysis(); + } catch (CallGraphBuilderCancelException e) { + System.err.println("TIMED OUT!!"); + retCG = e.getPartialCallGraph(); + retPA = e.getPartialPointerAnalysis(); + } + return Pair.make(retCG, retPA); + } + + private static RefinementPolicyFactory chooseRefinePolicyFactory(ClassHierarchy cha) { + if (true) { + return new TunedRefinementPolicy.Factory(cha); + } else { + return new ManualRefinementPolicy.Factory(cha); + } + } + + private static StateMachineFactory makeStateMachineFactory() { + return new ContextSensitiveStateMachine.Factory(); + } + + private static List> findFailingCasts(CallGraph cg, DemandRefinementPointsTo dmp) { + final IClassHierarchy cha = dmp.getClassHierarchy(); + List> failing = new ArrayList>(); + + int numSafe = 0, numMightFail = 0; + outer: for (Iterator nodeIter = cg.iterator(); nodeIter.hasNext();) { + CGNode node = nodeIter.next(); + TypeReference declaringClass = node.getMethod().getReference().getDeclaringClass(); + // skip library classes + if (declaringClass.getClassLoader().equals(ClassLoaderReference.Primordial)) { + continue; + } + IR ir = node.getIR(); + if (ir == null) + continue; + SSAInstruction[] instrs = ir.getInstructions(); + for (int i = 0; i < instrs.length; i++) { + if (numSafe + numMightFail > MAX_CASTS) + break outer; + SSAInstruction instruction = instrs[i]; + if (instruction instanceof SSACheckCastInstruction) { + SSACheckCastInstruction castInstr = (SSACheckCastInstruction) instruction; + final TypeReference[] declaredResultTypes = castInstr.getDeclaredResultTypes(); + + boolean primOnly = true; + for (TypeReference t : declaredResultTypes) { + if (! t.isPrimitiveType()) { + primOnly = false; + } + } + if (primOnly) { + continue; + } + + System.err.println("CHECKING " + castInstr + " in " + node.getMethod()); + PointerKey castedPk = heapModel.getPointerKeyForLocal(node, castInstr.getUse(0)); + Predicate castPred = new Predicate() { + + @Override + public boolean test(InstanceKey ik) { + TypeReference ikTypeRef = ik.getConcreteType().getReference(); + for (TypeReference t : declaredResultTypes) { + if (cha.isAssignableFrom(cha.lookupClass(t), cha.lookupClass(ikTypeRef))) { + return true; + } + } + return false; + } + + }; + long startTime = System.currentTimeMillis(); + Pair> queryResult = dmp.getPointsTo(castedPk, castPred); + long runningTime = System.currentTimeMillis() - startTime; + System.err.println("running time: " + runningTime + "ms"); + final FieldRefinePolicy fieldRefinePolicy = dmp.getRefinementPolicy().getFieldRefinePolicy(); + switch (queryResult.fst) { + case SUCCESS: + System.err.println("SAFE: " + castInstr + " in " + node.getMethod()); + if (fieldRefinePolicy instanceof ManualFieldPolicy) { + ManualFieldPolicy hackedFieldPolicy = (ManualFieldPolicy) fieldRefinePolicy; + System.err.println(hackedFieldPolicy.getHistory()); + } + System.err.println("TRAVERSED " + dmp.getNumNodesTraversed() + " nodes"); + numSafe++; + break; + case NOMOREREFINE: + if (queryResult.snd != null) { + System.err.println("MIGHT FAIL: no more refinement possible for " + castInstr + " in " + node.getMethod()); + } else { + System.err.println("MIGHT FAIL: exceeded budget for " + castInstr + " in " + node.getMethod()); + } + failing.add(Pair.make(node, castInstr)); + numMightFail++; + break; + case BUDGETEXCEEDED: + System.err.println("MIGHT FAIL: exceeded budget for " + castInstr + " in " + node.getMethod()); + failing.add(Pair.make(node, castInstr)); + numMightFail++; + break; + default: + Assertions.UNREACHABLE(); + } + } + } + // break outer; + } + System.err.println("TOTAL SAFE: " + numSafe); + System.err.println("TOTAL MIGHT FAIL: " + numMightFail); + return failing; + } + +} diff --git a/com.ibm.wala.cast.java.polyglot/source/com/ibm/wala/cast/java/translator/polyglot/PolyglotIdentityMapper.java b/com.ibm.wala.cast.java.polyglot/source/com/ibm/wala/cast/java/translator/polyglot/PolyglotIdentityMapper.java index a2aaccaea..1e6786234 100644 --- a/com.ibm.wala.cast.java.polyglot/source/com/ibm/wala/cast/java/translator/polyglot/PolyglotIdentityMapper.java +++ b/com.ibm.wala.cast.java.polyglot/source/com/ibm/wala/cast/java/translator/polyglot/PolyglotIdentityMapper.java @@ -1,229 +1,229 @@ -/** - * - */ -package com.ibm.wala.cast.java.translator.polyglot; - -import java.util.Iterator; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; - -import polyglot.types.ArrayType; -import polyglot.types.ClassType; -import polyglot.types.CodeInstance; -import polyglot.types.ConstructorInstance; -import polyglot.types.FieldInstance; -import polyglot.types.InitializerInstance; -import polyglot.types.MemberDef; -import polyglot.types.MethodInstance; -import polyglot.types.PrimitiveType; -import polyglot.types.ProcedureInstance; -import polyglot.types.Type; - -import com.ibm.wala.cast.java.translator.polyglot.PolyglotJava2CAstTranslator.IdentityMapper; -import com.ibm.wala.cast.java.types.JavaPrimitiveTypeMap; -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.collections.HashMapFactory; -import com.ibm.wala.util.debug.Assertions; -import com.ibm.wala.util.strings.Atom; - -/** - * Class responsible for mapping Polyglot type system objects representing types, - * methods and fields to the corresponding WALA TypeReferences, MethodReferences - * and FieldReferences. Used during translation and by clients to help correlate - * WALA analysis results to the various AST nodes. - * @author rfuhrer - */ -public class PolyglotIdentityMapper implements IdentityMapper { - private final Map fTypeMap = HashMapFactory.make(); - - private final Map fFieldMap = HashMapFactory.make(); - - private final Map fMethodMap = HashMapFactory.make(); - - /** - * Map from Polyglot local ClassTypes to their enclosing methods. Used by localTypeToTypeID().
- * Needed since Polyglot doesn't provide this information. (It doesn't need to, since it - * doesn't need to generate unambiguous names for such entities -- it hands the source - * off to javac to generate bytecode. It probably also wouldn't want to, since that would - * create back-pointers from Type objects in the TypeSystem to AST's.) - */ - protected Map fLocalTypeMap = new LinkedHashMap(); - - protected final ClassLoaderReference fClassLoaderRef; - - public PolyglotIdentityMapper(ClassLoaderReference clr) { - fClassLoaderRef= clr; - } - - public FieldReference getFieldRef(FieldInstance field) { - if (!fFieldMap.containsKey(field)) { - FieldReference ref= referenceForField(field); - fFieldMap.put(field, ref); - return ref; - } - return fFieldMap.get(field); - } - - public TypeReference getTypeRef(Type type) { - if (!fTypeMap.containsKey(type)) { - TypeReference ref= referenceForType(type); - fTypeMap.put(type, ref); - return ref; - } - return fTypeMap.get(type); - } - - public MethodReference getMethodRef(CodeInstance method) { - if (!fMethodMap.containsKey(method)) { - MethodReference sel= referenceForMethod(method); - fMethodMap.put(method, sel); - return sel; - } - return fMethodMap.get(method); - } - - public void mapLocalAnonTypeToMethod(ClassType anonLocalType, CodeInstance owningProc) { - fLocalTypeMap.put(anonLocalType, owningProc); - } - - /** - * Create a FieldReference for the given Polyglot FieldInstance.
- * N.B.: This method does not canonicalize the FieldReferences, - * but rather creates a new one for each call. - * You more likely want to call getFieldRef(). This method is exposed - * so that multiple Polyglot instances can use the translation services - * without having FieldInstances collide (producing the dreaded "we are - * TypeSystem_c but type Foo is from TypeSystem_c" exception). - */ - public FieldReference referenceForField(FieldInstance field) { - Type targetType= field.container(); - Type fieldType= field.type(); - TypeReference targetTypeRef= TypeReference.findOrCreate(fClassLoaderRef, typeToTypeID(targetType)); - TypeReference fieldTypeRef= TypeReference.findOrCreate(fClassLoaderRef, typeToTypeID(fieldType)); - Atom fieldName= Atom.findOrCreateUnicodeAtom(field.name().toString()); - FieldReference fieldRef= FieldReference.findOrCreate(targetTypeRef, fieldName, fieldTypeRef); - - return fieldRef; - } - - /** - * Create a TypeReference for the given Polyglot Type.
- * N.B.: This method does not canonicalize the TypeReferences, - * but rather creates a new one for each call. - * You more likely want to call getTypeRef(). This method is exposed - * so that multiple Polyglot instances can use the translation services - * without having Types collide (producing the dreaded "we are - * TypeSystem_c but type Foo is from TypeSystem_c" exception). - */ - public TypeReference referenceForType(Type type) { - TypeName typeName= TypeName.string2TypeName(typeToTypeID(type)); - TypeReference typeRef= TypeReference.findOrCreate(fClassLoaderRef, typeName); - - return typeRef; - } - - private Selector selectorForMethod(CodeInstance procInstance) { - Atom name= - (procInstance instanceof ConstructorInstance) ? - MethodReference.initAtom : - (procInstance instanceof InitializerInstance) ? - MethodReference.clinitName : - Atom.findOrCreateUnicodeAtom(((MethodInstance) procInstance).name().toString()); - - TypeName[] argTypeNames = null; - if (! (procInstance instanceof InitializerInstance)) { - List formalTypes = ((ProcedureInstance)procInstance).formalTypes(); - int numArgs = formalTypes.size(); - // Descriptor prefers null to an empty array - if (numArgs > 0) { - argTypeNames = new TypeName[numArgs]; - - int i = 0; - for(Iterator iter = formalTypes.iterator(); iter.hasNext(); i++) { - Type argType= (Type) iter.next(); - argTypeNames[i]= TypeName.string2TypeName(typeToTypeID(argType)); - } - } - } - - Type retType= - (procInstance instanceof MethodInstance) ? ((MethodInstance) procInstance).returnType() : procInstance.typeSystem().Void(); - TypeName retTypeName= TypeName.string2TypeName(typeToTypeID(retType)); - - Descriptor desc= Descriptor.findOrCreate(argTypeNames, retTypeName); - - return new Selector(name, desc); - } - - /** - * Create a MethodReference for the given Polyglot MethodInstance.
- * N.B.: This method does not canonicalize the MethodReferences, - * but rather creates a new one for each call. - * You more likely want to call getMethodRef(). This method is exposed - * so that multiple Polyglot instances can use the translation services - * without having MethodInstances collide (producing the dreaded "we are - * TypeSystem_c but type Foo is from TypeSystem_c" exception). - */ - public MethodReference referenceForMethod(CodeInstance procInstance) { - // Handles both ConstructorInstance's and MethodInstance's - TypeName ownerType= TypeName.string2TypeName(typeToTypeID(((MemberDef) procInstance.def()).container().get())); - TypeReference ownerTypeRef= TypeReference.findOrCreate(fClassLoaderRef, ownerType); - MethodReference methodRef= MethodReference.findOrCreate(ownerTypeRef, selectorForMethod(procInstance)); - - return methodRef; - } - - /** - * Translates the given Polyglot type to a name suitable for use in a WALA TypeReference - * (i.e. a bytecode-compliant type name). - */ - public String typeToTypeID(Type type) { - if (type.isPrimitive()) { - PrimitiveType ptype= (PrimitiveType) type; - - return JavaPrimitiveTypeMap.getShortName(ptype.name().toString()); - } else if (type.isArray()) { - ArrayType atype= (ArrayType) type; - return "[" + typeToTypeID(atype.base()); - } else if (type.isNull()) { - Assertions.UNREACHABLE("typeToTypeID() encountered a null type!"); - return null; - } - Assertions.productionAssertion(type.isClass(), "typeToTypeID() encountered the type " + type + " that is neither primitive, array, nor class!"); - - ClassType ctype= (ClassType) type; - - return (ctype.isLocal() || ctype.isAnonymous()) ? anonLocalTypeToTypeID(ctype) : composeWALATypeDescriptor(ctype); - } - - public String anonLocalTypeToTypeID(ClassType ctype) { - CodeInstance procInstance= (CodeInstance) fLocalTypeMap.get(ctype); - - String outerTypeID= typeToTypeID(ctype.outer()); - String shortName= (ctype.isAnonymous()) ? PolyglotJava2CAstTranslator.anonTypeName(ctype) : ctype.fullName().name().toString(); - - return outerTypeID + '/' + getMethodRef(procInstance).getSelector() + '/' + shortName; - } - - public String composeWALATypeDescriptor(ClassType ctype) { - return "L" + composeWALATypeName(ctype); - } - - public String composeWALATypeName(ClassType ctype) { - if (ctype.package_() != null) { - String packageName = ctype.package_().fullName().toString(); - - Assertions.productionAssertion(ctype.fullName().toString().startsWith(packageName)); - return packageName.replace('.','/') + "/" + ctype.fullName().toString().substring( packageName.length()+1 ).replace('.','$'); - } else { - return ctype.fullName().toString().replace('.', '$'); - } - } -} +/** + * + */ +package com.ibm.wala.cast.java.translator.polyglot; + +import java.util.Iterator; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; + +import polyglot.types.ArrayType; +import polyglot.types.ClassType; +import polyglot.types.CodeInstance; +import polyglot.types.ConstructorInstance; +import polyglot.types.FieldInstance; +import polyglot.types.InitializerInstance; +import polyglot.types.MemberDef; +import polyglot.types.MethodInstance; +import polyglot.types.PrimitiveType; +import polyglot.types.ProcedureInstance; +import polyglot.types.Type; + +import com.ibm.wala.cast.java.translator.polyglot.PolyglotJava2CAstTranslator.IdentityMapper; +import com.ibm.wala.cast.java.types.JavaPrimitiveTypeMap; +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.collections.HashMapFactory; +import com.ibm.wala.util.debug.Assertions; +import com.ibm.wala.util.strings.Atom; + +/** + * Class responsible for mapping Polyglot type system objects representing types, + * methods and fields to the corresponding WALA TypeReferences, MethodReferences + * and FieldReferences. Used during translation and by clients to help correlate + * WALA analysis results to the various AST nodes. + * @author rfuhrer + */ +public class PolyglotIdentityMapper implements IdentityMapper { + private final Map fTypeMap = HashMapFactory.make(); + + private final Map fFieldMap = HashMapFactory.make(); + + private final Map fMethodMap = HashMapFactory.make(); + + /** + * Map from Polyglot local ClassTypes to their enclosing methods. Used by localTypeToTypeID().
+ * Needed since Polyglot doesn't provide this information. (It doesn't need to, since it + * doesn't need to generate unambiguous names for such entities -- it hands the source + * off to javac to generate bytecode. It probably also wouldn't want to, since that would + * create back-pointers from Type objects in the TypeSystem to AST's.) + */ + protected Map fLocalTypeMap = new LinkedHashMap(); + + protected final ClassLoaderReference fClassLoaderRef; + + public PolyglotIdentityMapper(ClassLoaderReference clr) { + fClassLoaderRef= clr; + } + + public FieldReference getFieldRef(FieldInstance field) { + if (!fFieldMap.containsKey(field)) { + FieldReference ref= referenceForField(field); + fFieldMap.put(field, ref); + return ref; + } + return fFieldMap.get(field); + } + + public TypeReference getTypeRef(Type type) { + if (!fTypeMap.containsKey(type)) { + TypeReference ref= referenceForType(type); + fTypeMap.put(type, ref); + return ref; + } + return fTypeMap.get(type); + } + + public MethodReference getMethodRef(CodeInstance method) { + if (!fMethodMap.containsKey(method)) { + MethodReference sel= referenceForMethod(method); + fMethodMap.put(method, sel); + return sel; + } + return fMethodMap.get(method); + } + + public void mapLocalAnonTypeToMethod(ClassType anonLocalType, CodeInstance owningProc) { + fLocalTypeMap.put(anonLocalType, owningProc); + } + + /** + * Create a FieldReference for the given Polyglot FieldInstance.
+ * N.B.: This method does not canonicalize the FieldReferences, + * but rather creates a new one for each call. + * You more likely want to call getFieldRef(). This method is exposed + * so that multiple Polyglot instances can use the translation services + * without having FieldInstances collide (producing the dreaded "we are + * TypeSystem_c but type Foo is from TypeSystem_c" exception). + */ + public FieldReference referenceForField(FieldInstance field) { + Type targetType= field.container(); + Type fieldType= field.type(); + TypeReference targetTypeRef= TypeReference.findOrCreate(fClassLoaderRef, typeToTypeID(targetType)); + TypeReference fieldTypeRef= TypeReference.findOrCreate(fClassLoaderRef, typeToTypeID(fieldType)); + Atom fieldName= Atom.findOrCreateUnicodeAtom(field.name().toString()); + FieldReference fieldRef= FieldReference.findOrCreate(targetTypeRef, fieldName, fieldTypeRef); + + return fieldRef; + } + + /** + * Create a TypeReference for the given Polyglot Type.
+ * N.B.: This method does not canonicalize the TypeReferences, + * but rather creates a new one for each call. + * You more likely want to call getTypeRef(). This method is exposed + * so that multiple Polyglot instances can use the translation services + * without having Types collide (producing the dreaded "we are + * TypeSystem_c but type Foo is from TypeSystem_c" exception). + */ + public TypeReference referenceForType(Type type) { + TypeName typeName= TypeName.string2TypeName(typeToTypeID(type)); + TypeReference typeRef= TypeReference.findOrCreate(fClassLoaderRef, typeName); + + return typeRef; + } + + private Selector selectorForMethod(CodeInstance procInstance) { + Atom name= + (procInstance instanceof ConstructorInstance) ? + MethodReference.initAtom : + (procInstance instanceof InitializerInstance) ? + MethodReference.clinitName : + Atom.findOrCreateUnicodeAtom(((MethodInstance) procInstance).name().toString()); + + TypeName[] argTypeNames = null; + if (! (procInstance instanceof InitializerInstance)) { + List formalTypes = ((ProcedureInstance)procInstance).formalTypes(); + int numArgs = formalTypes.size(); + // Descriptor prefers null to an empty array + if (numArgs > 0) { + argTypeNames = new TypeName[numArgs]; + + int i = 0; + for(Iterator iter = formalTypes.iterator(); iter.hasNext(); i++) { + Type argType= (Type) iter.next(); + argTypeNames[i]= TypeName.string2TypeName(typeToTypeID(argType)); + } + } + } + + Type retType= + (procInstance instanceof MethodInstance) ? ((MethodInstance) procInstance).returnType() : procInstance.typeSystem().Void(); + TypeName retTypeName= TypeName.string2TypeName(typeToTypeID(retType)); + + Descriptor desc= Descriptor.findOrCreate(argTypeNames, retTypeName); + + return new Selector(name, desc); + } + + /** + * Create a MethodReference for the given Polyglot MethodInstance.
+ * N.B.: This method does not canonicalize the MethodReferences, + * but rather creates a new one for each call. + * You more likely want to call getMethodRef(). This method is exposed + * so that multiple Polyglot instances can use the translation services + * without having MethodInstances collide (producing the dreaded "we are + * TypeSystem_c but type Foo is from TypeSystem_c" exception). + */ + public MethodReference referenceForMethod(CodeInstance procInstance) { + // Handles both ConstructorInstance's and MethodInstance's + TypeName ownerType= TypeName.string2TypeName(typeToTypeID(((MemberDef) procInstance.def()).container().get())); + TypeReference ownerTypeRef= TypeReference.findOrCreate(fClassLoaderRef, ownerType); + MethodReference methodRef= MethodReference.findOrCreate(ownerTypeRef, selectorForMethod(procInstance)); + + return methodRef; + } + + /** + * Translates the given Polyglot type to a name suitable for use in a WALA TypeReference + * (i.e. a bytecode-compliant type name). + */ + public String typeToTypeID(Type type) { + if (type.isPrimitive()) { + PrimitiveType ptype= (PrimitiveType) type; + + return JavaPrimitiveTypeMap.getShortName(ptype.name().toString()); + } else if (type.isArray()) { + ArrayType atype= (ArrayType) type; + return "[" + typeToTypeID(atype.base()); + } else if (type.isNull()) { + Assertions.UNREACHABLE("typeToTypeID() encountered a null type!"); + return null; + } + Assertions.productionAssertion(type.isClass(), "typeToTypeID() encountered the type " + type + " that is neither primitive, array, nor class!"); + + ClassType ctype= (ClassType) type; + + return (ctype.isLocal() || ctype.isAnonymous()) ? anonLocalTypeToTypeID(ctype) : composeWALATypeDescriptor(ctype); + } + + public String anonLocalTypeToTypeID(ClassType ctype) { + CodeInstance procInstance= (CodeInstance) fLocalTypeMap.get(ctype); + + String outerTypeID= typeToTypeID(ctype.outer()); + String shortName= (ctype.isAnonymous()) ? PolyglotJava2CAstTranslator.anonTypeName(ctype) : ctype.fullName().name().toString(); + + return outerTypeID + '/' + getMethodRef(procInstance).getSelector() + '/' + shortName; + } + + public String composeWALATypeDescriptor(ClassType ctype) { + return "L" + composeWALATypeName(ctype); + } + + public String composeWALATypeName(ClassType ctype) { + if (ctype.package_() != null) { + String packageName = ctype.package_().fullName().toString(); + + Assertions.productionAssertion(ctype.fullName().toString().startsWith(packageName)); + return packageName.replace('.','/') + "/" + ctype.fullName().toString().substring( packageName.length()+1 ).replace('.','$'); + } else { + return ctype.fullName().toString().replace('.', '$'); + } + } +} diff --git a/com.ibm.wala.cast.java.test/src/com/ibm/wala/cast/java/test/IRTests.java b/com.ibm.wala.cast.java.test/src/com/ibm/wala/cast/java/test/IRTests.java index da6538c2e..903edf3b5 100644 --- a/com.ibm.wala.cast.java.test/src/com/ibm/wala/cast/java/test/IRTests.java +++ b/com.ibm.wala.cast.java.test/src/com/ibm/wala/cast/java/test/IRTests.java @@ -1,447 +1,447 @@ -/****************************************************************************** - * Copyright (c) 2002 - 2006 IBM Corporation. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * IBM Corporation - initial API and implementation - *****************************************************************************/ -/* - * Created on Oct 3, 2005 - */ -package com.ibm.wala.cast.java.test; - -import java.io.File; -import java.io.IOException; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.Iterator; -import java.util.LinkedList; -import java.util.List; -import java.util.Properties; -import java.util.Set; -import java.util.jar.JarFile; - -import org.junit.Assert; - -import com.ibm.wala.cast.java.client.JavaSourceAnalysisEngine; -import com.ibm.wala.cast.java.ipa.callgraph.JavaSourceAnalysisScope; -import com.ibm.wala.cast.loader.AstClass; -import com.ibm.wala.cast.loader.AstMethod; -import com.ibm.wala.classLoader.IClass; -import com.ibm.wala.classLoader.IClassLoader; -import com.ibm.wala.classLoader.IMethod; -import com.ibm.wala.classLoader.JarFileModule; -import com.ibm.wala.classLoader.Language; -import com.ibm.wala.classLoader.SourceDirectoryTreeModule; -import com.ibm.wala.classLoader.SourceFileModule; -import com.ibm.wala.client.AbstractAnalysisEngine; -import com.ibm.wala.ipa.callgraph.CGNode; -import com.ibm.wala.ipa.callgraph.CallGraph; -import com.ibm.wala.ipa.cha.IClassHierarchy; -import com.ibm.wala.properties.WalaProperties; -import com.ibm.wala.ssa.IR; -import com.ibm.wala.ssa.SSAInstruction; -import com.ibm.wala.types.ClassLoaderReference; -import com.ibm.wala.types.MethodReference; -import com.ibm.wala.types.TypeName; -import com.ibm.wala.types.TypeReference; -import com.ibm.wala.util.CancelException; -import com.ibm.wala.util.collections.HashSetFactory; -import com.ibm.wala.util.collections.Pair; -import com.ibm.wala.util.debug.Assertions; -import com.ibm.wala.util.strings.Atom; - -public abstract class IRTests { - - protected IRTests(String projectName) { - this.projectName = projectName; - } - - protected final String projectName; - - protected static String javaHomePath; - - private String testSrcPath = "." + File.separator + "src"; - - public static List rtJar; - - protected static List emptyList = Collections.emptyList(); - - static { - boolean found = false; - try { - rtJar = new LinkedList(); - - Properties p = WalaProperties.loadProperties(); - javaHomePath = p.getProperty(WalaProperties.J2SE_DIR); - - if (new File(javaHomePath).isDirectory()) { - if ("Mac OS X".equals(System.getProperty("os.name"))) { // nick - /** - * todo: {@link WalaProperties#getJ2SEJarFiles()} - */ - rtJar.add(javaHomePath + "/classes.jar"); - rtJar.add(javaHomePath + "/ui.jar"); - } else { - rtJar.add(javaHomePath + File.separator + "classes.jar"); - rtJar.add(javaHomePath + File.separator + "rt.jar"); - rtJar.add(javaHomePath + File.separator + "core.jar"); - rtJar.add(javaHomePath + File.separator + "vm.jar"); - } - found = true; - } - } catch (Exception e) { - // no properties - } - - if (!found) { - javaHomePath = System.getProperty("java.home"); - if ("Mac OS X".equals(System.getProperty("os.name"))) { // nick - rtJar.add(javaHomePath + "/../Classes/classes.jar"); - rtJar.add(javaHomePath + "/../Classes/ui.jar"); - } else { - rtJar.add(javaHomePath + File.separator + "lib" + File.separator + "rt.jar"); - rtJar.add(javaHomePath + File.separator + "lib" + File.separator + "core.jar"); - rtJar.add(javaHomePath + File.separator + "lib" + File.separator + "vm.jar"); - rtJar.add(javaHomePath + File.separator + "lib" + File.separator + "classes.jar"); - } - } - } - - public interface IRAssertion { - - void check(CallGraph cg); - - } - - protected static class EdgeAssertions implements IRAssertion { - public final String srcDescriptor; - - public final List/* */ tgtDescriptors = new ArrayList(); - - public EdgeAssertions(String srcDescriptor) { - this.srcDescriptor = srcDescriptor; - } - - public static EdgeAssertions make(String srcDescriptor, String tgtDescriptor) { - EdgeAssertions ea = new EdgeAssertions(srcDescriptor); - ea.tgtDescriptors.add(tgtDescriptor); - return ea; - } - - public static EdgeAssertions make(String srcDescriptor, String tgtDescriptor1, String tgtDescriptor2) { - EdgeAssertions ea = new EdgeAssertions(srcDescriptor); - ea.tgtDescriptors.add(tgtDescriptor1); - ea.tgtDescriptors.add(tgtDescriptor2); - return ea; - } - - public static EdgeAssertions make(String srcDescriptor, String tgtDescriptor1, String tgtDescriptor2, String tgtDescriptor3) { - EdgeAssertions ea = new EdgeAssertions(srcDescriptor); - ea.tgtDescriptors.add(tgtDescriptor1); - ea.tgtDescriptors.add(tgtDescriptor2); - ea.tgtDescriptors.add(tgtDescriptor3); - return ea; - } - - public static EdgeAssertions make(String srcDescriptor, String tgtDescriptor1, String tgtDescriptor2, String tgtDescriptor3, - String tgtDescriptor4) { - EdgeAssertions ea = new EdgeAssertions(srcDescriptor); - ea.tgtDescriptors.add(tgtDescriptor1); - ea.tgtDescriptors.add(tgtDescriptor2); - ea.tgtDescriptors.add(tgtDescriptor3); - ea.tgtDescriptors.add(tgtDescriptor4); - return ea; - } - - public void check(CallGraph callGraph) { - MethodReference srcMethod = descriptorToMethodRef(this.srcDescriptor, callGraph.getClassHierarchy()); - Set srcNodes = callGraph.getNodes(srcMethod); - - if (srcNodes.size() == 0) { - System.err.println(("Unreachable/non-existent method: " + srcMethod)); - return; - } - if (srcNodes.size() > 1) { - System.err.println("Context-sensitive call graph?"); - } - - // Assume only one node for src method - CGNode srcNode = srcNodes.iterator().next(); - - for (String target : this.tgtDescriptors) { - MethodReference tgtMethod = descriptorToMethodRef(target, callGraph.getClassHierarchy()); - // Assume only one node for target method - Set tgtNodes = callGraph.getNodes(tgtMethod); - if (tgtNodes.size() == 0) { - System.err.println(("Unreachable/non-existent method: " + tgtMethod)); - continue; - } - CGNode tgtNode = tgtNodes.iterator().next(); - - boolean found = false; - for (Iterator succIter = callGraph.getSuccNodes(srcNode); succIter.hasNext();) { - CGNode succ = succIter.next(); - - if (tgtNode == succ) { - found = true; - break; - } - } - if (!found) { - System.err.println(("Missing edge: " + srcMethod + " -> " + tgtMethod)); - } - } - } - } - - protected static class SourceMapAssertion implements IRAssertion { - private final String method; - - private final String variableName; - - private final int definingLineNumber; - - protected SourceMapAssertion(String method, String variableName, int definingLineNumber) { - this.method = method; - this.variableName = variableName; - this.definingLineNumber = definingLineNumber; - } - - public void check(CallGraph cg) { - - MethodReference mref = descriptorToMethodRef(method, cg.getClassHierarchy()); - - for (CGNode cgNode : cg.getNodes(mref)) { - Assert.assertTrue("failed for " + this.variableName + " in " + cgNode, this.check(cgNode.getMethod(), cgNode.getIR())); - } - } - - boolean check(IMethod m, IR ir) { - System.err.println(("check for " + variableName + " defined at " + definingLineNumber)); - SSAInstruction[] insts = ir.getInstructions(); - for (int i = 0; i < insts.length; i++) { - if (insts[i] != null) { - int ln = m.getLineNumber(i); - if (ln == definingLineNumber) { - System.err.println((" found " + insts[i] + " at " + ln)); - for (int j = 0; j < insts[i].getNumberOfDefs(); j++) { - int def = insts[i].getDef(j); - System.err.println((" looking at def " + j + ": " + def)); - String[] names = ir.getLocalNames(i, def); - if (names != null) { - for (String name : names) { - System.err.println((" looking at name " + name)); - if (name.equals(variableName)) { - return true; - } - } - } - } - } - } - } - - return false; - } - } - - protected Collection singleTestSrc() { - return Collections.singletonList(getTestSrcPath() + File.separator + singleJavaInputForTest()); - } - - protected Collection singleTestSrc(final String folder) { - return Collections.singletonList(getTestSrcPath() + File.separator + folder + File.separator + singleJavaInputForTest()); - } - - protected Collection singlePkgTestSrc(String pkgName) { - return Collections.singletonList(getTestSrcPath() + File.separator + singleJavaPkgInputForTest(pkgName)); - } - - protected String getTestName() { - StackTraceElement stack[] = new Throwable().getStackTrace(); - for(int i = 0; i <= stack.length; i++) { - if (stack[i].getMethodName().startsWith("test")) { - return stack[i].getMethodName(); - } - } - - throw new Error("test method not found"); - } - - protected String[] simpleTestEntryPoint() { - return new String[] { "L" + getTestName().substring(4) }; - } - - protected String[] simplePkgTestEntryPoint(String pkgName) { - return new String[] { "L" + pkgName + "/" + getTestName().substring(4) }; - } - - protected abstract AbstractAnalysisEngine getAnalysisEngine(String[] mainClassDescriptors, Collection sources, List libs); - - public Pair runTest(Collection sources, List libs, String[] mainClassDescriptors, List ca, - boolean assertReachable) { - AbstractAnalysisEngine engine = getAnalysisEngine(mainClassDescriptors, sources, libs); - - CallGraph callGraph; - try { - callGraph = engine.buildDefaultCallGraph(); - System.err.println(callGraph.toString()); - - // If we've gotten this far, IR has been produced. - dumpIR(callGraph, sources, assertReachable); - - // Now check any assertions as to source mapping - for (IRAssertion IRAssertion : ca) { - IRAssertion.check(callGraph); - } - - return Pair.make(callGraph, engine.getPointerAnalysis()); - } catch (IllegalArgumentException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } catch (CancelException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } catch (IOException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - - return null; -} - - protected static void dumpIR(CallGraph cg, Collection sources, boolean assertReachable) throws IOException { - Set sourcePaths = HashSetFactory.make(); - for(String src : sources) { - sourcePaths.add(src.substring(src.lastIndexOf(File.separator)+1)); - } - - Set unreachable = HashSetFactory.make(); - IClassHierarchy cha = cg.getClassHierarchy(); - IClassLoader sourceLoader = cha.getLoader(JavaSourceAnalysisScope.SOURCE); - for (Iterator iter = sourceLoader.iterateAllClasses(); iter.hasNext();) { - IClass clazz = (IClass) iter.next(); - - System.err.println(clazz); - if (clazz.isInterface()) - continue; - - for (IMethod m : clazz.getDeclaredMethods()) { - if (m.isAbstract()) { - System.err.println(m); - } else { - Iterator nodeIter = cg.getNodes(m.getReference()).iterator(); - if (!nodeIter.hasNext()) { - if (m instanceof AstMethod) { - String fn = ((AstClass)m.getDeclaringClass()).getSourcePosition().getURL().getFile(); - if (sourcePaths.contains(fn.substring(fn.lastIndexOf(File.separator)+1))) { - System.err.println(("Method " + m.getReference() + " not reachable?")); - unreachable.add(m); - } - } - continue; - } - CGNode node = (CGNode) nodeIter.next(); - System.err.println(node.getIR()); - } - } - } - - if (assertReachable) { - Assert.assertTrue("unreachable methods: " + unreachable.toString(), unreachable.isEmpty()); - } - } - - /** - * - * @param srcMethodDescriptor a full method descriptor of the form ldr#type#methName#methSig example: - * Source#Simple1#main#([Ljava/lang/String;)V - * @param cha - * @return - */ - public static MethodReference descriptorToMethodRef(String srcMethodDescriptor, IClassHierarchy cha) { - String[] ldrTypeMeth = srcMethodDescriptor.split("\\#"); - - String loaderName = ldrTypeMeth[0]; - String typeStr = ldrTypeMeth[1]; - String methName = ldrTypeMeth[2]; - String methSig = ldrTypeMeth[3]; - - TypeReference typeRef = findOrCreateTypeReference(loaderName, typeStr, cha); - - Language l = cha.getLoader(typeRef.getClassLoader()).getLanguage(); - return MethodReference.findOrCreate(l, typeRef, methName, methSig); - } - - static TypeReference findOrCreateTypeReference(String loaderName, String typeStr, IClassHierarchy cha) { - ClassLoaderReference clr = findLoader(loaderName, cha); - TypeName typeName = TypeName.string2TypeName("L" + typeStr); - TypeReference typeRef = TypeReference.findOrCreate(clr, typeName); - return typeRef; - } - - private static ClassLoaderReference findLoader(String loaderName, IClassHierarchy cha) { - Atom loaderAtom = Atom.findOrCreateUnicodeAtom(loaderName); - IClassLoader[] loaders = cha.getLoaders(); - for (IClassLoader loader : loaders) { - if (loader.getName() == loaderAtom) { - return loader.getReference(); - } - } - Assertions.UNREACHABLE(); - return null; - } - - protected void populateScope(JavaSourceAnalysisEngine engine, Collection sources, List libs) { - boolean foundLib = false; - for (String lib : libs) { - File libFile = new File(lib); - if (libFile.exists()) { - foundLib = true; - try { - engine.addSystemModule(new JarFileModule(new JarFile(libFile))); - } catch (IOException e) { - Assert.fail(e.getMessage()); - } - } - } - assert foundLib : "couldn't find library file from " + libs; - - for (String srcFilePath : sources) { - String srcFileName = srcFilePath.substring(srcFilePath.lastIndexOf(File.separator) + 1); - File f = new File(srcFilePath); - Assert.assertTrue("couldn't find " + srcFilePath, f.exists()); - if (f.isDirectory()) { - engine.addSourceModule(new SourceDirectoryTreeModule(f)); - } else { - engine.addSourceModule(new SourceFileModule(f, srcFileName)); - } - } - } - - protected void setTestSrcPath(String testSrcPath) { - this.testSrcPath = testSrcPath; - } - - protected String getTestSrcPath() { - return testSrcPath; - } - - protected String singleJavaInputForTest() { - return getTestName().substring(4) + ".java"; - } - - protected String singleInputForTest() { - return getTestName().substring(4); - } - - protected String singleJavaPkgInputForTest(String pkgName) { - return pkgName + File.separator + getTestName().substring(4) + ".java"; - } - -} +/****************************************************************************** + * Copyright (c) 2002 - 2006 IBM Corporation. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *****************************************************************************/ +/* + * Created on Oct 3, 2005 + */ +package com.ibm.wala.cast.java.test; + +import java.io.File; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; +import java.util.Properties; +import java.util.Set; +import java.util.jar.JarFile; + +import org.junit.Assert; + +import com.ibm.wala.cast.java.client.JavaSourceAnalysisEngine; +import com.ibm.wala.cast.java.ipa.callgraph.JavaSourceAnalysisScope; +import com.ibm.wala.cast.loader.AstClass; +import com.ibm.wala.cast.loader.AstMethod; +import com.ibm.wala.classLoader.IClass; +import com.ibm.wala.classLoader.IClassLoader; +import com.ibm.wala.classLoader.IMethod; +import com.ibm.wala.classLoader.JarFileModule; +import com.ibm.wala.classLoader.Language; +import com.ibm.wala.classLoader.SourceDirectoryTreeModule; +import com.ibm.wala.classLoader.SourceFileModule; +import com.ibm.wala.client.AbstractAnalysisEngine; +import com.ibm.wala.ipa.callgraph.CGNode; +import com.ibm.wala.ipa.callgraph.CallGraph; +import com.ibm.wala.ipa.cha.IClassHierarchy; +import com.ibm.wala.properties.WalaProperties; +import com.ibm.wala.ssa.IR; +import com.ibm.wala.ssa.SSAInstruction; +import com.ibm.wala.types.ClassLoaderReference; +import com.ibm.wala.types.MethodReference; +import com.ibm.wala.types.TypeName; +import com.ibm.wala.types.TypeReference; +import com.ibm.wala.util.CancelException; +import com.ibm.wala.util.collections.HashSetFactory; +import com.ibm.wala.util.collections.Pair; +import com.ibm.wala.util.debug.Assertions; +import com.ibm.wala.util.strings.Atom; + +public abstract class IRTests { + + protected IRTests(String projectName) { + this.projectName = projectName; + } + + protected final String projectName; + + protected static String javaHomePath; + + private String testSrcPath = "." + File.separator + "src"; + + public static List rtJar; + + protected static List emptyList = Collections.emptyList(); + + static { + boolean found = false; + try { + rtJar = new LinkedList(); + + Properties p = WalaProperties.loadProperties(); + javaHomePath = p.getProperty(WalaProperties.J2SE_DIR); + + if (new File(javaHomePath).isDirectory()) { + if ("Mac OS X".equals(System.getProperty("os.name"))) { // nick + /** + * todo: {@link WalaProperties#getJ2SEJarFiles()} + */ + rtJar.add(javaHomePath + "/classes.jar"); + rtJar.add(javaHomePath + "/ui.jar"); + } else { + rtJar.add(javaHomePath + File.separator + "classes.jar"); + rtJar.add(javaHomePath + File.separator + "rt.jar"); + rtJar.add(javaHomePath + File.separator + "core.jar"); + rtJar.add(javaHomePath + File.separator + "vm.jar"); + } + found = true; + } + } catch (Exception e) { + // no properties + } + + if (!found) { + javaHomePath = System.getProperty("java.home"); + if ("Mac OS X".equals(System.getProperty("os.name"))) { // nick + rtJar.add(javaHomePath + "/../Classes/classes.jar"); + rtJar.add(javaHomePath + "/../Classes/ui.jar"); + } else { + rtJar.add(javaHomePath + File.separator + "lib" + File.separator + "rt.jar"); + rtJar.add(javaHomePath + File.separator + "lib" + File.separator + "core.jar"); + rtJar.add(javaHomePath + File.separator + "lib" + File.separator + "vm.jar"); + rtJar.add(javaHomePath + File.separator + "lib" + File.separator + "classes.jar"); + } + } + } + + public interface IRAssertion { + + void check(CallGraph cg); + + } + + protected static class EdgeAssertions implements IRAssertion { + public final String srcDescriptor; + + public final List/* */ tgtDescriptors = new ArrayList(); + + public EdgeAssertions(String srcDescriptor) { + this.srcDescriptor = srcDescriptor; + } + + public static EdgeAssertions make(String srcDescriptor, String tgtDescriptor) { + EdgeAssertions ea = new EdgeAssertions(srcDescriptor); + ea.tgtDescriptors.add(tgtDescriptor); + return ea; + } + + public static EdgeAssertions make(String srcDescriptor, String tgtDescriptor1, String tgtDescriptor2) { + EdgeAssertions ea = new EdgeAssertions(srcDescriptor); + ea.tgtDescriptors.add(tgtDescriptor1); + ea.tgtDescriptors.add(tgtDescriptor2); + return ea; + } + + public static EdgeAssertions make(String srcDescriptor, String tgtDescriptor1, String tgtDescriptor2, String tgtDescriptor3) { + EdgeAssertions ea = new EdgeAssertions(srcDescriptor); + ea.tgtDescriptors.add(tgtDescriptor1); + ea.tgtDescriptors.add(tgtDescriptor2); + ea.tgtDescriptors.add(tgtDescriptor3); + return ea; + } + + public static EdgeAssertions make(String srcDescriptor, String tgtDescriptor1, String tgtDescriptor2, String tgtDescriptor3, + String tgtDescriptor4) { + EdgeAssertions ea = new EdgeAssertions(srcDescriptor); + ea.tgtDescriptors.add(tgtDescriptor1); + ea.tgtDescriptors.add(tgtDescriptor2); + ea.tgtDescriptors.add(tgtDescriptor3); + ea.tgtDescriptors.add(tgtDescriptor4); + return ea; + } + + public void check(CallGraph callGraph) { + MethodReference srcMethod = descriptorToMethodRef(this.srcDescriptor, callGraph.getClassHierarchy()); + Set srcNodes = callGraph.getNodes(srcMethod); + + if (srcNodes.size() == 0) { + System.err.println(("Unreachable/non-existent method: " + srcMethod)); + return; + } + if (srcNodes.size() > 1) { + System.err.println("Context-sensitive call graph?"); + } + + // Assume only one node for src method + CGNode srcNode = srcNodes.iterator().next(); + + for (String target : this.tgtDescriptors) { + MethodReference tgtMethod = descriptorToMethodRef(target, callGraph.getClassHierarchy()); + // Assume only one node for target method + Set tgtNodes = callGraph.getNodes(tgtMethod); + if (tgtNodes.size() == 0) { + System.err.println(("Unreachable/non-existent method: " + tgtMethod)); + continue; + } + CGNode tgtNode = tgtNodes.iterator().next(); + + boolean found = false; + for (Iterator succIter = callGraph.getSuccNodes(srcNode); succIter.hasNext();) { + CGNode succ = succIter.next(); + + if (tgtNode == succ) { + found = true; + break; + } + } + if (!found) { + System.err.println(("Missing edge: " + srcMethod + " -> " + tgtMethod)); + } + } + } + } + + protected static class SourceMapAssertion implements IRAssertion { + private final String method; + + private final String variableName; + + private final int definingLineNumber; + + protected SourceMapAssertion(String method, String variableName, int definingLineNumber) { + this.method = method; + this.variableName = variableName; + this.definingLineNumber = definingLineNumber; + } + + public void check(CallGraph cg) { + + MethodReference mref = descriptorToMethodRef(method, cg.getClassHierarchy()); + + for (CGNode cgNode : cg.getNodes(mref)) { + Assert.assertTrue("failed for " + this.variableName + " in " + cgNode, this.check(cgNode.getMethod(), cgNode.getIR())); + } + } + + boolean check(IMethod m, IR ir) { + System.err.println(("check for " + variableName + " defined at " + definingLineNumber)); + SSAInstruction[] insts = ir.getInstructions(); + for (int i = 0; i < insts.length; i++) { + if (insts[i] != null) { + int ln = m.getLineNumber(i); + if (ln == definingLineNumber) { + System.err.println((" found " + insts[i] + " at " + ln)); + for (int j = 0; j < insts[i].getNumberOfDefs(); j++) { + int def = insts[i].getDef(j); + System.err.println((" looking at def " + j + ": " + def)); + String[] names = ir.getLocalNames(i, def); + if (names != null) { + for (String name : names) { + System.err.println((" looking at name " + name)); + if (name.equals(variableName)) { + return true; + } + } + } + } + } + } + } + + return false; + } + } + + protected Collection singleTestSrc() { + return Collections.singletonList(getTestSrcPath() + File.separator + singleJavaInputForTest()); + } + + protected Collection singleTestSrc(final String folder) { + return Collections.singletonList(getTestSrcPath() + File.separator + folder + File.separator + singleJavaInputForTest()); + } + + protected Collection singlePkgTestSrc(String pkgName) { + return Collections.singletonList(getTestSrcPath() + File.separator + singleJavaPkgInputForTest(pkgName)); + } + + protected String getTestName() { + StackTraceElement stack[] = new Throwable().getStackTrace(); + for(int i = 0; i <= stack.length; i++) { + if (stack[i].getMethodName().startsWith("test")) { + return stack[i].getMethodName(); + } + } + + throw new Error("test method not found"); + } + + protected String[] simpleTestEntryPoint() { + return new String[] { "L" + getTestName().substring(4) }; + } + + protected String[] simplePkgTestEntryPoint(String pkgName) { + return new String[] { "L" + pkgName + "/" + getTestName().substring(4) }; + } + + protected abstract AbstractAnalysisEngine getAnalysisEngine(String[] mainClassDescriptors, Collection sources, List libs); + + public Pair runTest(Collection sources, List libs, String[] mainClassDescriptors, List ca, + boolean assertReachable) { + AbstractAnalysisEngine engine = getAnalysisEngine(mainClassDescriptors, sources, libs); + + CallGraph callGraph; + try { + callGraph = engine.buildDefaultCallGraph(); + System.err.println(callGraph.toString()); + + // If we've gotten this far, IR has been produced. + dumpIR(callGraph, sources, assertReachable); + + // Now check any assertions as to source mapping + for (IRAssertion IRAssertion : ca) { + IRAssertion.check(callGraph); + } + + return Pair.make(callGraph, engine.getPointerAnalysis()); + } catch (IllegalArgumentException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (CancelException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (IOException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + + return null; +} + + protected static void dumpIR(CallGraph cg, Collection sources, boolean assertReachable) throws IOException { + Set sourcePaths = HashSetFactory.make(); + for(String src : sources) { + sourcePaths.add(src.substring(src.lastIndexOf(File.separator)+1)); + } + + Set unreachable = HashSetFactory.make(); + IClassHierarchy cha = cg.getClassHierarchy(); + IClassLoader sourceLoader = cha.getLoader(JavaSourceAnalysisScope.SOURCE); + for (Iterator iter = sourceLoader.iterateAllClasses(); iter.hasNext();) { + IClass clazz = (IClass) iter.next(); + + System.err.println(clazz); + if (clazz.isInterface()) + continue; + + for (IMethod m : clazz.getDeclaredMethods()) { + if (m.isAbstract()) { + System.err.println(m); + } else { + Iterator nodeIter = cg.getNodes(m.getReference()).iterator(); + if (!nodeIter.hasNext()) { + if (m instanceof AstMethod) { + String fn = ((AstClass)m.getDeclaringClass()).getSourcePosition().getURL().getFile(); + if (sourcePaths.contains(fn.substring(fn.lastIndexOf(File.separator)+1))) { + System.err.println(("Method " + m.getReference() + " not reachable?")); + unreachable.add(m); + } + } + continue; + } + CGNode node = (CGNode) nodeIter.next(); + System.err.println(node.getIR()); + } + } + } + + if (assertReachable) { + Assert.assertTrue("unreachable methods: " + unreachable.toString(), unreachable.isEmpty()); + } + } + + /** + * + * @param srcMethodDescriptor a full method descriptor of the form ldr#type#methName#methSig example: + * Source#Simple1#main#([Ljava/lang/String;)V + * @param cha + * @return + */ + public static MethodReference descriptorToMethodRef(String srcMethodDescriptor, IClassHierarchy cha) { + String[] ldrTypeMeth = srcMethodDescriptor.split("\\#"); + + String loaderName = ldrTypeMeth[0]; + String typeStr = ldrTypeMeth[1]; + String methName = ldrTypeMeth[2]; + String methSig = ldrTypeMeth[3]; + + TypeReference typeRef = findOrCreateTypeReference(loaderName, typeStr, cha); + + Language l = cha.getLoader(typeRef.getClassLoader()).getLanguage(); + return MethodReference.findOrCreate(l, typeRef, methName, methSig); + } + + static TypeReference findOrCreateTypeReference(String loaderName, String typeStr, IClassHierarchy cha) { + ClassLoaderReference clr = findLoader(loaderName, cha); + TypeName typeName = TypeName.string2TypeName("L" + typeStr); + TypeReference typeRef = TypeReference.findOrCreate(clr, typeName); + return typeRef; + } + + private static ClassLoaderReference findLoader(String loaderName, IClassHierarchy cha) { + Atom loaderAtom = Atom.findOrCreateUnicodeAtom(loaderName); + IClassLoader[] loaders = cha.getLoaders(); + for (IClassLoader loader : loaders) { + if (loader.getName() == loaderAtom) { + return loader.getReference(); + } + } + Assertions.UNREACHABLE(); + return null; + } + + protected void populateScope(JavaSourceAnalysisEngine engine, Collection sources, List libs) { + boolean foundLib = false; + for (String lib : libs) { + File libFile = new File(lib); + if (libFile.exists()) { + foundLib = true; + try { + engine.addSystemModule(new JarFileModule(new JarFile(libFile))); + } catch (IOException e) { + Assert.fail(e.getMessage()); + } + } + } + assert foundLib : "couldn't find library file from " + libs; + + for (String srcFilePath : sources) { + String srcFileName = srcFilePath.substring(srcFilePath.lastIndexOf(File.separator) + 1); + File f = new File(srcFilePath); + Assert.assertTrue("couldn't find " + srcFilePath, f.exists()); + if (f.isDirectory()) { + engine.addSourceModule(new SourceDirectoryTreeModule(f)); + } else { + engine.addSourceModule(new SourceFileModule(f, srcFileName)); + } + } + } + + protected void setTestSrcPath(String testSrcPath) { + this.testSrcPath = testSrcPath; + } + + protected String getTestSrcPath() { + return testSrcPath; + } + + protected String singleJavaInputForTest() { + return getTestName().substring(4) + ".java"; + } + + protected String singleInputForTest() { + return getTestName().substring(4); + } + + protected String singleJavaPkgInputForTest(String pkgName) { + return pkgName + File.separator + getTestName().substring(4) + ".java"; + } + +} diff --git a/com.ibm.wala.cast.java.test/src/com/ibm/wala/cast/java/test/JavaIRTests.java b/com.ibm.wala.cast.java.test/src/com/ibm/wala/cast/java/test/JavaIRTests.java index 679cc3ea8..c94ec2ae7 100644 --- a/com.ibm.wala.cast.java.test/src/com/ibm/wala/cast/java/test/JavaIRTests.java +++ b/com.ibm.wala.cast.java.test/src/com/ibm/wala/cast/java/test/JavaIRTests.java @@ -1,609 +1,609 @@ -/****************************************************************************** - * Copyright (c) 2002 - 2006 IBM Corporation. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * IBM Corporation - initial API and implementation - *****************************************************************************/ -/* - * Created on Oct 21, 2005 - */ -package com.ibm.wala.cast.java.test; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; -import java.util.Iterator; -import java.util.List; -import java.util.Set; - -import junit.framework.Assert; - -import org.junit.Test; - -import com.ibm.wala.cast.java.ipa.callgraph.JavaSourceAnalysisScope; -import com.ibm.wala.cast.java.ipa.slicer.AstJavaSlicer; -import com.ibm.wala.cast.java.loader.JavaSourceLoaderImpl; -import com.ibm.wala.cast.java.ssa.EnclosingObjectReference; -import com.ibm.wala.classLoader.IClass; -import com.ibm.wala.classLoader.Language; -import com.ibm.wala.core.tests.slicer.SlicerTest; -import com.ibm.wala.ipa.callgraph.CGNode; -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.slicer.SDG; -import com.ibm.wala.ipa.slicer.Statement; -import com.ibm.wala.ssa.SSAArrayLengthInstruction; -import com.ibm.wala.ssa.SSAArrayReferenceInstruction; -import com.ibm.wala.ssa.SSAArrayStoreInstruction; -import com.ibm.wala.ssa.SSAGetInstruction; -import com.ibm.wala.ssa.SSAInstruction; -import com.ibm.wala.ssa.SSANewInstruction; -import com.ibm.wala.ssa.SymbolTable; -import com.ibm.wala.types.Descriptor; -import com.ibm.wala.types.FieldReference; -import com.ibm.wala.types.MethodReference; -import com.ibm.wala.types.TypeName; -import com.ibm.wala.types.TypeReference; -import com.ibm.wala.util.CancelException; -import com.ibm.wala.util.collections.Pair; -import com.ibm.wala.util.strings.Atom; - -public abstract class JavaIRTests extends IRTests { - - public JavaIRTests(String projectName) { - super(projectName); - } - - public JavaIRTests() { - this(null); - } - - @Test public void testSimple1() { - - List assertions = Arrays.asList( - new SourceMapAssertion("Source#Simple1#doStuff#(I)V", "prod", 24), - new SourceMapAssertion("Source#Simple1#doStuff#(I)V", "j", 23), - new SourceMapAssertion("Source#Simple1#main#([Ljava/lang/String;)V", "s", 32), - new SourceMapAssertion("Source#Simple1#main#([Ljava/lang/String;)V", "i", 28), - new SourceMapAssertion("Source#Simple1#main#([Ljava/lang/String;)V", "sum", 29), - EdgeAssertions.make("Source#Simple1#main#([Ljava/lang/String;)V", "Source#Simple1#doStuff#(I)V"), - EdgeAssertions.make("Source#Simple1#instanceMethod1#()V", "Source#Simple1#instanceMethod2#()V")); - - // this needs soure positions to work too - runTest(singleTestSrc(), rtJar, simpleTestEntryPoint(), assertions, true); - } - - @Test public void testTwoClasses() { - runTest(singleTestSrc(), rtJar, simpleTestEntryPoint(), Arrays.asList( - - new IRAssertion() { - - public void check(CallGraph cg) { - final String typeStr = singleInputForTest(); - - final TypeReference type = findOrCreateTypeReference("Source", typeStr, cg.getClassHierarchy()); - - final IClass iClass = cg.getClassHierarchy().lookupClass(type); - Assert.assertNotNull("Could not find class " + typeStr, iClass); - - /* - Assert.assertEquals("Expected two classes.", iClass.getClassLoader().getNumberOfClasses(), 2); - - for (Iterator it = iClass.getClassLoader().iterateAllClasses(); it.hasNext();) { - IClass cls = it.next(); - - Assert.assertTrue("Expected class to be either " + typeStr + " or " + "Bar", cls.getName().getClassName().toString() - .equals(typeStr) - || cls.getName().getClassName().toString().equals("Bar")); - } - */ - } - }), true); - } - - @Test public void testInterfaceTest1() { - runTest(singleTestSrc(), rtJar, simpleTestEntryPoint(), Arrays.asList( - - /** - * IFoo is an interface - */ - new IRAssertion() { - - public void check(CallGraph cg) { - final String typeStr = "IFoo"; - - final TypeReference type = findOrCreateTypeReference("Source", typeStr, cg.getClassHierarchy()); - - final IClass iClass = cg.getClassHierarchy().lookupClass(type); - Assert.assertNotNull("Could not find class " + typeStr, iClass); - - Assert.assertTrue("Expected IFoo to be an interface.", iClass.isInterface()); - } - }, - - /** - * Foo implements IFoo - */ - new IRAssertion() { - - public void check(CallGraph cg) { - final String typeStr = "FooIT1"; - - final TypeReference type = findOrCreateTypeReference("Source", typeStr, cg.getClassHierarchy()); - - final IClass iClass = cg.getClassHierarchy().lookupClass(type); - Assert.assertNotNull("Could not find class " + typeStr, iClass); - - final Collection interfaces = iClass.getDirectInterfaces(); - - Assert.assertEquals("Expected one single interface.", interfaces.size(), 1); - - Assert.assertTrue("Expected Foo to implement IFoo", interfaces.contains(cg.getClassHierarchy().lookupClass( - findOrCreateTypeReference("Source", "IFoo", cg.getClassHierarchy())))); - } - }), true); - } - - @Test public void testInheritance1() { - runTest(singleTestSrc(), rtJar, simpleTestEntryPoint(), Arrays.asList( - /** - * 'Derived' extends 'Base' - */ - new IRAssertion() { - - public void check(CallGraph cg) { - final String typeStr = "Derived"; - - final TypeReference type = findOrCreateTypeReference("Source", typeStr, cg.getClassHierarchy()); - - final IClass derivedClass = cg.getClassHierarchy().lookupClass(type); - Assert.assertNotNull("Could not find class " + typeStr, derivedClass); - - final TypeReference baseType = findOrCreateTypeReference("Source", "Base", cg.getClassHierarchy()); - final IClass baseClass = cg.getClassHierarchy().lookupClass(baseType); - - Assert.assertTrue("Expected 'Base' to be the superclass of 'Derived'", derivedClass.getSuperclass().equals(baseClass)); - - Collection subclasses = cg.getClassHierarchy().computeSubClasses(baseType); - - Assert.assertTrue("Expected subclasses of 'Base' to be 'Base' and 'Derived'.", subclasses.contains(derivedClass) - && subclasses.contains(baseClass)); - } - }), true); - } - - @Test public void testArray1() { - runTest(singleTestSrc(), rtJar, simpleTestEntryPoint(), Arrays.asList( - /** - * 'foo' has four array instructions: - 2 SSAArrayLengthInstruction - 1 - * SSAArrayLoadInstruction - 1 SSAArrayStoreInstruction - */ - new IRAssertion() { - - public void check(CallGraph cg) { - - MethodReference mref = descriptorToMethodRef("Source#Array1#foo#()V", cg.getClassHierarchy()); - - int count = 0; - CGNode node = cg.getNodes(mref).iterator().next(); - for (SSAInstruction s : node.getIR().getInstructions()) { - if (isArrayInstruction(s)) { - count++; - } - } - - Assert.assertEquals("Unexpected number of array instructions in 'foo'.", count, 4); - } - - private boolean isArrayInstruction(SSAInstruction s) { - return s instanceof SSAArrayReferenceInstruction || s instanceof SSAArrayLengthInstruction; - } - }), true); - } - - @Test public void testArrayLiteral1() { - runTest(singleTestSrc(), rtJar, simpleTestEntryPoint(), Arrays.asList( - /** - * 'foo' has four array instructions: - 2 SSAArrayLengthInstruction - 1 - * SSAArrayLoadInstruction - 1 SSAArrayStoreInstruction - */ - new IRAssertion() { - - public void check(CallGraph cg) { - - MethodReference mref = descriptorToMethodRef("Source#ArrayLiteral1#main#([Ljava/lang/String;)V", cg.getClassHierarchy()); - - CGNode node = cg.getNodes(mref).iterator().next(); - SSAInstruction s = node.getIR().getInstructions()[3]; - Assert.assertTrue("Did not find new array instruction.", s instanceof SSANewInstruction); - Assert.assertTrue("", ((SSANewInstruction) s).getNewSite().getDeclaredType().isArrayType()); - } - - }), true); - } - - @Test public void testArrayLiteral2() { - runTest(singleTestSrc(), rtJar, simpleTestEntryPoint(), Arrays.asList( - /** - * int[] y= { 1, 2, 3, 4 } is represented in the IR as four array store - * instructions - */ - new IRAssertion() { - - public void check(CallGraph cg) { - - MethodReference mref = descriptorToMethodRef("Source#ArrayLiteral2#main#([Ljava/lang/String;)V", cg.getClassHierarchy()); - - CGNode node = cg.getNodes(mref).iterator().next(); - - final SSAInstruction[] instructions = node.getIR().getInstructions(); - // test 1 - { - SSAInstruction s1 = instructions[3]; - if (s1 instanceof SSANewInstruction) { - Assert.assertTrue("", ((SSANewInstruction) s1).getNewSite().getDeclaredType().isArrayType()); - } else { - Assert.assertTrue("Expected 3rd to be a new array instruction.", false); - } - } - // test 2 - { - SSAInstruction s2 = instructions[4]; - if (s2 instanceof SSANewInstruction) { - Assert.assertTrue("", ((SSANewInstruction) s2).getNewSite().getDeclaredType().isArrayType()); - } else { - Assert.assertTrue("Expected 4th to be a new array instruction.", false); - } - } - // test 3: the last 4 instructions are of the form y[i] = i+1; - { - final SymbolTable symbolTable = node.getIR().getSymbolTable(); - for (int i = 5; i <= 8; i++) { - Assert.assertTrue("Expected only array stores.", instructions[i] instanceof SSAArrayStoreInstruction); - - SSAArrayStoreInstruction as = (SSAArrayStoreInstruction) instructions[i]; - - Assert.assertEquals("Expected an array store to 'y'.", node.getIR().getLocalNames(i, as.getArrayRef())[0], "y"); - - final Integer valueOfArrayIndex = ((Integer) symbolTable.getConstantValue(as.getIndex())); - final Integer valueAssigned = (Integer) symbolTable.getConstantValue(as.getValue()); - - Assert.assertEquals("Expected an array store to 'y' with value " + (valueOfArrayIndex + 1), valueAssigned.intValue(), - valueOfArrayIndex + 1); - - } - } - } - - }), true); - } - - @Test public void testInheritedField() { - List edgeAssertionses = Arrays.asList(EdgeAssertions.make("Source#InheritedField#main#([Ljava/lang/String;)V", - "Source#B#foo#()V"), EdgeAssertions.make("Source#InheritedField#main#([Ljava/lang/String;)V", "Source#B#bar#()V")); - runTest(singleTestSrc(), rtJar, simpleTestEntryPoint(), edgeAssertionses, true); - } - - @Test public void testQualifiedStatic() { - runTest(singleTestSrc(), rtJar, simpleTestEntryPoint(), Arrays.asList( - /** - * - */ - new IRAssertion() { - - public void check(CallGraph cg) { - - MethodReference mref = descriptorToMethodRef("Source#QualifiedStatic#main#([Ljava/lang/String;)V", cg.getClassHierarchy()); - - CGNode node = cg.getNodes(mref).iterator().next(); - SSAInstruction s = node.getIR().getInstructions()[5]; - - Assert.assertTrue("Did not find a getstatic instruction.", s instanceof SSAGetInstruction - && ((SSAGetInstruction) s).isStatic()); - final FieldReference field = ((SSAGetInstruction) s).getDeclaredField(); - Assert.assertEquals("Expected a getstatic for 'value'.", field.getName().toString(), "value"); - Assert.assertEquals("Expected a getstatic for 'value'.", field.getDeclaringClass().getName().toString(), "LFooQ"); - } - - }), true); - } - - @Test public void testStaticNesting() { - runTest(singleTestSrc(), rtJar, simpleTestEntryPoint(), Arrays.asList( - - new IRAssertion() { - - public void check(CallGraph cg) { - final String typeStr = singleInputForTest() + "$WhatsIt"; - - final TypeReference type = findOrCreateTypeReference("Source", typeStr, cg.getClassHierarchy()); - - final IClass iClass = cg.getClassHierarchy().lookupClass(type); - Assert.assertNotNull("Could not find class " + typeStr, iClass); - - // todo: this fails: Assert.assertNotNull("Expected to be enclosed in - // 'StaticNesting'.", - // ((JavaSourceLoaderImpl.JavaClass)iClass).getEnclosingClass()); - // todo: is there the concept of CompilationUnit? - - /** - * {@link JavaCAst2IRTranslator#getEnclosingType} return null for static - * inner classes..? - */ - } - }), true); - } - - @Test public void testCastFromNull() { - runTest(singleTestSrc(), rtJar, simpleTestEntryPoint(), new ArrayList(), true); - } - - @Test public void testInnerClass() { - runTest(singleTestSrc(), rtJar, simpleTestEntryPoint(), Arrays.asList( - - new IRAssertion() { - - public void check(CallGraph cg) { - final String typeStr = singleInputForTest(); - - final TypeReference type = findOrCreateTypeReference("Source", typeStr + "$WhatsIt", cg.getClassHierarchy()); - - final IClass iClass = cg.getClassHierarchy().lookupClass(type); - Assert.assertNotNull("Could not find class " + typeStr, iClass); - - Assert.assertEquals("Expected to be enclosed in 'InnerClass'.", ((JavaSourceLoaderImpl.JavaClass) iClass) - .getEnclosingClass(), // todo is there another way? - cg.getClassHierarchy().lookupClass(findOrCreateTypeReference("Source", typeStr, cg.getClassHierarchy()))); - } - }), true); - } - - @Test public void testNullArrayInit() { - runTest(singleTestSrc(), rtJar, simpleTestEntryPoint(), new ArrayList(), true); - } - - @Test public void testInnerClassA() { - Pair x = runTest(singleTestSrc(), rtJar, simpleTestEntryPoint(), new ArrayList(), true); - - // can't do an IRAssertion() -- we need the pointer analysis - - CallGraph cg = (CallGraph) x.fst; - PointerAnalysis pa = (PointerAnalysis) x.snd; - - Iterator iter = cg.iterator(); - while ( iter.hasNext() ) { - CGNode n = iter.next(); - - // assume in the test we have one enclosing instruction for each of the methods here. - String methodSigs[] = { "InnerClassA$AB.getA_X_from_AB()I", - "InnerClassA$AB.getA_X_thru_AB()I", - "InnerClassA$AB$ABSubA.getA_X()I", - "InnerClassA$AB$ABA$ABAA.getABA_X()I", - "InnerClassA$AB$ABA$ABAA.getA_X()I", - "InnerClassA$AB$ABA$ABAB.getABA_X()I", - "InnerClassA$AB$ABSubA$ABSubAA.getABA_X()I", - "InnerClassA$AB$ABSubA$ABSubAA.getA_X()I", }; - - // each type suffixed by "," - String ikConcreteTypeStrings[ ]= { - "LInnerClassA,", - "LInnerClassA,", - "LInnerClassA,", - "LInnerClassA$AB$ABSubA,LInnerClassA$AB$ABA,", - "LInnerClassA,", - "LInnerClassA$AB$ABA,", - "LInnerClassA$AB$ABSubA,", - "LInnerClassA,", - }; - - Assert.assertTrue ( "Buggy test", methodSigs.length == ikConcreteTypeStrings.length ); - for ( int i = 0; i < methodSigs.length; i++ ) { - if ( n.getMethod().getSignature().equals(methodSigs[i]) ) { - // find enclosing instruction - for ( SSAInstruction instr: n.getIR().getInstructions() ) { - if ( instr instanceof EnclosingObjectReference ) { - String allIks = ""; - for (InstanceKey ik: pa.getPointsToSet(new LocalPointerKey(n,instr.getDef()))) - allIks += ik.getConcreteType().getName() +","; - // System.out.printf("in method %s, got ik %s\n", methodSigs[i], allIks); - - Assert.assertTrue("assertion failed: expecting ik " + ikConcreteTypeStrings[i] + " in method " + methodSigs[i] + ", got " + allIks + "\n", - allIks.equals(ikConcreteTypeStrings[i])); - - break; - } - } - } - } - } - - - } - - @Test public void testInnerClassSuper() { - Pair x = runTest(singleTestSrc(), rtJar, simpleTestEntryPoint(), new ArrayList(), true); - - // can't do an IRAssertion() -- we need the pointer analysis - - CallGraph cg = (CallGraph) x.fst; - PointerAnalysis pa = (PointerAnalysis) x.snd; - - Iterator iter = cg.iterator(); - while ( iter.hasNext() ) { - CGNode n = iter.next(); - if ( n.getMethod().getSignature().equals("LInnerClassSuper$SuperOuter.test()V") ) { - // find enclosing instruction - for ( SSAInstruction instr: n.getIR().getInstructions() ) { - if ( instr instanceof EnclosingObjectReference ) { - String allIks = ""; - for (InstanceKey ik: pa.getPointsToSet(new LocalPointerKey(n,instr.getDef()))) - allIks += ik.getConcreteType().getName() +","; - Assert.assertTrue("assertion failed: expecting ik \"LSub,\" in method, got \"" + allIks + "\"\n", - allIks.equals("LSub,")); - - break; - } - } - } - } - - - } - - @Test public void testLocalClass() { - runTest(singleTestSrc(), rtJar, simpleTestEntryPoint(), Arrays.asList( - - new IRAssertion() { - - /** - * Classes local to method are enclosed in the class the methods belong - * to. - */ - public void check(CallGraph cg) { - final String typeStr = singleInputForTest(); - final String localClassStr = "Foo"; - - // Observe the descriptor for a class local to a method. - final TypeReference mainFooType = findOrCreateTypeReference("Source", typeStr + "/main([Ljava/lang/String;)V/" - + localClassStr, cg.getClassHierarchy()); - - // Observe the descriptor for a class local to a method. - final IClass mainFooClass = cg.getClassHierarchy().lookupClass(mainFooType); - Assert.assertNotNull("Could not find class " + mainFooType, mainFooClass); - - final TypeReference methodFooType = findOrCreateTypeReference("Source", typeStr + "/method()V/" + localClassStr, cg - .getClassHierarchy()); - - final IClass methodFooClass = cg.getClassHierarchy().lookupClass(methodFooType); - Assert.assertNotNull("Could not find class " + methodFooType, methodFooClass); - - final IClass localClass = cg.getClassHierarchy().lookupClass( - findOrCreateTypeReference("Source", typeStr, cg.getClassHierarchy())); - - Assert.assertSame("'Foo' is enclosed in 'Local'", ((JavaSourceLoaderImpl.JavaClass) methodFooClass).getEnclosingClass(), - localClass); - // todo: is this failing because 'main' is static? - // Assert.assertSame("'Foo' is enclosed in 'Local'", - // ((JavaSourceLoaderImpl.JavaClass)mainFooClass).getEnclosingClass(), - // localClass); - } - }), true); - } - - @Test public void testAnonymousClass() { - runTest(singleTestSrc(), rtJar, simpleTestEntryPoint(), Arrays.asList( - - new IRAssertion() { - - public void check(CallGraph cg) { - final String typeStr = singleInputForTest(); - - final TypeReference type = findOrCreateTypeReference("Source", typeStr, cg.getClassHierarchy()); - - final IClass iClass = cg.getClassHierarchy().lookupClass(type); - Assert.assertNotNull("Could not find class " + typeStr, iClass); - - // todo what to check?? could not find anything in the APIs for - // anonymous - } - }), true); - } - - @Test public void testWhileTest1() { - runTest(singleTestSrc(), rtJar, simpleTestEntryPoint(), emptyList, true); - } - - @Test public void testSwitch1() { - runTest(singleTestSrc(), rtJar, simpleTestEntryPoint(), emptyList, true); - } - - @Test public void testException1() { - runTest(singleTestSrc(), rtJar, simpleTestEntryPoint(), emptyList, true); - } - - @Test public void testException2() { - runTest(singleTestSrc(), rtJar, simpleTestEntryPoint(), emptyList, true); - } - - @Test public void testFinally1() { - runTest(singleTestSrc(), rtJar, simpleTestEntryPoint(), emptyList, true); - } - - @Test public void testScoping1() { - runTest(singleTestSrc(), rtJar, simpleTestEntryPoint(), emptyList, true); - } - - @Test public void testScoping2() { - runTest(singleTestSrc(), rtJar, simpleTestEntryPoint(), emptyList, true); - } - - @Test public void testNonPrimaryTopLevel() { - runTest(singlePkgTestSrc("p"), rtJar, simplePkgTestEntryPoint("p"), emptyList, true); - } - - @Test public void testMiniaturList() { - runTest(singleTestSrc(), rtJar, simpleTestEntryPoint(), emptyList, true); - } - - @Test public void testMonitor() { - runTest(singleTestSrc(), rtJar, simpleTestEntryPoint(), emptyList, true); - } - - @Test public void testStaticInitializers() { - runTest(singleTestSrc(), rtJar, simpleTestEntryPoint(), emptyList, true); - } - - @Test public void testThread1() { - runTest(singleTestSrc(), rtJar, simpleTestEntryPoint(), emptyList, true); - } - - @Test public void testCasts() { - runTest(singleTestSrc(), rtJar, simpleTestEntryPoint(), emptyList, true); - } - - @Test public void testBreaks() { - runTest(singleTestSrc(), rtJar, simpleTestEntryPoint(), emptyList, true); - } - - private MethodReference getSliceRootReference(String className, String methodName, String methodDescriptor) { - TypeName clsName = TypeName.string2TypeName("L" + className.replace('.', '/')); - TypeReference clsRef = TypeReference.findOrCreate(JavaSourceAnalysisScope.SOURCE, clsName); - - Atom nameAtom = Atom.findOrCreateUnicodeAtom(methodName); - Descriptor descr = Descriptor.findOrCreateUTF8(Language.JAVA, methodDescriptor); - - return MethodReference.findOrCreate(clsRef, nameAtom, descr); - } - - @Test public void testMiniaturSliceBug() throws IllegalArgumentException, CancelException { - Pair x = runTest(singleTestSrc(), rtJar, simpleTestEntryPoint(), emptyList, true); - - PointerAnalysis pa = (PointerAnalysis) x.snd; - CallGraph cg = (CallGraph) x.fst; - - // test partial slice - MethodReference sliceRootRef = getSliceRootReference("MiniaturSliceBug", "validNonDispatchedCall", "(LIntWrapper;)V"); - Set roots = cg.getNodes(sliceRootRef); - Pair, SDG> y = AstJavaSlicer.computeAssertionSlice(cg, pa, roots, false); - Collection slice = y.fst; - SlicerTest.dumpSlice(slice); - Assert.assertEquals(0, SlicerTest.countAllocations(slice)); - Assert.assertEquals(1, SlicerTest.countPutfields(slice)); - - // test slice from main - sliceRootRef = getSliceRootReference("MiniaturSliceBug", "main", "([Ljava/lang/String;)V"); - roots = cg.getNodes(sliceRootRef); - y = AstJavaSlicer.computeAssertionSlice(cg, pa, roots, false); - slice = y.fst; - SlicerTest.dumpSlice(slice); - Assert.assertEquals(2, SlicerTest.countAllocations(slice)); - Assert.assertEquals(2, SlicerTest.countPutfields(slice)); - } - -} +/****************************************************************************** + * Copyright (c) 2002 - 2006 IBM Corporation. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *****************************************************************************/ +/* + * Created on Oct 21, 2005 + */ +package com.ibm.wala.cast.java.test; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Iterator; +import java.util.List; +import java.util.Set; + +import junit.framework.Assert; + +import org.junit.Test; + +import com.ibm.wala.cast.java.ipa.callgraph.JavaSourceAnalysisScope; +import com.ibm.wala.cast.java.ipa.slicer.AstJavaSlicer; +import com.ibm.wala.cast.java.loader.JavaSourceLoaderImpl; +import com.ibm.wala.cast.java.ssa.EnclosingObjectReference; +import com.ibm.wala.classLoader.IClass; +import com.ibm.wala.classLoader.Language; +import com.ibm.wala.core.tests.slicer.SlicerTest; +import com.ibm.wala.ipa.callgraph.CGNode; +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.slicer.SDG; +import com.ibm.wala.ipa.slicer.Statement; +import com.ibm.wala.ssa.SSAArrayLengthInstruction; +import com.ibm.wala.ssa.SSAArrayReferenceInstruction; +import com.ibm.wala.ssa.SSAArrayStoreInstruction; +import com.ibm.wala.ssa.SSAGetInstruction; +import com.ibm.wala.ssa.SSAInstruction; +import com.ibm.wala.ssa.SSANewInstruction; +import com.ibm.wala.ssa.SymbolTable; +import com.ibm.wala.types.Descriptor; +import com.ibm.wala.types.FieldReference; +import com.ibm.wala.types.MethodReference; +import com.ibm.wala.types.TypeName; +import com.ibm.wala.types.TypeReference; +import com.ibm.wala.util.CancelException; +import com.ibm.wala.util.collections.Pair; +import com.ibm.wala.util.strings.Atom; + +public abstract class JavaIRTests extends IRTests { + + public JavaIRTests(String projectName) { + super(projectName); + } + + public JavaIRTests() { + this(null); + } + + @Test public void testSimple1() { + + List assertions = Arrays.asList( + new SourceMapAssertion("Source#Simple1#doStuff#(I)V", "prod", 24), + new SourceMapAssertion("Source#Simple1#doStuff#(I)V", "j", 23), + new SourceMapAssertion("Source#Simple1#main#([Ljava/lang/String;)V", "s", 32), + new SourceMapAssertion("Source#Simple1#main#([Ljava/lang/String;)V", "i", 28), + new SourceMapAssertion("Source#Simple1#main#([Ljava/lang/String;)V", "sum", 29), + EdgeAssertions.make("Source#Simple1#main#([Ljava/lang/String;)V", "Source#Simple1#doStuff#(I)V"), + EdgeAssertions.make("Source#Simple1#instanceMethod1#()V", "Source#Simple1#instanceMethod2#()V")); + + // this needs soure positions to work too + runTest(singleTestSrc(), rtJar, simpleTestEntryPoint(), assertions, true); + } + + @Test public void testTwoClasses() { + runTest(singleTestSrc(), rtJar, simpleTestEntryPoint(), Arrays.asList( + + new IRAssertion() { + + public void check(CallGraph cg) { + final String typeStr = singleInputForTest(); + + final TypeReference type = findOrCreateTypeReference("Source", typeStr, cg.getClassHierarchy()); + + final IClass iClass = cg.getClassHierarchy().lookupClass(type); + Assert.assertNotNull("Could not find class " + typeStr, iClass); + + /* + Assert.assertEquals("Expected two classes.", iClass.getClassLoader().getNumberOfClasses(), 2); + + for (Iterator it = iClass.getClassLoader().iterateAllClasses(); it.hasNext();) { + IClass cls = it.next(); + + Assert.assertTrue("Expected class to be either " + typeStr + " or " + "Bar", cls.getName().getClassName().toString() + .equals(typeStr) + || cls.getName().getClassName().toString().equals("Bar")); + } + */ + } + }), true); + } + + @Test public void testInterfaceTest1() { + runTest(singleTestSrc(), rtJar, simpleTestEntryPoint(), Arrays.asList( + + /** + * IFoo is an interface + */ + new IRAssertion() { + + public void check(CallGraph cg) { + final String typeStr = "IFoo"; + + final TypeReference type = findOrCreateTypeReference("Source", typeStr, cg.getClassHierarchy()); + + final IClass iClass = cg.getClassHierarchy().lookupClass(type); + Assert.assertNotNull("Could not find class " + typeStr, iClass); + + Assert.assertTrue("Expected IFoo to be an interface.", iClass.isInterface()); + } + }, + + /** + * Foo implements IFoo + */ + new IRAssertion() { + + public void check(CallGraph cg) { + final String typeStr = "FooIT1"; + + final TypeReference type = findOrCreateTypeReference("Source", typeStr, cg.getClassHierarchy()); + + final IClass iClass = cg.getClassHierarchy().lookupClass(type); + Assert.assertNotNull("Could not find class " + typeStr, iClass); + + final Collection interfaces = iClass.getDirectInterfaces(); + + Assert.assertEquals("Expected one single interface.", interfaces.size(), 1); + + Assert.assertTrue("Expected Foo to implement IFoo", interfaces.contains(cg.getClassHierarchy().lookupClass( + findOrCreateTypeReference("Source", "IFoo", cg.getClassHierarchy())))); + } + }), true); + } + + @Test public void testInheritance1() { + runTest(singleTestSrc(), rtJar, simpleTestEntryPoint(), Arrays.asList( + /** + * 'Derived' extends 'Base' + */ + new IRAssertion() { + + public void check(CallGraph cg) { + final String typeStr = "Derived"; + + final TypeReference type = findOrCreateTypeReference("Source", typeStr, cg.getClassHierarchy()); + + final IClass derivedClass = cg.getClassHierarchy().lookupClass(type); + Assert.assertNotNull("Could not find class " + typeStr, derivedClass); + + final TypeReference baseType = findOrCreateTypeReference("Source", "Base", cg.getClassHierarchy()); + final IClass baseClass = cg.getClassHierarchy().lookupClass(baseType); + + Assert.assertTrue("Expected 'Base' to be the superclass of 'Derived'", derivedClass.getSuperclass().equals(baseClass)); + + Collection subclasses = cg.getClassHierarchy().computeSubClasses(baseType); + + Assert.assertTrue("Expected subclasses of 'Base' to be 'Base' and 'Derived'.", subclasses.contains(derivedClass) + && subclasses.contains(baseClass)); + } + }), true); + } + + @Test public void testArray1() { + runTest(singleTestSrc(), rtJar, simpleTestEntryPoint(), Arrays.asList( + /** + * 'foo' has four array instructions: - 2 SSAArrayLengthInstruction - 1 + * SSAArrayLoadInstruction - 1 SSAArrayStoreInstruction + */ + new IRAssertion() { + + public void check(CallGraph cg) { + + MethodReference mref = descriptorToMethodRef("Source#Array1#foo#()V", cg.getClassHierarchy()); + + int count = 0; + CGNode node = cg.getNodes(mref).iterator().next(); + for (SSAInstruction s : node.getIR().getInstructions()) { + if (isArrayInstruction(s)) { + count++; + } + } + + Assert.assertEquals("Unexpected number of array instructions in 'foo'.", count, 4); + } + + private boolean isArrayInstruction(SSAInstruction s) { + return s instanceof SSAArrayReferenceInstruction || s instanceof SSAArrayLengthInstruction; + } + }), true); + } + + @Test public void testArrayLiteral1() { + runTest(singleTestSrc(), rtJar, simpleTestEntryPoint(), Arrays.asList( + /** + * 'foo' has four array instructions: - 2 SSAArrayLengthInstruction - 1 + * SSAArrayLoadInstruction - 1 SSAArrayStoreInstruction + */ + new IRAssertion() { + + public void check(CallGraph cg) { + + MethodReference mref = descriptorToMethodRef("Source#ArrayLiteral1#main#([Ljava/lang/String;)V", cg.getClassHierarchy()); + + CGNode node = cg.getNodes(mref).iterator().next(); + SSAInstruction s = node.getIR().getInstructions()[3]; + Assert.assertTrue("Did not find new array instruction.", s instanceof SSANewInstruction); + Assert.assertTrue("", ((SSANewInstruction) s).getNewSite().getDeclaredType().isArrayType()); + } + + }), true); + } + + @Test public void testArrayLiteral2() { + runTest(singleTestSrc(), rtJar, simpleTestEntryPoint(), Arrays.asList( + /** + * int[] y= { 1, 2, 3, 4 } is represented in the IR as four array store + * instructions + */ + new IRAssertion() { + + public void check(CallGraph cg) { + + MethodReference mref = descriptorToMethodRef("Source#ArrayLiteral2#main#([Ljava/lang/String;)V", cg.getClassHierarchy()); + + CGNode node = cg.getNodes(mref).iterator().next(); + + final SSAInstruction[] instructions = node.getIR().getInstructions(); + // test 1 + { + SSAInstruction s1 = instructions[3]; + if (s1 instanceof SSANewInstruction) { + Assert.assertTrue("", ((SSANewInstruction) s1).getNewSite().getDeclaredType().isArrayType()); + } else { + Assert.assertTrue("Expected 3rd to be a new array instruction.", false); + } + } + // test 2 + { + SSAInstruction s2 = instructions[4]; + if (s2 instanceof SSANewInstruction) { + Assert.assertTrue("", ((SSANewInstruction) s2).getNewSite().getDeclaredType().isArrayType()); + } else { + Assert.assertTrue("Expected 4th to be a new array instruction.", false); + } + } + // test 3: the last 4 instructions are of the form y[i] = i+1; + { + final SymbolTable symbolTable = node.getIR().getSymbolTable(); + for (int i = 5; i <= 8; i++) { + Assert.assertTrue("Expected only array stores.", instructions[i] instanceof SSAArrayStoreInstruction); + + SSAArrayStoreInstruction as = (SSAArrayStoreInstruction) instructions[i]; + + Assert.assertEquals("Expected an array store to 'y'.", node.getIR().getLocalNames(i, as.getArrayRef())[0], "y"); + + final Integer valueOfArrayIndex = ((Integer) symbolTable.getConstantValue(as.getIndex())); + final Integer valueAssigned = (Integer) symbolTable.getConstantValue(as.getValue()); + + Assert.assertEquals("Expected an array store to 'y' with value " + (valueOfArrayIndex + 1), valueAssigned.intValue(), + valueOfArrayIndex + 1); + + } + } + } + + }), true); + } + + @Test public void testInheritedField() { + List edgeAssertionses = Arrays.asList(EdgeAssertions.make("Source#InheritedField#main#([Ljava/lang/String;)V", + "Source#B#foo#()V"), EdgeAssertions.make("Source#InheritedField#main#([Ljava/lang/String;)V", "Source#B#bar#()V")); + runTest(singleTestSrc(), rtJar, simpleTestEntryPoint(), edgeAssertionses, true); + } + + @Test public void testQualifiedStatic() { + runTest(singleTestSrc(), rtJar, simpleTestEntryPoint(), Arrays.asList( + /** + * + */ + new IRAssertion() { + + public void check(CallGraph cg) { + + MethodReference mref = descriptorToMethodRef("Source#QualifiedStatic#main#([Ljava/lang/String;)V", cg.getClassHierarchy()); + + CGNode node = cg.getNodes(mref).iterator().next(); + SSAInstruction s = node.getIR().getInstructions()[5]; + + Assert.assertTrue("Did not find a getstatic instruction.", s instanceof SSAGetInstruction + && ((SSAGetInstruction) s).isStatic()); + final FieldReference field = ((SSAGetInstruction) s).getDeclaredField(); + Assert.assertEquals("Expected a getstatic for 'value'.", field.getName().toString(), "value"); + Assert.assertEquals("Expected a getstatic for 'value'.", field.getDeclaringClass().getName().toString(), "LFooQ"); + } + + }), true); + } + + @Test public void testStaticNesting() { + runTest(singleTestSrc(), rtJar, simpleTestEntryPoint(), Arrays.asList( + + new IRAssertion() { + + public void check(CallGraph cg) { + final String typeStr = singleInputForTest() + "$WhatsIt"; + + final TypeReference type = findOrCreateTypeReference("Source", typeStr, cg.getClassHierarchy()); + + final IClass iClass = cg.getClassHierarchy().lookupClass(type); + Assert.assertNotNull("Could not find class " + typeStr, iClass); + + // todo: this fails: Assert.assertNotNull("Expected to be enclosed in + // 'StaticNesting'.", + // ((JavaSourceLoaderImpl.JavaClass)iClass).getEnclosingClass()); + // todo: is there the concept of CompilationUnit? + + /** + * {@link JavaCAst2IRTranslator#getEnclosingType} return null for static + * inner classes..? + */ + } + }), true); + } + + @Test public void testCastFromNull() { + runTest(singleTestSrc(), rtJar, simpleTestEntryPoint(), new ArrayList(), true); + } + + @Test public void testInnerClass() { + runTest(singleTestSrc(), rtJar, simpleTestEntryPoint(), Arrays.asList( + + new IRAssertion() { + + public void check(CallGraph cg) { + final String typeStr = singleInputForTest(); + + final TypeReference type = findOrCreateTypeReference("Source", typeStr + "$WhatsIt", cg.getClassHierarchy()); + + final IClass iClass = cg.getClassHierarchy().lookupClass(type); + Assert.assertNotNull("Could not find class " + typeStr, iClass); + + Assert.assertEquals("Expected to be enclosed in 'InnerClass'.", ((JavaSourceLoaderImpl.JavaClass) iClass) + .getEnclosingClass(), // todo is there another way? + cg.getClassHierarchy().lookupClass(findOrCreateTypeReference("Source", typeStr, cg.getClassHierarchy()))); + } + }), true); + } + + @Test public void testNullArrayInit() { + runTest(singleTestSrc(), rtJar, simpleTestEntryPoint(), new ArrayList(), true); + } + + @Test public void testInnerClassA() { + Pair x = runTest(singleTestSrc(), rtJar, simpleTestEntryPoint(), new ArrayList(), true); + + // can't do an IRAssertion() -- we need the pointer analysis + + CallGraph cg = (CallGraph) x.fst; + PointerAnalysis pa = (PointerAnalysis) x.snd; + + Iterator iter = cg.iterator(); + while ( iter.hasNext() ) { + CGNode n = iter.next(); + + // assume in the test we have one enclosing instruction for each of the methods here. + String methodSigs[] = { "InnerClassA$AB.getA_X_from_AB()I", + "InnerClassA$AB.getA_X_thru_AB()I", + "InnerClassA$AB$ABSubA.getA_X()I", + "InnerClassA$AB$ABA$ABAA.getABA_X()I", + "InnerClassA$AB$ABA$ABAA.getA_X()I", + "InnerClassA$AB$ABA$ABAB.getABA_X()I", + "InnerClassA$AB$ABSubA$ABSubAA.getABA_X()I", + "InnerClassA$AB$ABSubA$ABSubAA.getA_X()I", }; + + // each type suffixed by "," + String ikConcreteTypeStrings[ ]= { + "LInnerClassA,", + "LInnerClassA,", + "LInnerClassA,", + "LInnerClassA$AB$ABSubA,LInnerClassA$AB$ABA,", + "LInnerClassA,", + "LInnerClassA$AB$ABA,", + "LInnerClassA$AB$ABSubA,", + "LInnerClassA,", + }; + + Assert.assertTrue ( "Buggy test", methodSigs.length == ikConcreteTypeStrings.length ); + for ( int i = 0; i < methodSigs.length; i++ ) { + if ( n.getMethod().getSignature().equals(methodSigs[i]) ) { + // find enclosing instruction + for ( SSAInstruction instr: n.getIR().getInstructions() ) { + if ( instr instanceof EnclosingObjectReference ) { + String allIks = ""; + for (InstanceKey ik: pa.getPointsToSet(new LocalPointerKey(n,instr.getDef()))) + allIks += ik.getConcreteType().getName() +","; + // System.out.printf("in method %s, got ik %s\n", methodSigs[i], allIks); + + Assert.assertTrue("assertion failed: expecting ik " + ikConcreteTypeStrings[i] + " in method " + methodSigs[i] + ", got " + allIks + "\n", + allIks.equals(ikConcreteTypeStrings[i])); + + break; + } + } + } + } + } + + + } + + @Test public void testInnerClassSuper() { + Pair x = runTest(singleTestSrc(), rtJar, simpleTestEntryPoint(), new ArrayList(), true); + + // can't do an IRAssertion() -- we need the pointer analysis + + CallGraph cg = (CallGraph) x.fst; + PointerAnalysis pa = (PointerAnalysis) x.snd; + + Iterator iter = cg.iterator(); + while ( iter.hasNext() ) { + CGNode n = iter.next(); + if ( n.getMethod().getSignature().equals("LInnerClassSuper$SuperOuter.test()V") ) { + // find enclosing instruction + for ( SSAInstruction instr: n.getIR().getInstructions() ) { + if ( instr instanceof EnclosingObjectReference ) { + String allIks = ""; + for (InstanceKey ik: pa.getPointsToSet(new LocalPointerKey(n,instr.getDef()))) + allIks += ik.getConcreteType().getName() +","; + Assert.assertTrue("assertion failed: expecting ik \"LSub,\" in method, got \"" + allIks + "\"\n", + allIks.equals("LSub,")); + + break; + } + } + } + } + + + } + + @Test public void testLocalClass() { + runTest(singleTestSrc(), rtJar, simpleTestEntryPoint(), Arrays.asList( + + new IRAssertion() { + + /** + * Classes local to method are enclosed in the class the methods belong + * to. + */ + public void check(CallGraph cg) { + final String typeStr = singleInputForTest(); + final String localClassStr = "Foo"; + + // Observe the descriptor for a class local to a method. + final TypeReference mainFooType = findOrCreateTypeReference("Source", typeStr + "/main([Ljava/lang/String;)V/" + + localClassStr, cg.getClassHierarchy()); + + // Observe the descriptor for a class local to a method. + final IClass mainFooClass = cg.getClassHierarchy().lookupClass(mainFooType); + Assert.assertNotNull("Could not find class " + mainFooType, mainFooClass); + + final TypeReference methodFooType = findOrCreateTypeReference("Source", typeStr + "/method()V/" + localClassStr, cg + .getClassHierarchy()); + + final IClass methodFooClass = cg.getClassHierarchy().lookupClass(methodFooType); + Assert.assertNotNull("Could not find class " + methodFooType, methodFooClass); + + final IClass localClass = cg.getClassHierarchy().lookupClass( + findOrCreateTypeReference("Source", typeStr, cg.getClassHierarchy())); + + Assert.assertSame("'Foo' is enclosed in 'Local'", ((JavaSourceLoaderImpl.JavaClass) methodFooClass).getEnclosingClass(), + localClass); + // todo: is this failing because 'main' is static? + // Assert.assertSame("'Foo' is enclosed in 'Local'", + // ((JavaSourceLoaderImpl.JavaClass)mainFooClass).getEnclosingClass(), + // localClass); + } + }), true); + } + + @Test public void testAnonymousClass() { + runTest(singleTestSrc(), rtJar, simpleTestEntryPoint(), Arrays.asList( + + new IRAssertion() { + + public void check(CallGraph cg) { + final String typeStr = singleInputForTest(); + + final TypeReference type = findOrCreateTypeReference("Source", typeStr, cg.getClassHierarchy()); + + final IClass iClass = cg.getClassHierarchy().lookupClass(type); + Assert.assertNotNull("Could not find class " + typeStr, iClass); + + // todo what to check?? could not find anything in the APIs for + // anonymous + } + }), true); + } + + @Test public void testWhileTest1() { + runTest(singleTestSrc(), rtJar, simpleTestEntryPoint(), emptyList, true); + } + + @Test public void testSwitch1() { + runTest(singleTestSrc(), rtJar, simpleTestEntryPoint(), emptyList, true); + } + + @Test public void testException1() { + runTest(singleTestSrc(), rtJar, simpleTestEntryPoint(), emptyList, true); + } + + @Test public void testException2() { + runTest(singleTestSrc(), rtJar, simpleTestEntryPoint(), emptyList, true); + } + + @Test public void testFinally1() { + runTest(singleTestSrc(), rtJar, simpleTestEntryPoint(), emptyList, true); + } + + @Test public void testScoping1() { + runTest(singleTestSrc(), rtJar, simpleTestEntryPoint(), emptyList, true); + } + + @Test public void testScoping2() { + runTest(singleTestSrc(), rtJar, simpleTestEntryPoint(), emptyList, true); + } + + @Test public void testNonPrimaryTopLevel() { + runTest(singlePkgTestSrc("p"), rtJar, simplePkgTestEntryPoint("p"), emptyList, true); + } + + @Test public void testMiniaturList() { + runTest(singleTestSrc(), rtJar, simpleTestEntryPoint(), emptyList, true); + } + + @Test public void testMonitor() { + runTest(singleTestSrc(), rtJar, simpleTestEntryPoint(), emptyList, true); + } + + @Test public void testStaticInitializers() { + runTest(singleTestSrc(), rtJar, simpleTestEntryPoint(), emptyList, true); + } + + @Test public void testThread1() { + runTest(singleTestSrc(), rtJar, simpleTestEntryPoint(), emptyList, true); + } + + @Test public void testCasts() { + runTest(singleTestSrc(), rtJar, simpleTestEntryPoint(), emptyList, true); + } + + @Test public void testBreaks() { + runTest(singleTestSrc(), rtJar, simpleTestEntryPoint(), emptyList, true); + } + + private MethodReference getSliceRootReference(String className, String methodName, String methodDescriptor) { + TypeName clsName = TypeName.string2TypeName("L" + className.replace('.', '/')); + TypeReference clsRef = TypeReference.findOrCreate(JavaSourceAnalysisScope.SOURCE, clsName); + + Atom nameAtom = Atom.findOrCreateUnicodeAtom(methodName); + Descriptor descr = Descriptor.findOrCreateUTF8(Language.JAVA, methodDescriptor); + + return MethodReference.findOrCreate(clsRef, nameAtom, descr); + } + + @Test public void testMiniaturSliceBug() throws IllegalArgumentException, CancelException { + Pair x = runTest(singleTestSrc(), rtJar, simpleTestEntryPoint(), emptyList, true); + + PointerAnalysis pa = (PointerAnalysis) x.snd; + CallGraph cg = (CallGraph) x.fst; + + // test partial slice + MethodReference sliceRootRef = getSliceRootReference("MiniaturSliceBug", "validNonDispatchedCall", "(LIntWrapper;)V"); + Set roots = cg.getNodes(sliceRootRef); + Pair, SDG> y = AstJavaSlicer.computeAssertionSlice(cg, pa, roots, false); + Collection slice = y.fst; + SlicerTest.dumpSlice(slice); + Assert.assertEquals(0, SlicerTest.countAllocations(slice)); + Assert.assertEquals(1, SlicerTest.countPutfields(slice)); + + // test slice from main + sliceRootRef = getSliceRootReference("MiniaturSliceBug", "main", "([Ljava/lang/String;)V"); + roots = cg.getNodes(sliceRootRef); + y = AstJavaSlicer.computeAssertionSlice(cg, pa, roots, false); + slice = y.fst; + SlicerTest.dumpSlice(slice); + Assert.assertEquals(2, SlicerTest.countAllocations(slice)); + Assert.assertEquals(2, SlicerTest.countPutfields(slice)); + } + +} diff --git a/com.ibm.wala.cast.java/src/com/ibm/wala/cast/java/client/JavaSourceAnalysisEngine.java b/com.ibm.wala.cast.java/src/com/ibm/wala/cast/java/client/JavaSourceAnalysisEngine.java index 2bab0c5aa..3e89a8f60 100644 --- a/com.ibm.wala.cast.java/src/com/ibm/wala/cast/java/client/JavaSourceAnalysisEngine.java +++ b/com.ibm.wala.cast.java/src/com/ibm/wala/cast/java/client/JavaSourceAnalysisEngine.java @@ -1,165 +1,165 @@ -/****************************************************************************** - * Copyright (c) 2002 - 2006 IBM Corporation. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * IBM Corporation - initial API and implementation - *****************************************************************************/ -package com.ibm.wala.cast.java.client; - -import java.io.File; -import java.io.IOException; -import java.util.Set; - -import com.ibm.wala.cast.ir.ssa.AstIRFactory; -import com.ibm.wala.cast.java.client.impl.ZeroCFABuilderFactory; -import com.ibm.wala.cast.java.ipa.callgraph.JavaSourceAnalysisScope; -import com.ibm.wala.classLoader.ClassLoaderFactory; -import com.ibm.wala.classLoader.Module; -import com.ibm.wala.client.AbstractAnalysisEngine; -import com.ibm.wala.ipa.callgraph.AnalysisCache; -import com.ibm.wala.ipa.callgraph.AnalysisOptions; -import com.ibm.wala.ipa.callgraph.AnalysisScope; -import com.ibm.wala.ipa.callgraph.CallGraphBuilder; -import com.ibm.wala.ipa.callgraph.Entrypoint; -import com.ibm.wala.ipa.callgraph.impl.SetOfClasses; -import com.ibm.wala.ipa.callgraph.impl.Util; -import com.ibm.wala.ipa.cha.ClassHierarchy; -import com.ibm.wala.ipa.cha.ClassHierarchyException; -import com.ibm.wala.ipa.cha.IClassHierarchy; -import com.ibm.wala.ssa.SSAOptions; -import com.ibm.wala.ssa.SymbolTable; -import com.ibm.wala.types.ClassLoaderReference; -import com.ibm.wala.util.collections.HashSetFactory; -import com.ibm.wala.util.config.FileOfClasses; - -/** - */ -public abstract class JavaSourceAnalysisEngine extends AbstractAnalysisEngine { - - /** - * Modules which are user-space code - */ - private final Set userEntries = HashSetFactory.make(); - - /** - * Modules which are source code - */ - private final Set sourceEntries = HashSetFactory.make(); - - /** - * Modules which are system or library code TODO: what about extension loader? - */ - private final Set systemEntries = HashSetFactory.make(); - - public JavaSourceAnalysisEngine() { - super(); - } - - /** - * Adds the given source module to the source loader's module list. Clients - * should/may call this method if they don't supply an IJavaProject to the - * constructor. - */ - public void addSourceModule(Module M) { - sourceEntries.add(M); - } - - /** - * Adds the given compiled module to the application loader's module list. - * Clients should/may call this method if they don't supply an IJavaProject to - * the constructor. - */ - public void addCompiledModule(Module M) { - userEntries.add(M); - } - - /** - * Adds the given module to the primordial loader's module list. Clients - * should/may call this method if they don't supply an IJavaProject to the - * constructor. - */ - public void addSystemModule(Module M) { - systemEntries.add(M); - } - - protected void addApplicationModulesToScope() { - ClassLoaderReference app = scope.getApplicationLoader(); - for (Module M : userEntries) { - scope.addToScope(app, M); - } - - ClassLoaderReference src = ((JavaSourceAnalysisScope) scope).getSourceLoader(); - - for (Module M : sourceEntries) { - scope.addToScope(src, M); - } - } - - public void buildAnalysisScope() throws IOException { - scope = makeSourceAnalysisScope(); - - if (getExclusionsFile() != null) { - scope.setExclusions(FileOfClasses.createFileOfClasses(new File(getExclusionsFile()))); - } - - for (Module M : this.systemEntries) { - scope.addToScope(scope.getPrimordialLoader(), M); - } - - // add user stuff - addApplicationModulesToScope(); - } - - protected AnalysisScope makeSourceAnalysisScope() { - return new JavaSourceAnalysisScope(); - } - - protected abstract ClassLoaderFactory getClassLoaderFactory(SetOfClasses exclusions); - - public IClassHierarchy buildClassHierarchy() { - IClassHierarchy cha = null; - ClassLoaderFactory factory = getClassLoaderFactory(scope.getExclusions()); - - try { - cha = ClassHierarchy.make(getScope(), factory); - } catch (ClassHierarchyException e) { - System.err.println("Class Hierarchy construction failed"); - System.err.println(e.toString()); - e.printStackTrace(); - } - return cha; - } - - protected Iterable makeDefaultEntrypoints(AnalysisScope scope, IClassHierarchy cha) { - return Util.makeMainEntrypoints(JavaSourceAnalysisScope.SOURCE, cha); - } - - @Override - public AnalysisCache makeDefaultCache() { - return new AnalysisCache(AstIRFactory.makeDefaultFactory()); - } - - public AnalysisOptions getDefaultOptions(Iterable entrypoints) { - AnalysisOptions options = new AnalysisOptions(getScope(), entrypoints); - - SSAOptions ssaOptions = new SSAOptions(); - ssaOptions.setDefaultValues(new SSAOptions.DefaultValues() { - public int getDefaultValue(SymbolTable symtab, int valueNumber) { - return symtab.getDefaultValue(valueNumber); - } - }); - - options.setSSAOptions(ssaOptions); - - return options; - } - - @Override - protected CallGraphBuilder getCallGraphBuilder(IClassHierarchy cha, AnalysisOptions options, AnalysisCache cache) { - return new ZeroCFABuilderFactory().make(options, cache, cha, scope, false); - } -} +/****************************************************************************** + * Copyright (c) 2002 - 2006 IBM Corporation. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *****************************************************************************/ +package com.ibm.wala.cast.java.client; + +import java.io.File; +import java.io.IOException; +import java.util.Set; + +import com.ibm.wala.cast.ir.ssa.AstIRFactory; +import com.ibm.wala.cast.java.client.impl.ZeroCFABuilderFactory; +import com.ibm.wala.cast.java.ipa.callgraph.JavaSourceAnalysisScope; +import com.ibm.wala.classLoader.ClassLoaderFactory; +import com.ibm.wala.classLoader.Module; +import com.ibm.wala.client.AbstractAnalysisEngine; +import com.ibm.wala.ipa.callgraph.AnalysisCache; +import com.ibm.wala.ipa.callgraph.AnalysisOptions; +import com.ibm.wala.ipa.callgraph.AnalysisScope; +import com.ibm.wala.ipa.callgraph.CallGraphBuilder; +import com.ibm.wala.ipa.callgraph.Entrypoint; +import com.ibm.wala.ipa.callgraph.impl.SetOfClasses; +import com.ibm.wala.ipa.callgraph.impl.Util; +import com.ibm.wala.ipa.cha.ClassHierarchy; +import com.ibm.wala.ipa.cha.ClassHierarchyException; +import com.ibm.wala.ipa.cha.IClassHierarchy; +import com.ibm.wala.ssa.SSAOptions; +import com.ibm.wala.ssa.SymbolTable; +import com.ibm.wala.types.ClassLoaderReference; +import com.ibm.wala.util.collections.HashSetFactory; +import com.ibm.wala.util.config.FileOfClasses; + +/** + */ +public abstract class JavaSourceAnalysisEngine extends AbstractAnalysisEngine { + + /** + * Modules which are user-space code + */ + private final Set userEntries = HashSetFactory.make(); + + /** + * Modules which are source code + */ + private final Set sourceEntries = HashSetFactory.make(); + + /** + * Modules which are system or library code TODO: what about extension loader? + */ + private final Set systemEntries = HashSetFactory.make(); + + public JavaSourceAnalysisEngine() { + super(); + } + + /** + * Adds the given source module to the source loader's module list. Clients + * should/may call this method if they don't supply an IJavaProject to the + * constructor. + */ + public void addSourceModule(Module M) { + sourceEntries.add(M); + } + + /** + * Adds the given compiled module to the application loader's module list. + * Clients should/may call this method if they don't supply an IJavaProject to + * the constructor. + */ + public void addCompiledModule(Module M) { + userEntries.add(M); + } + + /** + * Adds the given module to the primordial loader's module list. Clients + * should/may call this method if they don't supply an IJavaProject to the + * constructor. + */ + public void addSystemModule(Module M) { + systemEntries.add(M); + } + + protected void addApplicationModulesToScope() { + ClassLoaderReference app = scope.getApplicationLoader(); + for (Module M : userEntries) { + scope.addToScope(app, M); + } + + ClassLoaderReference src = ((JavaSourceAnalysisScope) scope).getSourceLoader(); + + for (Module M : sourceEntries) { + scope.addToScope(src, M); + } + } + + public void buildAnalysisScope() throws IOException { + scope = makeSourceAnalysisScope(); + + if (getExclusionsFile() != null) { + scope.setExclusions(FileOfClasses.createFileOfClasses(new File(getExclusionsFile()))); + } + + for (Module M : this.systemEntries) { + scope.addToScope(scope.getPrimordialLoader(), M); + } + + // add user stuff + addApplicationModulesToScope(); + } + + protected AnalysisScope makeSourceAnalysisScope() { + return new JavaSourceAnalysisScope(); + } + + protected abstract ClassLoaderFactory getClassLoaderFactory(SetOfClasses exclusions); + + public IClassHierarchy buildClassHierarchy() { + IClassHierarchy cha = null; + ClassLoaderFactory factory = getClassLoaderFactory(scope.getExclusions()); + + try { + cha = ClassHierarchy.make(getScope(), factory); + } catch (ClassHierarchyException e) { + System.err.println("Class Hierarchy construction failed"); + System.err.println(e.toString()); + e.printStackTrace(); + } + return cha; + } + + protected Iterable makeDefaultEntrypoints(AnalysisScope scope, IClassHierarchy cha) { + return Util.makeMainEntrypoints(JavaSourceAnalysisScope.SOURCE, cha); + } + + @Override + public AnalysisCache makeDefaultCache() { + return new AnalysisCache(AstIRFactory.makeDefaultFactory()); + } + + public AnalysisOptions getDefaultOptions(Iterable entrypoints) { + AnalysisOptions options = new AnalysisOptions(getScope(), entrypoints); + + SSAOptions ssaOptions = new SSAOptions(); + ssaOptions.setDefaultValues(new SSAOptions.DefaultValues() { + public int getDefaultValue(SymbolTable symtab, int valueNumber) { + return symtab.getDefaultValue(valueNumber); + } + }); + + options.setSSAOptions(ssaOptions); + + return options; + } + + @Override + protected CallGraphBuilder getCallGraphBuilder(IClassHierarchy cha, AnalysisOptions options, AnalysisCache cache) { + return new ZeroCFABuilderFactory().make(options, cache, cha, scope, false); + } +} diff --git a/com.ibm.wala.cast.java/src/com/ibm/wala/cast/java/ipa/callgraph/AstJavaZeroOneContainerCFABuilder.java b/com.ibm.wala.cast.java/src/com/ibm/wala/cast/java/ipa/callgraph/AstJavaZeroOneContainerCFABuilder.java index fcd3eb2ec..903cb85bf 100644 --- a/com.ibm.wala.cast.java/src/com/ibm/wala/cast/java/ipa/callgraph/AstJavaZeroOneContainerCFABuilder.java +++ b/com.ibm.wala.cast.java/src/com/ibm/wala/cast/java/ipa/callgraph/AstJavaZeroOneContainerCFABuilder.java @@ -1,75 +1,75 @@ -/******************************************************************************* - * Copyright (c) 2002 - 2006 IBM Corporation. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * IBM Corporation - initial API and implementation - *******************************************************************************/ -package com.ibm.wala.cast.java.ipa.callgraph; - -import com.ibm.wala.ipa.callgraph.AnalysisCache; -import com.ibm.wala.ipa.callgraph.AnalysisOptions; -import com.ibm.wala.ipa.callgraph.ContextSelector; -import com.ibm.wala.ipa.callgraph.impl.DefaultContextSelector; -import com.ibm.wala.ipa.callgraph.impl.DelegatingContextSelector; -import com.ibm.wala.ipa.callgraph.propagation.SSAContextInterpreter; -import com.ibm.wala.ipa.callgraph.propagation.cfa.ContainerContextSelector; -import com.ibm.wala.ipa.callgraph.propagation.cfa.ZeroXInstanceKeys; -import com.ibm.wala.ipa.cha.IClassHierarchy; - -/** - * - * 0-1-CFA Call graph builder which analyzes calls to "container methods" in a context which is defined by the receiver - * instance. - * - * @author sfink - */ -public class AstJavaZeroOneContainerCFABuilder extends AstJavaCFABuilder { - - /** - * @param cha governing class hierarchy - * @param warnings object to track analysis warnings - * @param options call graph construction options - * @param appContextSelector application-specific logic to choose contexts - * @param appContextInterpreter application-specific logic to interpret a method in context - * @param reflect reflection specification - */ - public AstJavaZeroOneContainerCFABuilder(IClassHierarchy cha, AnalysisOptions options, AnalysisCache cache, - ContextSelector appContextSelector, SSAContextInterpreter appContextInterpreter) { - super(cha, options, cache); - - ContextSelector def = new DefaultContextSelector(options, cha); - ContextSelector contextSelector = appContextSelector == null ? def : new DelegatingContextSelector(appContextSelector, def); - - SSAContextInterpreter contextInterpreter = makeDefaultContextInterpreters(appContextInterpreter, options, cha); - setContextInterpreter(contextInterpreter); - - ZeroXInstanceKeys zik = makeInstanceKeys(cha, options, contextInterpreter); - setInstanceKeys(new JavaScopeMappingInstanceKeys(cha, this, zik)); - - ContextSelector CCS = makeContainerContextSelector(cha, zik); - DelegatingContextSelector DCS = new DelegatingContextSelector(CCS, contextSelector); - setContextSelector(DCS); - } - - protected ZeroXInstanceKeys makeInstanceKeys(IClassHierarchy cha, AnalysisOptions options, - SSAContextInterpreter contextInterpreter) { - ZeroXInstanceKeys zik = new ZeroXInstanceKeys(options, cha, contextInterpreter, ZeroXInstanceKeys.ALLOCATIONS - | ZeroXInstanceKeys.SMUSH_PRIMITIVE_HOLDERS | ZeroXInstanceKeys.SMUSH_STRINGS | ZeroXInstanceKeys.SMUSH_MANY - | ZeroXInstanceKeys.SMUSH_THROWABLES); - return zik; - } - - /** - * @param cha - * @param keys - * @return an object which creates contexts for call graph nodes based on the container disambiguation policy - */ - protected ContextSelector makeContainerContextSelector(IClassHierarchy cha, ZeroXInstanceKeys keys) { - return new ContainerContextSelector(cha, keys); - } - -} +/******************************************************************************* + * Copyright (c) 2002 - 2006 IBM Corporation. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package com.ibm.wala.cast.java.ipa.callgraph; + +import com.ibm.wala.ipa.callgraph.AnalysisCache; +import com.ibm.wala.ipa.callgraph.AnalysisOptions; +import com.ibm.wala.ipa.callgraph.ContextSelector; +import com.ibm.wala.ipa.callgraph.impl.DefaultContextSelector; +import com.ibm.wala.ipa.callgraph.impl.DelegatingContextSelector; +import com.ibm.wala.ipa.callgraph.propagation.SSAContextInterpreter; +import com.ibm.wala.ipa.callgraph.propagation.cfa.ContainerContextSelector; +import com.ibm.wala.ipa.callgraph.propagation.cfa.ZeroXInstanceKeys; +import com.ibm.wala.ipa.cha.IClassHierarchy; + +/** + * + * 0-1-CFA Call graph builder which analyzes calls to "container methods" in a context which is defined by the receiver + * instance. + * + * @author sfink + */ +public class AstJavaZeroOneContainerCFABuilder extends AstJavaCFABuilder { + + /** + * @param cha governing class hierarchy + * @param warnings object to track analysis warnings + * @param options call graph construction options + * @param appContextSelector application-specific logic to choose contexts + * @param appContextInterpreter application-specific logic to interpret a method in context + * @param reflect reflection specification + */ + public AstJavaZeroOneContainerCFABuilder(IClassHierarchy cha, AnalysisOptions options, AnalysisCache cache, + ContextSelector appContextSelector, SSAContextInterpreter appContextInterpreter) { + super(cha, options, cache); + + ContextSelector def = new DefaultContextSelector(options, cha); + ContextSelector contextSelector = appContextSelector == null ? def : new DelegatingContextSelector(appContextSelector, def); + + SSAContextInterpreter contextInterpreter = makeDefaultContextInterpreters(appContextInterpreter, options, cha); + setContextInterpreter(contextInterpreter); + + ZeroXInstanceKeys zik = makeInstanceKeys(cha, options, contextInterpreter); + setInstanceKeys(new JavaScopeMappingInstanceKeys(cha, this, zik)); + + ContextSelector CCS = makeContainerContextSelector(cha, zik); + DelegatingContextSelector DCS = new DelegatingContextSelector(CCS, contextSelector); + setContextSelector(DCS); + } + + protected ZeroXInstanceKeys makeInstanceKeys(IClassHierarchy cha, AnalysisOptions options, + SSAContextInterpreter contextInterpreter) { + ZeroXInstanceKeys zik = new ZeroXInstanceKeys(options, cha, contextInterpreter, ZeroXInstanceKeys.ALLOCATIONS + | ZeroXInstanceKeys.SMUSH_PRIMITIVE_HOLDERS | ZeroXInstanceKeys.SMUSH_STRINGS | ZeroXInstanceKeys.SMUSH_MANY + | ZeroXInstanceKeys.SMUSH_THROWABLES); + return zik; + } + + /** + * @param cha + * @param keys + * @return an object which creates contexts for call graph nodes based on the container disambiguation policy + */ + protected ContextSelector makeContainerContextSelector(IClassHierarchy cha, ZeroXInstanceKeys keys) { + return new ContainerContextSelector(cha, keys); + } + +} diff --git a/com.ibm.wala.cast.java/src/com/ibm/wala/cast/java/ipa/slicer/AstJavaSlicer.java b/com.ibm.wala.cast.java/src/com/ibm/wala/cast/java/ipa/slicer/AstJavaSlicer.java index ae66bae0b..8a0dd8501 100644 --- a/com.ibm.wala.cast.java/src/com/ibm/wala/cast/java/ipa/slicer/AstJavaSlicer.java +++ b/com.ibm.wala.cast.java/src/com/ibm/wala/cast/java/ipa/slicer/AstJavaSlicer.java @@ -1,115 +1,115 @@ -package com.ibm.wala.cast.java.ipa.slicer; - -import java.util.Collection; -import java.util.HashSet; -import java.util.Iterator; -import java.util.LinkedHashSet; -import java.util.Set; - -import com.ibm.wala.cast.ir.ssa.AstAssertInstruction; -import com.ibm.wala.cast.java.ipa.modref.AstJavaModRef; -import com.ibm.wala.ipa.callgraph.CGNode; -import com.ibm.wala.ipa.callgraph.CallGraph; -import com.ibm.wala.ipa.callgraph.impl.PartialCallGraph; -import com.ibm.wala.ipa.callgraph.propagation.PointerAnalysis; -import com.ibm.wala.ipa.slicer.NormalStatement; -import com.ibm.wala.ipa.slicer.SDG; -import com.ibm.wala.ipa.slicer.Slicer; -import com.ibm.wala.ipa.slicer.Statement; -import com.ibm.wala.ssa.IR; -import com.ibm.wala.ssa.SSAArrayLoadInstruction; -import com.ibm.wala.ssa.SSAArrayStoreInstruction; -import com.ibm.wala.ssa.SSAGetInstruction; -import com.ibm.wala.ssa.SSAInstruction; -import com.ibm.wala.ssa.SSAMonitorInstruction; -import com.ibm.wala.ssa.SSAPutInstruction; -import com.ibm.wala.util.CancelException; -import com.ibm.wala.util.collections.Filter; -import com.ibm.wala.util.collections.Pair; -import com.ibm.wala.util.graph.traverse.DFS; - -@SuppressWarnings("deprecation") -public class AstJavaSlicer extends Slicer { - - /* - * Use the passed-in SDG - */ - public static Collection computeBackwardSlice(SDG sdg, Collection ss) throws IllegalArgumentException, - CancelException { - return computeSlice(sdg, ss, true); - } - - /** - * @param ss a collection of statements of interest - * @throws CancelException - */ - public static Collection computeSlice(SDG sdg, Collection ss, boolean backward) throws CancelException { - return new AstJavaSlicer().slice(sdg, ss, backward); - } - - public static Set gatherStatements(CallGraph CG, Collection partialRoots, Filter filter) { - Set result = new HashSet(); - for (Iterator ns = DFS.getReachableNodes(CG, partialRoots).iterator(); ns.hasNext();) { - CGNode n = ns.next(); - IR nir = n.getIR(); - if (nir != null) { - SSAInstruction insts[] = nir.getInstructions(); - for (int i = 0; i < insts.length; i++) { - if (filter.accepts(insts[i])) { - result.add(new NormalStatement(n, i)); - } - } - } - } - - return result; - } - - public static Set gatherAssertions(CallGraph CG, Collection partialRoots) { - return gatherStatements(CG, partialRoots, new Filter() { - public boolean accepts(SSAInstruction o) { - return o instanceof AstAssertInstruction; - } - }); - } - - public static Set gatherMonitors(CallGraph CG, Collection partialRoots) { - return gatherStatements(CG, partialRoots, new Filter() { - public boolean accepts(SSAInstruction o) { - return o instanceof SSAMonitorInstruction; - } - }); - } - - public static Set gatherWrites(CallGraph CG, Collection partialRoots) { - return gatherStatements(CG, partialRoots, new Filter() { - public boolean accepts(SSAInstruction o) { - return (o instanceof SSAPutInstruction) || (o instanceof SSAArrayStoreInstruction); - } - }); - } - - public static Set gatherReads(CallGraph CG, Collection partialRoots) { - return gatherStatements(CG, partialRoots, new Filter() { - public boolean accepts(SSAInstruction o) { - return (o instanceof SSAGetInstruction) || (o instanceof SSAArrayLoadInstruction); - } - }); - } - - public static Pair, SDG> computeAssertionSlice(CallGraph CG, PointerAnalysis pa, - Collection partialRoots, boolean multiThreadedCode) throws IllegalArgumentException, CancelException { - CallGraph pcg = PartialCallGraph.make(CG, new LinkedHashSet(partialRoots)); - SDG sdg = new SDG(pcg, pa, new AstJavaModRef(), DataDependenceOptions.FULL, ControlDependenceOptions.FULL); - System.err.println(("SDG:\n" + sdg)); - Set stmts = gatherAssertions(CG, partialRoots); - if (multiThreadedCode) { - // Grab anything that has "side effects" under JMM - stmts.addAll(gatherReads(CG, partialRoots)); - stmts.addAll(gatherWrites(CG, partialRoots)); - stmts.addAll(gatherMonitors(CG, partialRoots)); - } - return Pair.make(AstJavaSlicer.computeBackwardSlice(sdg, stmts), sdg); - } - -} +package com.ibm.wala.cast.java.ipa.slicer; + +import java.util.Collection; +import java.util.HashSet; +import java.util.Iterator; +import java.util.LinkedHashSet; +import java.util.Set; + +import com.ibm.wala.cast.ir.ssa.AstAssertInstruction; +import com.ibm.wala.cast.java.ipa.modref.AstJavaModRef; +import com.ibm.wala.ipa.callgraph.CGNode; +import com.ibm.wala.ipa.callgraph.CallGraph; +import com.ibm.wala.ipa.callgraph.impl.PartialCallGraph; +import com.ibm.wala.ipa.callgraph.propagation.PointerAnalysis; +import com.ibm.wala.ipa.slicer.NormalStatement; +import com.ibm.wala.ipa.slicer.SDG; +import com.ibm.wala.ipa.slicer.Slicer; +import com.ibm.wala.ipa.slicer.Statement; +import com.ibm.wala.ssa.IR; +import com.ibm.wala.ssa.SSAArrayLoadInstruction; +import com.ibm.wala.ssa.SSAArrayStoreInstruction; +import com.ibm.wala.ssa.SSAGetInstruction; +import com.ibm.wala.ssa.SSAInstruction; +import com.ibm.wala.ssa.SSAMonitorInstruction; +import com.ibm.wala.ssa.SSAPutInstruction; +import com.ibm.wala.util.CancelException; +import com.ibm.wala.util.collections.Filter; +import com.ibm.wala.util.collections.Pair; +import com.ibm.wala.util.graph.traverse.DFS; + +@SuppressWarnings("deprecation") +public class AstJavaSlicer extends Slicer { + + /* + * Use the passed-in SDG + */ + public static Collection computeBackwardSlice(SDG sdg, Collection ss) throws IllegalArgumentException, + CancelException { + return computeSlice(sdg, ss, true); + } + + /** + * @param ss a collection of statements of interest + * @throws CancelException + */ + public static Collection computeSlice(SDG sdg, Collection ss, boolean backward) throws CancelException { + return new AstJavaSlicer().slice(sdg, ss, backward); + } + + public static Set gatherStatements(CallGraph CG, Collection partialRoots, Filter filter) { + Set result = new HashSet(); + for (Iterator ns = DFS.getReachableNodes(CG, partialRoots).iterator(); ns.hasNext();) { + CGNode n = ns.next(); + IR nir = n.getIR(); + if (nir != null) { + SSAInstruction insts[] = nir.getInstructions(); + for (int i = 0; i < insts.length; i++) { + if (filter.accepts(insts[i])) { + result.add(new NormalStatement(n, i)); + } + } + } + } + + return result; + } + + public static Set gatherAssertions(CallGraph CG, Collection partialRoots) { + return gatherStatements(CG, partialRoots, new Filter() { + public boolean accepts(SSAInstruction o) { + return o instanceof AstAssertInstruction; + } + }); + } + + public static Set gatherMonitors(CallGraph CG, Collection partialRoots) { + return gatherStatements(CG, partialRoots, new Filter() { + public boolean accepts(SSAInstruction o) { + return o instanceof SSAMonitorInstruction; + } + }); + } + + public static Set gatherWrites(CallGraph CG, Collection partialRoots) { + return gatherStatements(CG, partialRoots, new Filter() { + public boolean accepts(SSAInstruction o) { + return (o instanceof SSAPutInstruction) || (o instanceof SSAArrayStoreInstruction); + } + }); + } + + public static Set gatherReads(CallGraph CG, Collection partialRoots) { + return gatherStatements(CG, partialRoots, new Filter() { + public boolean accepts(SSAInstruction o) { + return (o instanceof SSAGetInstruction) || (o instanceof SSAArrayLoadInstruction); + } + }); + } + + public static Pair, SDG> computeAssertionSlice(CallGraph CG, PointerAnalysis pa, + Collection partialRoots, boolean multiThreadedCode) throws IllegalArgumentException, CancelException { + CallGraph pcg = PartialCallGraph.make(CG, new LinkedHashSet(partialRoots)); + SDG sdg = new SDG(pcg, pa, new AstJavaModRef(), DataDependenceOptions.FULL, ControlDependenceOptions.FULL); + System.err.println(("SDG:\n" + sdg)); + Set stmts = gatherAssertions(CG, partialRoots); + if (multiThreadedCode) { + // Grab anything that has "side effects" under JMM + stmts.addAll(gatherReads(CG, partialRoots)); + stmts.addAll(gatherWrites(CG, partialRoots)); + stmts.addAll(gatherMonitors(CG, partialRoots)); + } + return Pair.make(AstJavaSlicer.computeBackwardSlice(sdg, stmts), sdg); + } + +} diff --git a/com.ibm.wala.cast.java/src/com/ibm/wala/cast/java/ssa/EnclosingObjectReference.java b/com.ibm.wala.cast.java/src/com/ibm/wala/cast/java/ssa/EnclosingObjectReference.java index 6dae54b6f..fae2817fa 100644 --- a/com.ibm.wala.cast.java/src/com/ibm/wala/cast/java/ssa/EnclosingObjectReference.java +++ b/com.ibm.wala.cast.java/src/com/ibm/wala/cast/java/ssa/EnclosingObjectReference.java @@ -1,74 +1,74 @@ -package com.ibm.wala.cast.java.ssa; - -import java.util.Collection; -import java.util.Collections; - -import com.ibm.wala.ssa.SSAInstruction; -import com.ibm.wala.ssa.SSAInstructionFactory; -import com.ibm.wala.ssa.SymbolTable; -import com.ibm.wala.types.TypeReference; - -/** - * The CAst source language front end for Java has explicit support for lexically-enclosing objects, rather than compiling them - * away into extra fields and access-control thwarting accessor methods as is done in bytecode. This instruction represents a read - * of the object of the given type that lexically encloses its use value. - * - * @author Julian Dolby (dolby@us.ibm.com) - */ -public class EnclosingObjectReference extends SSAInstruction { - private final TypeReference type; - - private final int lval; - - public EnclosingObjectReference(int lval, TypeReference type) { - this.lval = lval; - this.type = type; - } - - public boolean hasDef() { - return true; - } - - public int getDef() { - return lval; - } - - public int getDef(int i) { - assert i == 0; - - return lval; - } - - public int getNumberOfDefs() { - return 1; - } - - public TypeReference getEnclosingType() { - return type; - } - - public SSAInstruction copyForSSA(SSAInstructionFactory insts, int[] defs, int[] uses) { - return ((AstJavaInstructionFactory) insts).EnclosingObjectReference(defs == null ? lval : defs[0], type); - } - - public String toString(SymbolTable symbolTable) { - return getValueString(symbolTable, lval) + " = enclosing " + type.getName(); - } - - public void visit(IVisitor v) { - ((AstJavaInstructionVisitor) v).visitEnclosingObjectReference(this); - } - - public int hashCode() { - return lval * type.hashCode(); - } - - public Collection getExceptionTypes() { - return Collections.emptySet(); - } - - public boolean isFallThrough() { - return true; - } - -} +package com.ibm.wala.cast.java.ssa; + +import java.util.Collection; +import java.util.Collections; + +import com.ibm.wala.ssa.SSAInstruction; +import com.ibm.wala.ssa.SSAInstructionFactory; +import com.ibm.wala.ssa.SymbolTable; +import com.ibm.wala.types.TypeReference; + +/** + * The CAst source language front end for Java has explicit support for lexically-enclosing objects, rather than compiling them + * away into extra fields and access-control thwarting accessor methods as is done in bytecode. This instruction represents a read + * of the object of the given type that lexically encloses its use value. + * + * @author Julian Dolby (dolby@us.ibm.com) + */ +public class EnclosingObjectReference extends SSAInstruction { + private final TypeReference type; + + private final int lval; + + public EnclosingObjectReference(int lval, TypeReference type) { + this.lval = lval; + this.type = type; + } + + public boolean hasDef() { + return true; + } + + public int getDef() { + return lval; + } + + public int getDef(int i) { + assert i == 0; + + return lval; + } + + public int getNumberOfDefs() { + return 1; + } + + public TypeReference getEnclosingType() { + return type; + } + + public SSAInstruction copyForSSA(SSAInstructionFactory insts, int[] defs, int[] uses) { + return ((AstJavaInstructionFactory) insts).EnclosingObjectReference(defs == null ? lval : defs[0], type); + } + + public String toString(SymbolTable symbolTable) { + return getValueString(symbolTable, lval) + " = enclosing " + type.getName(); + } + + public void visit(IVisitor v) { + ((AstJavaInstructionVisitor) v).visitEnclosingObjectReference(this); + } + + public int hashCode() { + return lval * type.hashCode(); + } + + public Collection getExceptionTypes() { + return Collections.emptySet(); + } + + public boolean isFallThrough() { + return true; + } + +} diff --git a/com.ibm.wala.cast.js.rhino.test/harness-src/com/ibm/wala/cast/js/vis/JsViewerDriver.java b/com.ibm.wala.cast.js.rhino.test/harness-src/com/ibm/wala/cast/js/vis/JsViewerDriver.java index b295927c7..f6de71dad 100644 --- a/com.ibm.wala.cast.js.rhino.test/harness-src/com/ibm/wala/cast/js/vis/JsViewerDriver.java +++ b/com.ibm.wala.cast.js.rhino.test/harness-src/com/ibm/wala/cast/js/vis/JsViewerDriver.java @@ -1,71 +1,71 @@ -package com.ibm.wala.cast.js.vis; - -import java.io.IOException; -import java.net.URL; -import java.util.Set; - -import com.ibm.wala.cast.ir.ssa.AstIRFactory; -import com.ibm.wala.cast.js.html.DefaultSourceExtractor; -import com.ibm.wala.cast.js.html.DomLessSourceExtractor; -import com.ibm.wala.cast.js.html.IdentityUrlResolver; -import com.ibm.wala.cast.js.html.JSSourceExtractor; -import com.ibm.wala.cast.js.html.MappedSourceModule; -import com.ibm.wala.cast.js.html.WebPageLoaderFactory; -import com.ibm.wala.cast.js.html.WebUtil; -import com.ibm.wala.cast.js.html.jericho.JerichoHtmlParser; -import com.ibm.wala.cast.js.ipa.callgraph.JSCFABuilder; -import com.ibm.wala.cast.js.loader.JavaScriptLoader; -import com.ibm.wala.cast.js.test.JSCallGraphBuilderUtil; -import com.ibm.wala.cast.js.translator.CAstRhinoTranslatorFactory; -import com.ibm.wala.classLoader.SourceFileModule; -import com.ibm.wala.classLoader.SourceModule; -import com.ibm.wala.ipa.callgraph.CallGraph; -import com.ibm.wala.ipa.callgraph.propagation.PointerAnalysis; -import com.ibm.wala.ipa.cha.ClassHierarchyException; -import com.ibm.wala.util.CancelException; - -public class JsViewerDriver extends JSCallGraphBuilderUtil { - public static void main(String args[]) throws ClassHierarchyException, IllegalArgumentException, IOException, CancelException { - - if (args.length != 1){ - System.out.println("Usage: "); - System.exit(1); - } - boolean domless = false; - - URL url = new URL(args[0]); - - // computing CG + PA - JSCallGraphBuilderUtil.setTranslatorFactory(new CAstRhinoTranslatorFactory()); - JavaScriptLoader.addBootstrapFile(WebUtil.preamble); - - SourceModule[] sources = getSources(domless, url); - - JSCFABuilder builder = makeCGBuilder(new WebPageLoaderFactory(translatorFactory), sources, CGBuilderType.ZERO_ONE_CFA, AstIRFactory.makeDefaultFactory()); - builder.setBaseURL(url); - - CallGraph cg = builder.makeCallGraph(builder.getOptions()); - PointerAnalysis pa = builder.getPointerAnalysis(); - - new JsViewer(cg, pa); - } - - private static SourceModule[] getSources(boolean domless, URL url) - throws IOException { - JSSourceExtractor sourceExtractor; - if (domless ){ - sourceExtractor = new DomLessSourceExtractor(); - } else { - sourceExtractor = new DefaultSourceExtractor(); - } - - Set sourcesMap = sourceExtractor.extractSources(url, new JerichoHtmlParser(), new IdentityUrlResolver()); - SourceModule[] sources = new SourceFileModule[sourcesMap.size()]; - int i = 0; - for (SourceModule m : sourcesMap){ - sources[i++] = m; - } - return sources; - } - -} +package com.ibm.wala.cast.js.vis; + +import java.io.IOException; +import java.net.URL; +import java.util.Set; + +import com.ibm.wala.cast.ir.ssa.AstIRFactory; +import com.ibm.wala.cast.js.html.DefaultSourceExtractor; +import com.ibm.wala.cast.js.html.DomLessSourceExtractor; +import com.ibm.wala.cast.js.html.IdentityUrlResolver; +import com.ibm.wala.cast.js.html.JSSourceExtractor; +import com.ibm.wala.cast.js.html.MappedSourceModule; +import com.ibm.wala.cast.js.html.WebPageLoaderFactory; +import com.ibm.wala.cast.js.html.WebUtil; +import com.ibm.wala.cast.js.html.jericho.JerichoHtmlParser; +import com.ibm.wala.cast.js.ipa.callgraph.JSCFABuilder; +import com.ibm.wala.cast.js.loader.JavaScriptLoader; +import com.ibm.wala.cast.js.test.JSCallGraphBuilderUtil; +import com.ibm.wala.cast.js.translator.CAstRhinoTranslatorFactory; +import com.ibm.wala.classLoader.SourceFileModule; +import com.ibm.wala.classLoader.SourceModule; +import com.ibm.wala.ipa.callgraph.CallGraph; +import com.ibm.wala.ipa.callgraph.propagation.PointerAnalysis; +import com.ibm.wala.ipa.cha.ClassHierarchyException; +import com.ibm.wala.util.CancelException; + +public class JsViewerDriver extends JSCallGraphBuilderUtil { + public static void main(String args[]) throws ClassHierarchyException, IllegalArgumentException, IOException, CancelException { + + if (args.length != 1){ + System.out.println("Usage: "); + System.exit(1); + } + boolean domless = false; + + URL url = new URL(args[0]); + + // computing CG + PA + JSCallGraphBuilderUtil.setTranslatorFactory(new CAstRhinoTranslatorFactory()); + JavaScriptLoader.addBootstrapFile(WebUtil.preamble); + + SourceModule[] sources = getSources(domless, url); + + JSCFABuilder builder = makeCGBuilder(new WebPageLoaderFactory(translatorFactory), sources, CGBuilderType.ZERO_ONE_CFA, AstIRFactory.makeDefaultFactory()); + builder.setBaseURL(url); + + CallGraph cg = builder.makeCallGraph(builder.getOptions()); + PointerAnalysis pa = builder.getPointerAnalysis(); + + new JsViewer(cg, pa); + } + + private static SourceModule[] getSources(boolean domless, URL url) + throws IOException { + JSSourceExtractor sourceExtractor; + if (domless ){ + sourceExtractor = new DomLessSourceExtractor(); + } else { + sourceExtractor = new DefaultSourceExtractor(); + } + + Set sourcesMap = sourceExtractor.extractSources(url, new JerichoHtmlParser(), new IdentityUrlResolver()); + SourceModule[] sources = new SourceFileModule[sourcesMap.size()]; + int i = 0; + for (SourceModule m : sourcesMap){ + sources[i++] = m; + } + return sources; + } + +} diff --git a/com.ibm.wala.cast.js/source/com/ibm/wala/cast/js/html/DefaultSourceExtractor.java b/com.ibm.wala.cast.js/source/com/ibm/wala/cast/js/html/DefaultSourceExtractor.java index f60cd371d..141e320fc 100644 --- a/com.ibm.wala.cast.js/source/com/ibm/wala/cast/js/html/DefaultSourceExtractor.java +++ b/com.ibm.wala.cast.js/source/com/ibm/wala/cast/js/html/DefaultSourceExtractor.java @@ -1,185 +1,185 @@ -/****************************************************************************** - * Copyright (c) 2002 - 2011 IBM Corporation. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * IBM Corporation - initial API and implementation - *****************************************************************************/ - -package com.ibm.wala.cast.js.html; - -import java.net.MalformedURLException; -import java.net.URL; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Map; -import java.util.Map.Entry; -import java.util.Set; -import java.util.Stack; - -import com.ibm.wala.cast.tree.CAstSourcePositionMap.Position; -import com.ibm.wala.util.collections.HashMapFactory; -import com.ibm.wala.util.collections.Pair; - -public class DefaultSourceExtractor extends DomLessSourceExtractor{ - - protected static class HtmlCallBack extends DomLessSourceExtractor.HtmlCallback{ - - private final HashMap constructors = HashMapFactory.make(); - - private final Stack stack = new Stack(); - - private final Stack forms = new Stack(); - private final Set> sets = new HashSet>(); - - public HtmlCallBack(URL entrypointUrl, IUrlResolver urlResolver) { - super(entrypointUrl, urlResolver); - constructors.put("FORM", "DOMHTMLFormElement"); - constructors.put("TABLE", "DOMHTMLTableElement"); - } - - @Override - public void handleEndTag(ITag tag) { - super.handleEndTag(tag); - endElement(stack.pop()); - if (tag.getName().equalsIgnoreCase("FORM")) { - forms.pop(); - } - for(Entry> e : tag.getAllAttributes().entrySet()) { - String a = e.getKey(); - String v = e.getValue().fst; - if (v != null && v.startsWith("javascript:")) { - try { - entrypointRegion.println(" " + v.substring(11), e.getValue().snd, new URL(tag.getElementPosition().getURL().toString() + "#" + a)); - } catch (MalformedURLException ex) { - entrypointRegion.println(v.substring(11), e.getValue().snd, entrypointUrl); - } - } - } - } - - @Override - protected void handleDOM(ITag tag, String funcName) { - - String cons = constructors.get(tag.getName().toUpperCase()); - if(cons == null) cons = "DOMHTMLElement"; - writeElement(tag, cons, funcName); - newLine(); - } - - private void printlnIndented(String line, ITag relatedTag){ - printlnIndented(line, relatedTag==null? null: relatedTag.getElementPosition()); - } - - private void printlnIndented(String line, Position pos){ - StringBuilder indentedLine = new StringBuilder(); - for (int i = 0 ; i < stack.size() ; i++){ - indentedLine.append(" "); - } - indentedLine.append(line); - - if (pos == null){ - domRegion.println(indentedLine.toString()); - } else { - domRegion.println(indentedLine.toString(), pos, entrypointUrl); - } - } - - private void newLine(){ - domRegion.println(""); - } - - protected void writeElement(ITag tag, String cons, String varName){ - Map> attrs = tag.getAllAttributes(); - - printlnIndented("function make_" + varName + "(parent) {", tag); - stack.push(varName); - - printlnIndented("this.temp = " + cons + ";", tag); - printlnIndented("this.temp(\"" + tag.getName() + "\");", tag); - for (Map.Entry> e : attrs.entrySet()){ - String attr = e.getKey(); - String value = e.getValue().fst; - writeAttribute(tag, e.getValue().snd, attr, value, "this", varName); - } - - if (tag.getName().equalsIgnoreCase("FORM")) { - forms.push(tag); - printlnIndented(" document.forms[document.formCount++] = this;", tag); - printlnIndented(" var currentForm = this;", tag); - } if (tag.getName().equalsIgnoreCase("INPUT")) { - String prop = attrs.containsKey("name") ? attrs.get("name").fst : null; - String type = attrs.containsKey("type") ? attrs.get("type").fst : null; - - if (type != null && prop != null) { - if (type.equalsIgnoreCase("RADIO")) { - if (! sets.contains(Pair.make(forms.peek(), prop))) { - sets.add(Pair.make(forms.peek(), prop)); - printlnIndented(" currentForm." + prop + " = new Array();", tag); - printlnIndented(" currentForm." + prop + "Counter = 0;", tag); - } - printlnIndented(" currentForm." + prop + "[currentForm." + prop + "Counter++] = this;", tag); - } else { - printlnIndented(" currentForm." + prop + " = this;", tag); - } - } - } - - printlnIndented(varName + " = this;", tag); - printlnIndented("document." + varName + " = this;", tag); - printlnIndented("parent.appendChild(this);", tag); - } - - protected void writeAttribute(ITag tag, Position pos, String attr, String value, String varName, String varName2) { - writePortletAttribute(tag, attr, value, varName); - writeEventAttribute(tag, pos, attr, value, varName, varName2); - } - - protected void writeEventAttribute(ITag tag, Position pos, String attr, String value, String varName, String varName2){ - if(attr.substring(0,2).equals("on")) { - printlnIndented(varName + "." + attr + " = function " + tag.getName().toLowerCase() + "_" + attr + "(event) {" + value + "};", tag); - entrypointRegion.println(varName2 + "." + attr + "(null);", tag.getElementPosition(), entrypointUrl); - } else if (value != null) { - if (value.indexOf('\'') > 0) { - value = value.replaceAll("\\'", "\\\\'"); - } - if (value.indexOf('\n') > 0) { - value = value.replaceAll("\\n", "\\\\n"); - } - if (attr.equals(attr.toUpperCase())) { - attr = attr.toLowerCase(); - } - printlnIndented(varName + "['" + attr + "'] = '" + value + "';", tag); - } - } - - protected void writePortletAttribute(ITag tag, String attr, String value, String varName){ - if(attr.equals("portletid")) { - if(value.substring(value.length()-4).equals("vice")) { - newLine(); newLine(); - printlnIndented("function cVice() { var contextVice = " + varName + "; }\ncVice();\n", tag); - } else if(value.substring(value.length()-4).equals("root")) { - newLine(); newLine(); - printlnIndented("function cRoot() { var contextRoot = " + varName + "; }\ncRoot();\n", tag); - } - } - } - - protected void endElement(String name) { - printlnIndented("};", (Position)null); - if (stack.isEmpty()) { - printlnIndented("new make_" + name + "(document);\n\n", (Position)null); - } else { - printlnIndented("new make_" + name + "(this);\n", (Position)null); - } - } - } - - @Override - protected IGeneratorCallback createHtmlCallback(URL entrypointUrl, IUrlResolver urlResolver) { - return new HtmlCallBack(entrypointUrl, urlResolver); - } -} +/****************************************************************************** + * Copyright (c) 2002 - 2011 IBM Corporation. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *****************************************************************************/ + +package com.ibm.wala.cast.js.html; + +import java.net.MalformedURLException; +import java.net.URL; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Set; +import java.util.Stack; + +import com.ibm.wala.cast.tree.CAstSourcePositionMap.Position; +import com.ibm.wala.util.collections.HashMapFactory; +import com.ibm.wala.util.collections.Pair; + +public class DefaultSourceExtractor extends DomLessSourceExtractor{ + + protected static class HtmlCallBack extends DomLessSourceExtractor.HtmlCallback{ + + private final HashMap constructors = HashMapFactory.make(); + + private final Stack stack = new Stack(); + + private final Stack forms = new Stack(); + private final Set> sets = new HashSet>(); + + public HtmlCallBack(URL entrypointUrl, IUrlResolver urlResolver) { + super(entrypointUrl, urlResolver); + constructors.put("FORM", "DOMHTMLFormElement"); + constructors.put("TABLE", "DOMHTMLTableElement"); + } + + @Override + public void handleEndTag(ITag tag) { + super.handleEndTag(tag); + endElement(stack.pop()); + if (tag.getName().equalsIgnoreCase("FORM")) { + forms.pop(); + } + for(Entry> e : tag.getAllAttributes().entrySet()) { + String a = e.getKey(); + String v = e.getValue().fst; + if (v != null && v.startsWith("javascript:")) { + try { + entrypointRegion.println(" " + v.substring(11), e.getValue().snd, new URL(tag.getElementPosition().getURL().toString() + "#" + a)); + } catch (MalformedURLException ex) { + entrypointRegion.println(v.substring(11), e.getValue().snd, entrypointUrl); + } + } + } + } + + @Override + protected void handleDOM(ITag tag, String funcName) { + + String cons = constructors.get(tag.getName().toUpperCase()); + if(cons == null) cons = "DOMHTMLElement"; + writeElement(tag, cons, funcName); + newLine(); + } + + private void printlnIndented(String line, ITag relatedTag){ + printlnIndented(line, relatedTag==null? null: relatedTag.getElementPosition()); + } + + private void printlnIndented(String line, Position pos){ + StringBuilder indentedLine = new StringBuilder(); + for (int i = 0 ; i < stack.size() ; i++){ + indentedLine.append(" "); + } + indentedLine.append(line); + + if (pos == null){ + domRegion.println(indentedLine.toString()); + } else { + domRegion.println(indentedLine.toString(), pos, entrypointUrl); + } + } + + private void newLine(){ + domRegion.println(""); + } + + protected void writeElement(ITag tag, String cons, String varName){ + Map> attrs = tag.getAllAttributes(); + + printlnIndented("function make_" + varName + "(parent) {", tag); + stack.push(varName); + + printlnIndented("this.temp = " + cons + ";", tag); + printlnIndented("this.temp(\"" + tag.getName() + "\");", tag); + for (Map.Entry> e : attrs.entrySet()){ + String attr = e.getKey(); + String value = e.getValue().fst; + writeAttribute(tag, e.getValue().snd, attr, value, "this", varName); + } + + if (tag.getName().equalsIgnoreCase("FORM")) { + forms.push(tag); + printlnIndented(" document.forms[document.formCount++] = this;", tag); + printlnIndented(" var currentForm = this;", tag); + } if (tag.getName().equalsIgnoreCase("INPUT")) { + String prop = attrs.containsKey("name") ? attrs.get("name").fst : null; + String type = attrs.containsKey("type") ? attrs.get("type").fst : null; + + if (type != null && prop != null) { + if (type.equalsIgnoreCase("RADIO")) { + if (! sets.contains(Pair.make(forms.peek(), prop))) { + sets.add(Pair.make(forms.peek(), prop)); + printlnIndented(" currentForm." + prop + " = new Array();", tag); + printlnIndented(" currentForm." + prop + "Counter = 0;", tag); + } + printlnIndented(" currentForm." + prop + "[currentForm." + prop + "Counter++] = this;", tag); + } else { + printlnIndented(" currentForm." + prop + " = this;", tag); + } + } + } + + printlnIndented(varName + " = this;", tag); + printlnIndented("document." + varName + " = this;", tag); + printlnIndented("parent.appendChild(this);", tag); + } + + protected void writeAttribute(ITag tag, Position pos, String attr, String value, String varName, String varName2) { + writePortletAttribute(tag, attr, value, varName); + writeEventAttribute(tag, pos, attr, value, varName, varName2); + } + + protected void writeEventAttribute(ITag tag, Position pos, String attr, String value, String varName, String varName2){ + if(attr.substring(0,2).equals("on")) { + printlnIndented(varName + "." + attr + " = function " + tag.getName().toLowerCase() + "_" + attr + "(event) {" + value + "};", tag); + entrypointRegion.println(varName2 + "." + attr + "(null);", tag.getElementPosition(), entrypointUrl); + } else if (value != null) { + if (value.indexOf('\'') > 0) { + value = value.replaceAll("\\'", "\\\\'"); + } + if (value.indexOf('\n') > 0) { + value = value.replaceAll("\\n", "\\\\n"); + } + if (attr.equals(attr.toUpperCase())) { + attr = attr.toLowerCase(); + } + printlnIndented(varName + "['" + attr + "'] = '" + value + "';", tag); + } + } + + protected void writePortletAttribute(ITag tag, String attr, String value, String varName){ + if(attr.equals("portletid")) { + if(value.substring(value.length()-4).equals("vice")) { + newLine(); newLine(); + printlnIndented("function cVice() { var contextVice = " + varName + "; }\ncVice();\n", tag); + } else if(value.substring(value.length()-4).equals("root")) { + newLine(); newLine(); + printlnIndented("function cRoot() { var contextRoot = " + varName + "; }\ncRoot();\n", tag); + } + } + } + + protected void endElement(String name) { + printlnIndented("};", (Position)null); + if (stack.isEmpty()) { + printlnIndented("new make_" + name + "(document);\n\n", (Position)null); + } else { + printlnIndented("new make_" + name + "(this);\n", (Position)null); + } + } + } + + @Override + protected IGeneratorCallback createHtmlCallback(URL entrypointUrl, IUrlResolver urlResolver) { + return new HtmlCallBack(entrypointUrl, urlResolver); + } +} diff --git a/com.ibm.wala.cast.js/source/com/ibm/wala/cast/js/html/DomLessSourceExtractor.java b/com.ibm.wala.cast.js/source/com/ibm/wala/cast/js/html/DomLessSourceExtractor.java index 13690cb6f..66b73bce0 100644 --- a/com.ibm.wala.cast.js/source/com/ibm/wala/cast/js/html/DomLessSourceExtractor.java +++ b/com.ibm.wala.cast.js/source/com/ibm/wala/cast/js/html/DomLessSourceExtractor.java @@ -1,279 +1,279 @@ -/****************************************************************************** - * Copyright (c) 2002 - 2011 IBM Corporation. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * IBM Corporation - initial API and implementation - *****************************************************************************/ -package com.ibm.wala.cast.js.html; - -import java.io.BufferedReader; -import java.io.File; -import java.io.IOException; -import java.io.InputStream; -import java.io.PrintStream; -import java.net.MalformedURLException; -import java.net.URL; -import java.util.Collections; -import java.util.Map; -import java.util.Map.Entry; -import java.util.Set; -import java.util.regex.Pattern; - -import com.ibm.wala.cast.js.html.jericho.JerichoHtmlParser; -import com.ibm.wala.cast.tree.CAstSourcePositionMap.Position; -import com.ibm.wala.util.collections.Pair; - - -public class DomLessSourceExtractor extends JSSourceExtractor { - private static final Pattern LEGAL_JS_IDENTIFIER_REGEXP = Pattern.compile("[a-zA-Z$_][a-zA-Z\\d$_]*"); - protected interface IGeneratorCallback extends IHtmlCallback { - void writeToFinalRegion(SourceRegion finalRegion); - } - - protected static class HtmlCallback implements IGeneratorCallback{ - protected final URL entrypointUrl; - protected final IUrlResolver urlResolver; - - protected final SourceRegion scriptRegion; - protected final SourceRegion domRegion; - protected final SourceRegion entrypointRegion; - - private ITag currentScriptTag; - - private int nodeCounter = 0; - private int scriptNodeCounter = 0; - - public HtmlCallback(URL entrypointUrl, IUrlResolver urlResolver) { - this.entrypointUrl = entrypointUrl; - this.urlResolver = urlResolver; - this.scriptRegion = new SourceRegion(); - this.domRegion = new SourceRegion(); - this.entrypointRegion = new SourceRegion(); - } - - protected Position makePos(int lineNumber, ITag governingTag) { - return makePos(entrypointUrl, lineNumber, governingTag); - } - - protected Position makePos(final URL url, final int lineNumber, ITag governingTag) { - return governingTag.getElementPosition(); - } - - public void handleEndTag(ITag tag) { - if (tag.getName().equalsIgnoreCase("script")) { - assert currentScriptTag != null; - currentScriptTag = null; - } - } - - public void handleText(Position p, String text) { - if (currentScriptTag != null) { - if (text.startsWith(""); - text = text.substring(9, text.length()-11); - } - - URL url = entrypointUrl; - try { - url = new URL(entrypointUrl, "#" + scriptNodeCounter); - } catch (MalformedURLException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - - scriptRegion.println(text, currentScriptTag.getContentPosition(), url); - } - } - - public void handleStartTag(ITag tag) { - if (tag.getName().equalsIgnoreCase("script")) { - handleScript(tag); - assert currentScriptTag == null; - currentScriptTag = tag; - scriptNodeCounter++; - } - handleDOM(tag); - } - - /** - * Model the HTML DOM - * - * @param tag - * - the HTML tag to module - */ - protected void handleDOM(ITag tag) { - // Get the name of the modeling function either from the id attribute or a - // running counter - Pair idAttribute = tag.getAttributeByName("id"); - String funcName; - if (idAttribute != null && LEGAL_JS_IDENTIFIER_REGEXP.matcher(idAttribute.fst).matches()) { - funcName = idAttribute.fst; - } else { - funcName = "node" + (nodeCounter++); - } - handleDOM(tag, funcName); - } - - protected void handleDOM(ITag tag, String funcName) { - Map> attributeSet = tag.getAllAttributes(); - for (Entry> a : attributeSet.entrySet()) { - handleAttribute(a, funcName, tag); - } - } - - private void handleAttribute(Entry> a, String funcName, ITag tag) { - URL url = entrypointUrl; - try { - url = new URL(entrypointUrl, "#" + tag.getElementPosition().getFirstOffset()); - } catch (MalformedURLException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - Position pos = a.getValue().snd; - String attName = a.getKey(); - String attValue = a.getValue().fst; - if (attName.toLowerCase().startsWith("on") || (attValue != null && attValue.toLowerCase().startsWith("javascript:"))) { - String fName = tag.getName().toLowerCase() + "_" + attName + "_" + funcName; - String signatureLine = "function " + fName + "(event) {"; - // Defines the function - domRegion.println(signatureLine + "\n" + extructJS(attValue) + "\n}", pos, url); - // Run it - entrypointRegion.println("\t" + fName + "(null);", pos, url); - } - } - - private String extructJS(String attValue) { - if (attValue == null){ - return ""; - } - String content; - if (attValue.toLowerCase().equals("javascript:")) { - content = attValue.substring("javascript:".length()); - } else { - content = attValue; - } - - return content; - } - - protected void handleScript(ITag tag) { - - Pair value = tag.getAttributeByName("src"); - - try { - if (value != null) { - // script is out-of-line - getScriptFromUrl(value.fst, tag); - } - - } catch (IOException e) { - System.err.println("Error reading script file: " + e.getMessage()); - } - } - - private void getScriptFromUrl(String urlAsString, ITag scriptTag) throws IOException, MalformedURLException { - URL absoluteUrl = UrlManipulator.relativeToAbsoluteUrl(urlAsString, this.entrypointUrl); - URL scriptSrc = urlResolver.resolve(absoluteUrl); - if (scriptSrc == null) { //Error resolving URL - return; - } - - InputStream scriptInputStream = scriptSrc.openConnection().getInputStream(); - try{ - String line; - BufferedReader scriptReader = new BufferedReader(new UnicodeReader(scriptInputStream, "UTF8")); - StringBuffer x = new StringBuffer(); - while ((line = scriptReader.readLine()) != null) { - x.append(line).append("\n"); - } - - scriptRegion.println(x.toString(), scriptTag.getElementPosition(), scriptSrc); - - } finally { - scriptInputStream.close(); - } - } - - protected String getScriptName(URL url) throws MalformedURLException { - String file = url.getFile(); - int lastIdxOfSlash = file.lastIndexOf('/'); - file = (lastIdxOfSlash == (-1)) ? file : file.substring(lastIdxOfSlash + 1); - return file; - } - - public void writeToFinalRegion(SourceRegion finalRegion) { - // wrapping the embedded scripts with a fake method of the window. Required for making this == window. - finalRegion.println("window.__MAIN__ = function __WINDOW_MAIN__(){"); - - finalRegion.write(scriptRegion); - - finalRegion.write(domRegion); - - finalRegion.println(" document.URL = new String(\"" + entrypointUrl + "\");"); - - finalRegion.println("while (true){ "); - finalRegion.write(entrypointRegion); - finalRegion.println("} // while (true)"); - - finalRegion.println("} // end of window.__MAIN__"); - finalRegion.println("window.__MAIN__();"); - } - } - - public Set extractSources(URL entrypointUrl, IHtmlParser htmlParser, IUrlResolver urlResolver) - throws IOException { - - InputStream inputStreamReader = WebUtil.getStream(entrypointUrl); - IGeneratorCallback htmlCallback = createHtmlCallback(entrypointUrl, urlResolver); - htmlParser.parse(entrypointUrl, inputStreamReader, htmlCallback, entrypointUrl.getFile()); - - SourceRegion finalRegion = new SourceRegion(); - htmlCallback.writeToFinalRegion(finalRegion); - - // writing the final region into one SourceFileModule. - File outputFile = createOutputFile(entrypointUrl, DELETE_UPON_EXIT, USE_TEMP_NAME); - FileMapping fileMapping = finalRegion.writeToFile(new PrintStream(outputFile)); - MappedSourceModule singleFileModule = new MappedSourceFileModule(outputFile, outputFile.getName(), fileMapping); - return Collections.singleton(singleFileModule); - } - - protected IGeneratorCallback createHtmlCallback(URL entrypointUrl, IUrlResolver urlResolver) { - return new HtmlCallback(entrypointUrl, urlResolver); - } - - private File createOutputFile(URL url, boolean delete, boolean useTempName) throws IOException { - File outputFile; - if (useTempName) { - outputFile = File.createTempFile(new File(url.getFile()).getName(), ".js"); - } else { - outputFile = new File(new File(url.getFile()).getName()); - } - if (outputFile.exists()){ - outputFile.delete(); - } - if(delete){ - outputFile.deleteOnExit(); - } - return outputFile; - } - - - public static void main(String[] args) throws IOException { -// DomLessSourceExtractor domLessScopeGenerator = new DomLessSourceExtractor(); - JSSourceExtractor domLessScopeGenerator = new DefaultSourceExtractor(); - JSSourceExtractor.DELETE_UPON_EXIT = false; - URL entrypointUrl = new URL(args[0]); - IHtmlParser htmlParser = new JerichoHtmlParser(); - IUrlResolver urlResolver = new IdentityUrlResolver(); - Set res = domLessScopeGenerator.extractSources(entrypointUrl , htmlParser , urlResolver); - MappedSourceModule entry = res.iterator().next(); - System.out.println(entry); - entry.getMapping().dump(System.out); - - } -} - +/****************************************************************************** + * Copyright (c) 2002 - 2011 IBM Corporation. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *****************************************************************************/ +package com.ibm.wala.cast.js.html; + +import java.io.BufferedReader; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.io.PrintStream; +import java.net.MalformedURLException; +import java.net.URL; +import java.util.Collections; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Set; +import java.util.regex.Pattern; + +import com.ibm.wala.cast.js.html.jericho.JerichoHtmlParser; +import com.ibm.wala.cast.tree.CAstSourcePositionMap.Position; +import com.ibm.wala.util.collections.Pair; + + +public class DomLessSourceExtractor extends JSSourceExtractor { + private static final Pattern LEGAL_JS_IDENTIFIER_REGEXP = Pattern.compile("[a-zA-Z$_][a-zA-Z\\d$_]*"); + protected interface IGeneratorCallback extends IHtmlCallback { + void writeToFinalRegion(SourceRegion finalRegion); + } + + protected static class HtmlCallback implements IGeneratorCallback{ + protected final URL entrypointUrl; + protected final IUrlResolver urlResolver; + + protected final SourceRegion scriptRegion; + protected final SourceRegion domRegion; + protected final SourceRegion entrypointRegion; + + private ITag currentScriptTag; + + private int nodeCounter = 0; + private int scriptNodeCounter = 0; + + public HtmlCallback(URL entrypointUrl, IUrlResolver urlResolver) { + this.entrypointUrl = entrypointUrl; + this.urlResolver = urlResolver; + this.scriptRegion = new SourceRegion(); + this.domRegion = new SourceRegion(); + this.entrypointRegion = new SourceRegion(); + } + + protected Position makePos(int lineNumber, ITag governingTag) { + return makePos(entrypointUrl, lineNumber, governingTag); + } + + protected Position makePos(final URL url, final int lineNumber, ITag governingTag) { + return governingTag.getElementPosition(); + } + + public void handleEndTag(ITag tag) { + if (tag.getName().equalsIgnoreCase("script")) { + assert currentScriptTag != null; + currentScriptTag = null; + } + } + + public void handleText(Position p, String text) { + if (currentScriptTag != null) { + if (text.startsWith(""); + text = text.substring(9, text.length()-11); + } + + URL url = entrypointUrl; + try { + url = new URL(entrypointUrl, "#" + scriptNodeCounter); + } catch (MalformedURLException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + + scriptRegion.println(text, currentScriptTag.getContentPosition(), url); + } + } + + public void handleStartTag(ITag tag) { + if (tag.getName().equalsIgnoreCase("script")) { + handleScript(tag); + assert currentScriptTag == null; + currentScriptTag = tag; + scriptNodeCounter++; + } + handleDOM(tag); + } + + /** + * Model the HTML DOM + * + * @param tag + * - the HTML tag to module + */ + protected void handleDOM(ITag tag) { + // Get the name of the modeling function either from the id attribute or a + // running counter + Pair idAttribute = tag.getAttributeByName("id"); + String funcName; + if (idAttribute != null && LEGAL_JS_IDENTIFIER_REGEXP.matcher(idAttribute.fst).matches()) { + funcName = idAttribute.fst; + } else { + funcName = "node" + (nodeCounter++); + } + handleDOM(tag, funcName); + } + + protected void handleDOM(ITag tag, String funcName) { + Map> attributeSet = tag.getAllAttributes(); + for (Entry> a : attributeSet.entrySet()) { + handleAttribute(a, funcName, tag); + } + } + + private void handleAttribute(Entry> a, String funcName, ITag tag) { + URL url = entrypointUrl; + try { + url = new URL(entrypointUrl, "#" + tag.getElementPosition().getFirstOffset()); + } catch (MalformedURLException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + Position pos = a.getValue().snd; + String attName = a.getKey(); + String attValue = a.getValue().fst; + if (attName.toLowerCase().startsWith("on") || (attValue != null && attValue.toLowerCase().startsWith("javascript:"))) { + String fName = tag.getName().toLowerCase() + "_" + attName + "_" + funcName; + String signatureLine = "function " + fName + "(event) {"; + // Defines the function + domRegion.println(signatureLine + "\n" + extructJS(attValue) + "\n}", pos, url); + // Run it + entrypointRegion.println("\t" + fName + "(null);", pos, url); + } + } + + private String extructJS(String attValue) { + if (attValue == null){ + return ""; + } + String content; + if (attValue.toLowerCase().equals("javascript:")) { + content = attValue.substring("javascript:".length()); + } else { + content = attValue; + } + + return content; + } + + protected void handleScript(ITag tag) { + + Pair value = tag.getAttributeByName("src"); + + try { + if (value != null) { + // script is out-of-line + getScriptFromUrl(value.fst, tag); + } + + } catch (IOException e) { + System.err.println("Error reading script file: " + e.getMessage()); + } + } + + private void getScriptFromUrl(String urlAsString, ITag scriptTag) throws IOException, MalformedURLException { + URL absoluteUrl = UrlManipulator.relativeToAbsoluteUrl(urlAsString, this.entrypointUrl); + URL scriptSrc = urlResolver.resolve(absoluteUrl); + if (scriptSrc == null) { //Error resolving URL + return; + } + + InputStream scriptInputStream = scriptSrc.openConnection().getInputStream(); + try{ + String line; + BufferedReader scriptReader = new BufferedReader(new UnicodeReader(scriptInputStream, "UTF8")); + StringBuffer x = new StringBuffer(); + while ((line = scriptReader.readLine()) != null) { + x.append(line).append("\n"); + } + + scriptRegion.println(x.toString(), scriptTag.getElementPosition(), scriptSrc); + + } finally { + scriptInputStream.close(); + } + } + + protected String getScriptName(URL url) throws MalformedURLException { + String file = url.getFile(); + int lastIdxOfSlash = file.lastIndexOf('/'); + file = (lastIdxOfSlash == (-1)) ? file : file.substring(lastIdxOfSlash + 1); + return file; + } + + public void writeToFinalRegion(SourceRegion finalRegion) { + // wrapping the embedded scripts with a fake method of the window. Required for making this == window. + finalRegion.println("window.__MAIN__ = function __WINDOW_MAIN__(){"); + + finalRegion.write(scriptRegion); + + finalRegion.write(domRegion); + + finalRegion.println(" document.URL = new String(\"" + entrypointUrl + "\");"); + + finalRegion.println("while (true){ "); + finalRegion.write(entrypointRegion); + finalRegion.println("} // while (true)"); + + finalRegion.println("} // end of window.__MAIN__"); + finalRegion.println("window.__MAIN__();"); + } + } + + public Set extractSources(URL entrypointUrl, IHtmlParser htmlParser, IUrlResolver urlResolver) + throws IOException { + + InputStream inputStreamReader = WebUtil.getStream(entrypointUrl); + IGeneratorCallback htmlCallback = createHtmlCallback(entrypointUrl, urlResolver); + htmlParser.parse(entrypointUrl, inputStreamReader, htmlCallback, entrypointUrl.getFile()); + + SourceRegion finalRegion = new SourceRegion(); + htmlCallback.writeToFinalRegion(finalRegion); + + // writing the final region into one SourceFileModule. + File outputFile = createOutputFile(entrypointUrl, DELETE_UPON_EXIT, USE_TEMP_NAME); + FileMapping fileMapping = finalRegion.writeToFile(new PrintStream(outputFile)); + MappedSourceModule singleFileModule = new MappedSourceFileModule(outputFile, outputFile.getName(), fileMapping); + return Collections.singleton(singleFileModule); + } + + protected IGeneratorCallback createHtmlCallback(URL entrypointUrl, IUrlResolver urlResolver) { + return new HtmlCallback(entrypointUrl, urlResolver); + } + + private File createOutputFile(URL url, boolean delete, boolean useTempName) throws IOException { + File outputFile; + if (useTempName) { + outputFile = File.createTempFile(new File(url.getFile()).getName(), ".js"); + } else { + outputFile = new File(new File(url.getFile()).getName()); + } + if (outputFile.exists()){ + outputFile.delete(); + } + if(delete){ + outputFile.deleteOnExit(); + } + return outputFile; + } + + + public static void main(String[] args) throws IOException { +// DomLessSourceExtractor domLessScopeGenerator = new DomLessSourceExtractor(); + JSSourceExtractor domLessScopeGenerator = new DefaultSourceExtractor(); + JSSourceExtractor.DELETE_UPON_EXIT = false; + URL entrypointUrl = new URL(args[0]); + IHtmlParser htmlParser = new JerichoHtmlParser(); + IUrlResolver urlResolver = new IdentityUrlResolver(); + Set res = domLessScopeGenerator.extractSources(entrypointUrl , htmlParser , urlResolver); + MappedSourceModule entry = res.iterator().next(); + System.out.println(entry); + entry.getMapping().dump(System.out); + + } +} + diff --git a/com.ibm.wala.cast.js/source/com/ibm/wala/cast/js/html/IHtmlCallback.java b/com.ibm.wala.cast.js/source/com/ibm/wala/cast/js/html/IHtmlCallback.java index 44fb7f334..923e21623 100644 --- a/com.ibm.wala.cast.js/source/com/ibm/wala/cast/js/html/IHtmlCallback.java +++ b/com.ibm.wala.cast.js/source/com/ibm/wala/cast/js/html/IHtmlCallback.java @@ -1,31 +1,31 @@ -/****************************************************************************** - * Copyright (c) 2002 - 2011 IBM Corporation. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * IBM Corporation - initial API and implementation - *****************************************************************************/ -package com.ibm.wala.cast.js.html; - -import com.ibm.wala.cast.tree.CAstSourcePositionMap.Position; - - - -/** - * Callback which is implemented by users of the IHtmlParser. The parser traverses the dom-nodes in an in-order. - * @author danielk - * @author yinnonh - * - */ -public interface IHtmlCallback { - - void handleStartTag(ITag tag); - - void handleText(Position pos, String text); - - void handleEndTag(ITag tag); - -} +/****************************************************************************** + * Copyright (c) 2002 - 2011 IBM Corporation. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *****************************************************************************/ +package com.ibm.wala.cast.js.html; + +import com.ibm.wala.cast.tree.CAstSourcePositionMap.Position; + + + +/** + * Callback which is implemented by users of the IHtmlParser. The parser traverses the dom-nodes in an in-order. + * @author danielk + * @author yinnonh + * + */ +public interface IHtmlCallback { + + void handleStartTag(ITag tag); + + void handleText(Position pos, String text); + + void handleEndTag(ITag tag); + +} diff --git a/com.ibm.wala.cast.js/source/com/ibm/wala/cast/js/html/IHtmlParser.java b/com.ibm.wala.cast.js/source/com/ibm/wala/cast/js/html/IHtmlParser.java index 7afce31ac..8bf32cfd7 100644 --- a/com.ibm.wala.cast.js/source/com/ibm/wala/cast/js/html/IHtmlParser.java +++ b/com.ibm.wala.cast.js/source/com/ibm/wala/cast/js/html/IHtmlParser.java @@ -1,31 +1,31 @@ -/****************************************************************************** - * Copyright (c) 2002 - 2011 IBM Corporation. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * IBM Corporation - initial API and implementation - *****************************************************************************/ -package com.ibm.wala.cast.js.html; - -import java.io.InputStream; -import java.net.URL; - -/** - * @author danielk - * @author yinnonh - * Parses an HTML file using call backs - */ -public interface IHtmlParser { - - /** - * Parses a given HTML, calling the given callback. - * @param reader - * @param callback - * @param fileName - */ - public void parse(URL url, InputStream reader, IHtmlCallback callback, String fileName); - -} +/****************************************************************************** + * Copyright (c) 2002 - 2011 IBM Corporation. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *****************************************************************************/ +package com.ibm.wala.cast.js.html; + +import java.io.InputStream; +import java.net.URL; + +/** + * @author danielk + * @author yinnonh + * Parses an HTML file using call backs + */ +public interface IHtmlParser { + + /** + * Parses a given HTML, calling the given callback. + * @param reader + * @param callback + * @param fileName + */ + public void parse(URL url, InputStream reader, IHtmlCallback callback, String fileName); + +} diff --git a/com.ibm.wala.cast.js/source/com/ibm/wala/cast/js/html/ITag.java b/com.ibm.wala.cast.js/source/com/ibm/wala/cast/js/html/ITag.java index a07b6e395..de05576f8 100644 --- a/com.ibm.wala.cast.js/source/com/ibm/wala/cast/js/html/ITag.java +++ b/com.ibm.wala.cast.js/source/com/ibm/wala/cast/js/html/ITag.java @@ -1,45 +1,45 @@ -package com.ibm.wala.cast.js.html; - -/****************************************************************************** - * Copyright (c) 2002 - 2011 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 - *****************************************************************************/ -import java.util.Map; - -import com.ibm.wala.cast.tree.CAstSourcePositionMap.Position; -import com.ibm.wala.util.collections.Pair; - -/** - * @author danielk - * Data structure representing an HTML tag, with its attributes and content. Used by the HTML parser when calling the callback. - */ -public interface ITag { - - /** - * @return tag's name (e.g., "HEAD" / "HTML" / "FORM") - */ - public String getName(); - - /** - * Retrieves a specific attribute - * @param name - * @return null if there is no such attribute - */ - public Pair getAttributeByName(String name); - - public Map> getAllAttributes(); - - /** - * Returns the starting line number of the tag. - * @return null if no known - */ - public Position getElementPosition(); - - public Position getContentPosition(); -} +package com.ibm.wala.cast.js.html; + +/****************************************************************************** + * Copyright (c) 2002 - 2011 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 + *****************************************************************************/ +import java.util.Map; + +import com.ibm.wala.cast.tree.CAstSourcePositionMap.Position; +import com.ibm.wala.util.collections.Pair; + +/** + * @author danielk + * Data structure representing an HTML tag, with its attributes and content. Used by the HTML parser when calling the callback. + */ +public interface ITag { + + /** + * @return tag's name (e.g., "HEAD" / "HTML" / "FORM") + */ + public String getName(); + + /** + * Retrieves a specific attribute + * @param name + * @return null if there is no such attribute + */ + public Pair getAttributeByName(String name); + + public Map> getAllAttributes(); + + /** + * Returns the starting line number of the tag. + * @return null if no known + */ + public Position getElementPosition(); + + public Position getContentPosition(); +} diff --git a/com.ibm.wala.cast.js/source/com/ibm/wala/cast/js/html/IUrlResolver.java b/com.ibm.wala.cast.js/source/com/ibm/wala/cast/js/html/IUrlResolver.java index b6635d7e2..6905160c3 100644 --- a/com.ibm.wala.cast.js/source/com/ibm/wala/cast/js/html/IUrlResolver.java +++ b/com.ibm.wala.cast.js/source/com/ibm/wala/cast/js/html/IUrlResolver.java @@ -1,36 +1,36 @@ -/****************************************************************************** - * Copyright (c) 2002 - 2011 IBM Corporation. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * IBM Corporation - initial API and implementation - *****************************************************************************/ -package com.ibm.wala.cast.js.html; - -import java.net.URL; - -/** - * Used for handling resources that were copied from the web to local files (and still contain references to the web) - * @author yinnonh - * @author danielk - * - */ -public interface IUrlResolver { - /** - * From Internet to local - * @param input - * @return - */ - public URL resolve(URL input); - - /** - * From local to Internet - * @param input - * @return - */ - public URL deResolve(URL input); - -} +/****************************************************************************** + * Copyright (c) 2002 - 2011 IBM Corporation. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *****************************************************************************/ +package com.ibm.wala.cast.js.html; + +import java.net.URL; + +/** + * Used for handling resources that were copied from the web to local files (and still contain references to the web) + * @author yinnonh + * @author danielk + * + */ +public interface IUrlResolver { + /** + * From Internet to local + * @param input + * @return + */ + public URL resolve(URL input); + + /** + * From local to Internet + * @param input + * @return + */ + public URL deResolve(URL input); + +} diff --git a/com.ibm.wala.cast.js/source/com/ibm/wala/cast/js/html/IdentityUrlResolver.java b/com.ibm.wala.cast.js/source/com/ibm/wala/cast/js/html/IdentityUrlResolver.java index b95921755..3d36c3f3e 100644 --- a/com.ibm.wala.cast.js/source/com/ibm/wala/cast/js/html/IdentityUrlResolver.java +++ b/com.ibm.wala.cast.js/source/com/ibm/wala/cast/js/html/IdentityUrlResolver.java @@ -1,25 +1,25 @@ -/****************************************************************************** - * Copyright (c) 2002 - 2011 IBM Corporation. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * IBM Corporation - initial API and implementation - *****************************************************************************/ -package com.ibm.wala.cast.js.html; - -import java.net.URL; - -public class IdentityUrlResolver implements IUrlResolver{ - - public URL resolve(URL input) { - return input; - } - - public URL deResolve(URL input) { - return input; - } - -} +/****************************************************************************** + * Copyright (c) 2002 - 2011 IBM Corporation. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *****************************************************************************/ +package com.ibm.wala.cast.js.html; + +import java.net.URL; + +public class IdentityUrlResolver implements IUrlResolver{ + + public URL resolve(URL input) { + return input; + } + + public URL deResolve(URL input) { + return input; + } + +} diff --git a/com.ibm.wala.cast.js/source/com/ibm/wala/cast/js/html/JSSourceExtractor.java b/com.ibm.wala.cast.js/source/com/ibm/wala/cast/js/html/JSSourceExtractor.java index 45f3fc32e..c93ef1730 100644 --- a/com.ibm.wala.cast.js/source/com/ibm/wala/cast/js/html/JSSourceExtractor.java +++ b/com.ibm.wala.cast.js/source/com/ibm/wala/cast/js/html/JSSourceExtractor.java @@ -1,32 +1,32 @@ -/****************************************************************************** - * Copyright (c) 2002 - 2011 IBM Corporation. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * IBM Corporation - initial API and implementation - *****************************************************************************/ -package com.ibm.wala.cast.js.html; - -import java.io.IOException; -import java.net.URL; -import java.util.Set; - -/** - * Extracts scripts from a given URL of an HTML. Retrieves also attached js files. - * Provides file and line mapping for each extracted SourceFileModule back to the original file and line number. - * - * @author yinnonh - * @author danielk - */ -public abstract class JSSourceExtractor { - - public static boolean DELETE_UPON_EXIT = false; - - public static boolean USE_TEMP_NAME = false; - - public abstract Set extractSources(URL entrypointUrl, IHtmlParser htmlParser, IUrlResolver urlResolver) throws IOException; - -} +/****************************************************************************** + * Copyright (c) 2002 - 2011 IBM Corporation. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *****************************************************************************/ +package com.ibm.wala.cast.js.html; + +import java.io.IOException; +import java.net.URL; +import java.util.Set; + +/** + * Extracts scripts from a given URL of an HTML. Retrieves also attached js files. + * Provides file and line mapping for each extracted SourceFileModule back to the original file and line number. + * + * @author yinnonh + * @author danielk + */ +public abstract class JSSourceExtractor { + + public static boolean DELETE_UPON_EXIT = false; + + public static boolean USE_TEMP_NAME = false; + + public abstract Set extractSources(URL entrypointUrl, IHtmlParser htmlParser, IUrlResolver urlResolver) throws IOException; + +} diff --git a/com.ibm.wala.cast.js/source/com/ibm/wala/cast/js/html/SourceRegion.java b/com.ibm.wala.cast.js/source/com/ibm/wala/cast/js/html/SourceRegion.java index 995ee9ca0..6e8be4f8c 100644 --- a/com.ibm.wala.cast.js/source/com/ibm/wala/cast/js/html/SourceRegion.java +++ b/com.ibm.wala.cast.js/source/com/ibm/wala/cast/js/html/SourceRegion.java @@ -1,100 +1,100 @@ -/****************************************************************************** - * Copyright (c) 2002 - 2011 IBM Corporation. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * IBM Corporation - initial API and implementation - *****************************************************************************/ -package com.ibm.wala.cast.js.html; - -import java.io.PrintStream; -import java.net.URL; - -import com.ibm.wala.cast.tree.CAstSourcePositionMap.Position; - -public class SourceRegion { - - private final StringBuilder source = new StringBuilder(); - private FileMapping fileMapping; - private int currentLine = 1; - - public SourceRegion() { - } - - public void print(String text, Position originalPos, URL url){ - int startOffset = source.length(); - source.append(text); - int endOffset = source.length(); - - int numberOfLineDrops = getNumberOfLineDrops(text); - - if (originalPos != null) { - RangeFileMapping map = new RangeFileMapping(startOffset, endOffset, currentLine, currentLine+numberOfLineDrops, originalPos, url); - if (fileMapping == null) { - fileMapping = map; - } else { - fileMapping = new CompositeFileMapping(map, fileMapping); - } - } - - currentLine += numberOfLineDrops; - } - - public void println(String text, Position originalPos, URL url){ - print(text + "\n", originalPos, url); - } - - public void print(String text){ - print(text, null, null); - } - - public void println(String text){ - print(text + "\n"); - } - - public FileMapping writeToFile(PrintStream ps){ - ps.print(source.toString()); - return fileMapping; - } - - public void write(SourceRegion otherRegion){ - int rangeStart = source.length(); - String text = otherRegion.source.toString(); - source.append(text); - int rangeEnd = source.length(); - - int numberOfLineDrops = getNumberOfLineDrops(text); - - if (otherRegion.fileMapping != null) { - FileMapping map = new NestedRangeMapping(rangeStart, rangeEnd, currentLine, currentLine+numberOfLineDrops, otherRegion.fileMapping); - if (fileMapping == null) { - fileMapping = map; - } else { - fileMapping = new CompositeFileMapping(map, fileMapping); - } - } - - currentLine += numberOfLineDrops; - } - - public void dump(PrintStream ps){ - ps.println(source.toString()); - } - - private static int getNumberOfLineDrops(String text) { - int ret = 0; - int i = text.indexOf('\n'); - while (i != -1){ - ret++; - if (i < text.length()-1){ - i = text.indexOf('\n', i + 1); - } else { - break; // CR was the the last character. - } - } - return ret; - } -} +/****************************************************************************** + * Copyright (c) 2002 - 2011 IBM Corporation. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *****************************************************************************/ +package com.ibm.wala.cast.js.html; + +import java.io.PrintStream; +import java.net.URL; + +import com.ibm.wala.cast.tree.CAstSourcePositionMap.Position; + +public class SourceRegion { + + private final StringBuilder source = new StringBuilder(); + private FileMapping fileMapping; + private int currentLine = 1; + + public SourceRegion() { + } + + public void print(String text, Position originalPos, URL url){ + int startOffset = source.length(); + source.append(text); + int endOffset = source.length(); + + int numberOfLineDrops = getNumberOfLineDrops(text); + + if (originalPos != null) { + RangeFileMapping map = new RangeFileMapping(startOffset, endOffset, currentLine, currentLine+numberOfLineDrops, originalPos, url); + if (fileMapping == null) { + fileMapping = map; + } else { + fileMapping = new CompositeFileMapping(map, fileMapping); + } + } + + currentLine += numberOfLineDrops; + } + + public void println(String text, Position originalPos, URL url){ + print(text + "\n", originalPos, url); + } + + public void print(String text){ + print(text, null, null); + } + + public void println(String text){ + print(text + "\n"); + } + + public FileMapping writeToFile(PrintStream ps){ + ps.print(source.toString()); + return fileMapping; + } + + public void write(SourceRegion otherRegion){ + int rangeStart = source.length(); + String text = otherRegion.source.toString(); + source.append(text); + int rangeEnd = source.length(); + + int numberOfLineDrops = getNumberOfLineDrops(text); + + if (otherRegion.fileMapping != null) { + FileMapping map = new NestedRangeMapping(rangeStart, rangeEnd, currentLine, currentLine+numberOfLineDrops, otherRegion.fileMapping); + if (fileMapping == null) { + fileMapping = map; + } else { + fileMapping = new CompositeFileMapping(map, fileMapping); + } + } + + currentLine += numberOfLineDrops; + } + + public void dump(PrintStream ps){ + ps.println(source.toString()); + } + + private static int getNumberOfLineDrops(String text) { + int ret = 0; + int i = text.indexOf('\n'); + while (i != -1){ + ret++; + if (i < text.length()-1){ + i = text.indexOf('\n', i + 1); + } else { + break; // CR was the the last character. + } + } + return ret; + } +} diff --git a/com.ibm.wala.cast.js/source/com/ibm/wala/cast/js/html/UnicodeReader.java b/com.ibm.wala.cast.js/source/com/ibm/wala/cast/js/html/UnicodeReader.java index a13aa4d72..b15ad292f 100644 --- a/com.ibm.wala.cast.js/source/com/ibm/wala/cast/js/html/UnicodeReader.java +++ b/com.ibm.wala.cast.js/source/com/ibm/wala/cast/js/html/UnicodeReader.java @@ -1,122 +1,122 @@ -/****************************************************************************** - * Copyright (c) 2002 - 2011 IBM Corporation. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * IBM Corporation - initial API and implementation - *****************************************************************************/ -package com.ibm.wala.cast.js.html; - -/** - http://www.unicode.org/unicode/faq/utf_bom.html - BOMs: - 00 00 FE FF = UTF-32, big-endian - FF FE 00 00 = UTF-32, little-endian - FE FF = UTF-16, big-endian - FF FE = UTF-16, little-endian - EF BB BF = UTF-8 - - Win2k Notepad: - Unicode format = UTF-16LE - ***/ - -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.io.PushbackInputStream; -import java.io.Reader; - -/** - * Generic unicode textreader, which will use BOM mark to identify the encoding to be used. - */ -public class UnicodeReader extends Reader { - PushbackInputStream internalIn; - - InputStreamReader internalIn2 = null; - - String defaultEnc; - - private static final int BOM_SIZE = 6; - - /* - * Default encoding is used only if BOM is not found. If defaultEncoding is NULL then systemdefault is used. - */ - public UnicodeReader(InputStream in, String defaultEnc) { - internalIn = new PushbackInputStream(in, BOM_SIZE); - this.defaultEnc = defaultEnc; - } - - public String getDefaultEncoding() { - return defaultEnc; - } - - public String getEncoding() { - if (internalIn2 == null) - return null; - return internalIn2.getEncoding(); - } - - /** - * Read-ahead four bytes and check for BOM marks. Extra bytes are unread back to the stream, only BOM bytes are skipped. - */ - protected void init() throws IOException { - if (internalIn2 != null) - return; - - String encoding; - byte bom[] = new byte[BOM_SIZE]; - int n, unread; - n = internalIn.read(bom, 0, bom.length); - - if ((bom[0] == (byte) 0xEF) && (bom[1] == (byte) 0xBB) && (bom[2] == (byte) 0xBF) && (bom[3] == (byte) 0xEF) && (bom[4] == (byte) 0xBB) && (bom[5] == (byte) 0xBF)) { - encoding = "UTF-8"; - unread = n - 6; - } else if ((bom[0] == (byte) 0xEF) && (bom[1] == (byte) 0xBB) && (bom[2] == (byte) 0xBF)) { - encoding = "UTF-8"; - unread = n - 3; - } else if ((bom[0] == (byte) 0xFE) && (bom[1] == (byte) 0xFF)) { - encoding = "UTF-16BE"; - unread = n - 2; - } else if ((bom[0] == (byte) 0xFF) && (bom[1] == (byte) 0xFE)) { - encoding = "UTF-16LE"; - unread = n - 2; - } else if ((bom[0] == (byte) 0x00) && (bom[1] == (byte) 0x00) && (bom[2] == (byte) 0xFE) && (bom[3] == (byte) 0xFF)) { - encoding = "UTF-32BE"; - unread = n - 4; - } else if ((bom[0] == (byte) 0xFF) && (bom[1] == (byte) 0xFE) && (bom[2] == (byte) 0x00) && (bom[3] == (byte) 0x00)) { - encoding = "UTF-32LE"; - unread = n - 4; - } else { - // Unicode BOM mark not found, unread all bytes - encoding = defaultEnc; - unread = n; - } - // System.out.println("read=" + n + ", unread=" + unread); - - if (unread > 0) - internalIn.unread(bom, (n - unread), unread); - else if (unread < -1) - internalIn.unread(bom, 0, 0); - - // Use given encoding - if (encoding == null) { - internalIn2 = new InputStreamReader(internalIn); - } else { - internalIn2 = new InputStreamReader(internalIn, encoding); - } - } - - public void close() throws IOException { - init(); - internalIn2.close(); - } - - public int read(char[] cbuf, int off, int len) throws IOException { - init(); - return internalIn2.read(cbuf, off, len); - } - -} +/****************************************************************************** + * Copyright (c) 2002 - 2011 IBM Corporation. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *****************************************************************************/ +package com.ibm.wala.cast.js.html; + +/** + http://www.unicode.org/unicode/faq/utf_bom.html + BOMs: + 00 00 FE FF = UTF-32, big-endian + FF FE 00 00 = UTF-32, little-endian + FE FF = UTF-16, big-endian + FF FE = UTF-16, little-endian + EF BB BF = UTF-8 + + Win2k Notepad: + Unicode format = UTF-16LE + ***/ + +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.PushbackInputStream; +import java.io.Reader; + +/** + * Generic unicode textreader, which will use BOM mark to identify the encoding to be used. + */ +public class UnicodeReader extends Reader { + PushbackInputStream internalIn; + + InputStreamReader internalIn2 = null; + + String defaultEnc; + + private static final int BOM_SIZE = 6; + + /* + * Default encoding is used only if BOM is not found. If defaultEncoding is NULL then systemdefault is used. + */ + public UnicodeReader(InputStream in, String defaultEnc) { + internalIn = new PushbackInputStream(in, BOM_SIZE); + this.defaultEnc = defaultEnc; + } + + public String getDefaultEncoding() { + return defaultEnc; + } + + public String getEncoding() { + if (internalIn2 == null) + return null; + return internalIn2.getEncoding(); + } + + /** + * Read-ahead four bytes and check for BOM marks. Extra bytes are unread back to the stream, only BOM bytes are skipped. + */ + protected void init() throws IOException { + if (internalIn2 != null) + return; + + String encoding; + byte bom[] = new byte[BOM_SIZE]; + int n, unread; + n = internalIn.read(bom, 0, bom.length); + + if ((bom[0] == (byte) 0xEF) && (bom[1] == (byte) 0xBB) && (bom[2] == (byte) 0xBF) && (bom[3] == (byte) 0xEF) && (bom[4] == (byte) 0xBB) && (bom[5] == (byte) 0xBF)) { + encoding = "UTF-8"; + unread = n - 6; + } else if ((bom[0] == (byte) 0xEF) && (bom[1] == (byte) 0xBB) && (bom[2] == (byte) 0xBF)) { + encoding = "UTF-8"; + unread = n - 3; + } else if ((bom[0] == (byte) 0xFE) && (bom[1] == (byte) 0xFF)) { + encoding = "UTF-16BE"; + unread = n - 2; + } else if ((bom[0] == (byte) 0xFF) && (bom[1] == (byte) 0xFE)) { + encoding = "UTF-16LE"; + unread = n - 2; + } else if ((bom[0] == (byte) 0x00) && (bom[1] == (byte) 0x00) && (bom[2] == (byte) 0xFE) && (bom[3] == (byte) 0xFF)) { + encoding = "UTF-32BE"; + unread = n - 4; + } else if ((bom[0] == (byte) 0xFF) && (bom[1] == (byte) 0xFE) && (bom[2] == (byte) 0x00) && (bom[3] == (byte) 0x00)) { + encoding = "UTF-32LE"; + unread = n - 4; + } else { + // Unicode BOM mark not found, unread all bytes + encoding = defaultEnc; + unread = n; + } + // System.out.println("read=" + n + ", unread=" + unread); + + if (unread > 0) + internalIn.unread(bom, (n - unread), unread); + else if (unread < -1) + internalIn.unread(bom, 0, 0); + + // Use given encoding + if (encoding == null) { + internalIn2 = new InputStreamReader(internalIn); + } else { + internalIn2 = new InputStreamReader(internalIn, encoding); + } + } + + public void close() throws IOException { + init(); + internalIn2.close(); + } + + public int read(char[] cbuf, int off, int len) throws IOException { + init(); + return internalIn2.read(cbuf, off, len); + } + +} diff --git a/com.ibm.wala.cast.js/source/com/ibm/wala/cast/js/html/UrlManipulator.java b/com.ibm.wala.cast.js/source/com/ibm/wala/cast/js/html/UrlManipulator.java index f2fb02544..ac10c3bb2 100644 --- a/com.ibm.wala.cast.js/source/com/ibm/wala/cast/js/html/UrlManipulator.java +++ b/com.ibm.wala.cast.js/source/com/ibm/wala/cast/js/html/UrlManipulator.java @@ -1,78 +1,78 @@ -/****************************************************************************** - * Copyright (c) 2002 - 2011 IBM Corporation. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * IBM Corporation - initial API and implementation - *****************************************************************************/ -package com.ibm.wala.cast.js.html; - -import java.net.MalformedURLException; -import java.net.URL; - -public class UrlManipulator { - - - /** - * @param urlFound the link as appear - * @param context the URL in which the link appeared - * @return - * @throws MalformedURLException - */ - public static URL relativeToAbsoluteUrl(String urlFound, URL context) throws MalformedURLException { - urlFound = urlFound.replace("\\", "/").toLowerCase(); - - URL absoluteUrl; - if (!isAbsoluteUrl(urlFound)) { - if (urlFound.startsWith("//")) { - //create URL taking only the protocol from the context - String origHostAndPath = urlFound.substring(2);// removing "//" - String host; - String path; - int indexOf = origHostAndPath.indexOf("/"); - if (indexOf > 0) { - host = origHostAndPath.substring(0, indexOf); - path = origHostAndPath.substring(indexOf); - } else { - host = origHostAndPath; - path = ""; - } - absoluteUrl = new URL(context.getProtocol(), host, path); - } else if (urlFound.startsWith("/")) { - //create URL taking the protocol and the host from the context - absoluteUrl = new URL(context.getProtocol(), context.getHost(), urlFound); - } else { - //"concat" URL to context - int backDir = 0; // removing directories due to "../" - while(urlFound.startsWith("../")){ - urlFound = urlFound.substring(3); - backDir++; - } - StringBuilder contextPath = new StringBuilder(); - String path = context.getPath().replace("\\", "/"); - boolean isContextDirectory = path.endsWith("/"); - String[] split = path.split("/"); - // we are also removing last element in case of a directory - int rightTrimFromPath = (isContextDirectory ? 0 : 1) + backDir; - - for (int i = 0; i < split.length - rightTrimFromPath; i++) { - contextPath.append(split[i]); - contextPath.append("/"); - } - absoluteUrl = new URL(context.getProtocol(), context.getHost(), contextPath.toString() + urlFound); - } - } else{ - absoluteUrl = new URL(urlFound); - } - return absoluteUrl; - } - - private static boolean isAbsoluteUrl(String orig) { - return orig.startsWith("http"); - } - - -} +/****************************************************************************** + * Copyright (c) 2002 - 2011 IBM Corporation. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *****************************************************************************/ +package com.ibm.wala.cast.js.html; + +import java.net.MalformedURLException; +import java.net.URL; + +public class UrlManipulator { + + + /** + * @param urlFound the link as appear + * @param context the URL in which the link appeared + * @return + * @throws MalformedURLException + */ + public static URL relativeToAbsoluteUrl(String urlFound, URL context) throws MalformedURLException { + urlFound = urlFound.replace("\\", "/").toLowerCase(); + + URL absoluteUrl; + if (!isAbsoluteUrl(urlFound)) { + if (urlFound.startsWith("//")) { + //create URL taking only the protocol from the context + String origHostAndPath = urlFound.substring(2);// removing "//" + String host; + String path; + int indexOf = origHostAndPath.indexOf("/"); + if (indexOf > 0) { + host = origHostAndPath.substring(0, indexOf); + path = origHostAndPath.substring(indexOf); + } else { + host = origHostAndPath; + path = ""; + } + absoluteUrl = new URL(context.getProtocol(), host, path); + } else if (urlFound.startsWith("/")) { + //create URL taking the protocol and the host from the context + absoluteUrl = new URL(context.getProtocol(), context.getHost(), urlFound); + } else { + //"concat" URL to context + int backDir = 0; // removing directories due to "../" + while(urlFound.startsWith("../")){ + urlFound = urlFound.substring(3); + backDir++; + } + StringBuilder contextPath = new StringBuilder(); + String path = context.getPath().replace("\\", "/"); + boolean isContextDirectory = path.endsWith("/"); + String[] split = path.split("/"); + // we are also removing last element in case of a directory + int rightTrimFromPath = (isContextDirectory ? 0 : 1) + backDir; + + for (int i = 0; i < split.length - rightTrimFromPath; i++) { + contextPath.append(split[i]); + contextPath.append("/"); + } + absoluteUrl = new URL(context.getProtocol(), context.getHost(), contextPath.toString() + urlFound); + } + } else{ + absoluteUrl = new URL(urlFound); + } + return absoluteUrl; + } + + private static boolean isAbsoluteUrl(String orig) { + return orig.startsWith("http"); + } + + +} diff --git a/com.ibm.wala.cast.js/source/com/ibm/wala/cast/js/html/jericho/JerichoHtmlParser.java b/com.ibm.wala.cast.js/source/com/ibm/wala/cast/js/html/jericho/JerichoHtmlParser.java index ec34bbd43..20b4c256a 100644 --- a/com.ibm.wala.cast.js/source/com/ibm/wala/cast/js/html/jericho/JerichoHtmlParser.java +++ b/com.ibm.wala.cast.js/source/com/ibm/wala/cast/js/html/jericho/JerichoHtmlParser.java @@ -1,78 +1,78 @@ -/****************************************************************************** - * Copyright (c) 2002 - 2011 IBM Corporation. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * IBM Corporation - initial API and implementation - *****************************************************************************/ -package com.ibm.wala.cast.js.html.jericho; - -import java.io.IOException; -import java.io.InputStream; -import java.net.URL; -import java.util.Iterator; -import java.util.List; - -import net.htmlparser.jericho.Config; -import net.htmlparser.jericho.Element; -import net.htmlparser.jericho.LoggerProvider; -import net.htmlparser.jericho.Source; - -import com.ibm.wala.cast.js.html.IHtmlCallback; -import com.ibm.wala.cast.js.html.IHtmlParser; - - -/** - * @author danielk - * Uses the Jericho parser to go over the HTML - */ -public class JerichoHtmlParser implements IHtmlParser{ - static{ - Config.LoggerProvider = LoggerProvider.STDERR; - } - - public void parse(URL url, InputStream reader, IHtmlCallback callback, String fileName) { - Parser parser = new Parser(callback, fileName); - Source src; - try { - src = new Source(reader); - List childElements = src.getChildElements(); - for (Iterator nodeIterator = childElements.iterator(); nodeIterator.hasNext();) { - Element e = nodeIterator.next(); - parser.parse(e); - } - } catch (IOException e) { - System.err.println("Error parsing file: " + e.getMessage()); - } - } - /** - * @author danielk - * Inner class does the actual traversal of the HTML using recursion - */ - private static class Parser { - private final IHtmlCallback handler; - private final String fileName; - - public Parser(IHtmlCallback handler, String fileName) { - this.handler = handler; - this.fileName = fileName; - } - - private void parse(Element root) { - JerichoTag tag = new JerichoTag(root, fileName); - handler.handleStartTag(tag); - handler.handleText(tag.getElementPosition(), tag.getBodyText().snd); - List childElements = root.getChildElements(); - for (Iterator nodeIterator = childElements.iterator(); nodeIterator.hasNext();) { - Element child = nodeIterator.next(); - parse(child); - } - handler.handleEndTag(tag); - } - - } - -} +/****************************************************************************** + * Copyright (c) 2002 - 2011 IBM Corporation. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *****************************************************************************/ +package com.ibm.wala.cast.js.html.jericho; + +import java.io.IOException; +import java.io.InputStream; +import java.net.URL; +import java.util.Iterator; +import java.util.List; + +import net.htmlparser.jericho.Config; +import net.htmlparser.jericho.Element; +import net.htmlparser.jericho.LoggerProvider; +import net.htmlparser.jericho.Source; + +import com.ibm.wala.cast.js.html.IHtmlCallback; +import com.ibm.wala.cast.js.html.IHtmlParser; + + +/** + * @author danielk + * Uses the Jericho parser to go over the HTML + */ +public class JerichoHtmlParser implements IHtmlParser{ + static{ + Config.LoggerProvider = LoggerProvider.STDERR; + } + + public void parse(URL url, InputStream reader, IHtmlCallback callback, String fileName) { + Parser parser = new Parser(callback, fileName); + Source src; + try { + src = new Source(reader); + List childElements = src.getChildElements(); + for (Iterator nodeIterator = childElements.iterator(); nodeIterator.hasNext();) { + Element e = nodeIterator.next(); + parser.parse(e); + } + } catch (IOException e) { + System.err.println("Error parsing file: " + e.getMessage()); + } + } + /** + * @author danielk + * Inner class does the actual traversal of the HTML using recursion + */ + private static class Parser { + private final IHtmlCallback handler; + private final String fileName; + + public Parser(IHtmlCallback handler, String fileName) { + this.handler = handler; + this.fileName = fileName; + } + + private void parse(Element root) { + JerichoTag tag = new JerichoTag(root, fileName); + handler.handleStartTag(tag); + handler.handleText(tag.getElementPosition(), tag.getBodyText().snd); + List childElements = root.getChildElements(); + for (Iterator nodeIterator = childElements.iterator(); nodeIterator.hasNext();) { + Element child = nodeIterator.next(); + parse(child); + } + handler.handleEndTag(tag); + } + + } + +} diff --git a/com.ibm.wala.cast.js/source/com/ibm/wala/cast/js/html/jericho/JerichoTag.java b/com.ibm.wala.cast.js/source/com/ibm/wala/cast/js/html/jericho/JerichoTag.java index 54d653ebc..90c5a4d18 100644 --- a/com.ibm.wala.cast.js/source/com/ibm/wala/cast/js/html/jericho/JerichoTag.java +++ b/com.ibm.wala.cast.js/source/com/ibm/wala/cast/js/html/jericho/JerichoTag.java @@ -1,147 +1,147 @@ -/****************************************************************************** - * Copyright (c) 2002 - 2011 IBM Corporation. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * IBM Corporation - initial API and implementation - *****************************************************************************/ -package com.ibm.wala.cast.js.html.jericho; - -import java.io.FileInputStream; -import java.io.IOException; -import java.io.InputStream; -import java.net.MalformedURLException; -import java.net.URL; -import java.util.Map; - -import net.htmlparser.jericho.Attribute; -import net.htmlparser.jericho.Element; -import net.htmlparser.jericho.Segment; - -import com.ibm.wala.cast.js.html.ITag; -import com.ibm.wala.cast.tree.CAstSourcePositionMap.Position; -import com.ibm.wala.cast.tree.impl.AbstractSourcePosition; -import com.ibm.wala.util.collections.HashMapFactory; -import com.ibm.wala.util.collections.Pair; - -/** - * ITag impel for Jericho generated tags - * @author danielk - */ -public class JerichoTag implements ITag { - - private final Element innerElement; - private final String sourceFile; - private Map> allAttributes = null; - - public JerichoTag(Element root, String sourceFile) { - this.innerElement = root; - this.sourceFile = sourceFile; - } - - private Position getPosition(final Segment e) { - return new AbstractSourcePosition() { - - @Override - public int getFirstLine() { - return e.getSource().getRowColumnVector(e.getBegin()).getRow(); - } - - @Override - public int getLastLine() { - return e.getSource().getRowColumnVector(e.getEnd()).getRow(); - } - - @Override - public int getFirstCol() { - return e.getSource().getRowColumnVector(e.getBegin()).getColumn(); - } - - @Override - public int getLastCol() { - return e.getSource().getRowColumnVector(e.getEnd()).getColumn(); - } - - @Override - public int getFirstOffset() { - return e.getBegin(); - } - - @Override - public int getLastOffset() { - return e.getEnd(); - } - - @Override - public URL getURL() { - try { - return new URL("file://" + sourceFile); - } catch (MalformedURLException e) { - return null; - } - } - - @Override - public InputStream getInputStream() throws IOException { - return new FileInputStream(sourceFile); - } - }; - } - - private Map> makeAllAttributes() { - Map> result = HashMapFactory.make(); - if (innerElement.getStartTag().getAttributes() != null) { - for (Attribute a : innerElement.getStartTag().getAttributes()) { - result.put( - a.getName().toLowerCase(), - Pair.make(a.getValue(), getPosition(a.getValueSegment()))); - } - } - return result; - } - - public Map> getAllAttributes() { - if (allAttributes == null) { - allAttributes = makeAllAttributes(); - } - return allAttributes; - } - - public Pair getAttributeByName(String name) { - if (allAttributes == null) { - allAttributes = makeAllAttributes(); - } - return allAttributes.get(name.toLowerCase()); - } - - public Pair getBodyText() { - Segment content = innerElement.getContent(); - Integer lineNum = innerElement.getSource().getRow(content.getBegin()); - String body = content.toString(); - return Pair.make(lineNum, body); - } - - public String getFilePath() { - return sourceFile; - } - - public String getName() { - return innerElement.getName(); - } - - @Override - public String toString() { - return innerElement.toString(); - } - - public Position getElementPosition() { - return getPosition(innerElement); - } - - public Position getContentPosition() { - return getPosition(innerElement.getContent()); - } -} +/****************************************************************************** + * Copyright (c) 2002 - 2011 IBM Corporation. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *****************************************************************************/ +package com.ibm.wala.cast.js.html.jericho; + +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.net.MalformedURLException; +import java.net.URL; +import java.util.Map; + +import net.htmlparser.jericho.Attribute; +import net.htmlparser.jericho.Element; +import net.htmlparser.jericho.Segment; + +import com.ibm.wala.cast.js.html.ITag; +import com.ibm.wala.cast.tree.CAstSourcePositionMap.Position; +import com.ibm.wala.cast.tree.impl.AbstractSourcePosition; +import com.ibm.wala.util.collections.HashMapFactory; +import com.ibm.wala.util.collections.Pair; + +/** + * ITag impel for Jericho generated tags + * @author danielk + */ +public class JerichoTag implements ITag { + + private final Element innerElement; + private final String sourceFile; + private Map> allAttributes = null; + + public JerichoTag(Element root, String sourceFile) { + this.innerElement = root; + this.sourceFile = sourceFile; + } + + private Position getPosition(final Segment e) { + return new AbstractSourcePosition() { + + @Override + public int getFirstLine() { + return e.getSource().getRowColumnVector(e.getBegin()).getRow(); + } + + @Override + public int getLastLine() { + return e.getSource().getRowColumnVector(e.getEnd()).getRow(); + } + + @Override + public int getFirstCol() { + return e.getSource().getRowColumnVector(e.getBegin()).getColumn(); + } + + @Override + public int getLastCol() { + return e.getSource().getRowColumnVector(e.getEnd()).getColumn(); + } + + @Override + public int getFirstOffset() { + return e.getBegin(); + } + + @Override + public int getLastOffset() { + return e.getEnd(); + } + + @Override + public URL getURL() { + try { + return new URL("file://" + sourceFile); + } catch (MalformedURLException e) { + return null; + } + } + + @Override + public InputStream getInputStream() throws IOException { + return new FileInputStream(sourceFile); + } + }; + } + + private Map> makeAllAttributes() { + Map> result = HashMapFactory.make(); + if (innerElement.getStartTag().getAttributes() != null) { + for (Attribute a : innerElement.getStartTag().getAttributes()) { + result.put( + a.getName().toLowerCase(), + Pair.make(a.getValue(), getPosition(a.getValueSegment()))); + } + } + return result; + } + + public Map> getAllAttributes() { + if (allAttributes == null) { + allAttributes = makeAllAttributes(); + } + return allAttributes; + } + + public Pair getAttributeByName(String name) { + if (allAttributes == null) { + allAttributes = makeAllAttributes(); + } + return allAttributes.get(name.toLowerCase()); + } + + public Pair getBodyText() { + Segment content = innerElement.getContent(); + Integer lineNum = innerElement.getSource().getRow(content.getBegin()); + String body = content.toString(); + return Pair.make(lineNum, body); + } + + public String getFilePath() { + return sourceFile; + } + + public String getName() { + return innerElement.getName(); + } + + @Override + public String toString() { + return innerElement.toString(); + } + + public Position getElementPosition() { + return getPosition(innerElement); + } + + public Position getContentPosition() { + return getPosition(innerElement.getContent()); + } +} diff --git a/com.ibm.wala.cast/source/java/com/ibm/wala/cast/ipa/callgraph/AstCallGraph.java b/com.ibm.wala.cast/source/java/com/ibm/wala/cast/ipa/callgraph/AstCallGraph.java index 9158cbef8..12cc37510 100644 --- a/com.ibm.wala.cast/source/java/com/ibm/wala/cast/ipa/callgraph/AstCallGraph.java +++ b/com.ibm.wala.cast/source/java/com/ibm/wala/cast/ipa/callgraph/AstCallGraph.java @@ -1,198 +1,198 @@ -/****************************************************************************** - * Copyright (c) 2002 - 2006 IBM Corporation. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * IBM Corporation - initial API and implementation - *****************************************************************************/ -package com.ibm.wala.cast.ipa.callgraph; - -import java.util.ConcurrentModificationException; -import java.util.Iterator; -import java.util.Set; - -import com.ibm.wala.cast.ir.cfg.AstInducedCFG; -import com.ibm.wala.cast.ir.ssa.AstLexicalRead; -import com.ibm.wala.cfg.InducedCFG; -import com.ibm.wala.classLoader.CallSiteReference; -import com.ibm.wala.classLoader.IClass; -import com.ibm.wala.classLoader.IMethod; -import com.ibm.wala.ipa.callgraph.AnalysisCache; -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.impl.AbstractRootMethod; -import com.ibm.wala.ipa.callgraph.impl.Everywhere; -import com.ibm.wala.ipa.callgraph.impl.ExplicitCallGraph; -import com.ibm.wala.ipa.callgraph.impl.FakeRootMethod; -import com.ibm.wala.ipa.cha.IClassHierarchy; -import com.ibm.wala.ssa.DefUse; -import com.ibm.wala.ssa.IR; -import com.ibm.wala.ssa.SSAAbstractInvokeInstruction; -import com.ibm.wala.ssa.SSAInstruction; -import com.ibm.wala.types.MethodReference; -import com.ibm.wala.types.TypeReference; -import com.ibm.wala.util.CancelException; -import com.ibm.wala.util.collections.HashSetFactory; -import com.ibm.wala.util.functions.Function; - -public class AstCallGraph extends ExplicitCallGraph { - public AstCallGraph(IClassHierarchy cha, AnalysisOptions options, AnalysisCache cache) { - super(cha, options, cache); - } - - public static class AstFakeRoot extends AbstractRootMethod { - - public AstFakeRoot(MethodReference rootMethod, IClass declaringClass, IClassHierarchy cha, AnalysisOptions options, AnalysisCache cache) { - super(rootMethod, declaringClass, cha, options, cache); - } - - public AstFakeRoot(MethodReference rootMethod, IClassHierarchy cha, AnalysisOptions options, AnalysisCache cache) { - super(rootMethod, cha, options, cache); - } - - public InducedCFG makeControlFlowGraph(SSAInstruction[] statements) { - return new AstInducedCFG(statements, this, Everywhere.EVERYWHERE); - } - - public AstLexicalRead addGlobalRead(TypeReference type, String name) { - AstLexicalRead s = new AstLexicalRead(nextLocal++, null, name); - statements.add(s); - return s; - } - } - - public static abstract class ScriptFakeRoot extends AstFakeRoot { - - public ScriptFakeRoot(MethodReference rootMethod, IClass declaringClass, IClassHierarchy cha, AnalysisOptions options, AnalysisCache cache) { - super(rootMethod, declaringClass, cha, options, cache); - } - - public ScriptFakeRoot(MethodReference rootMethod, IClassHierarchy cha, AnalysisOptions options, AnalysisCache cache) { - super(rootMethod, cha, options, cache); - } - - public abstract SSAAbstractInvokeInstruction addDirectCall(int functionVn, int[] argVns, CallSiteReference callSite); - - } - - public class AstCGNode extends ExplicitNode { - private Set> callbacks; - - private boolean lexicalScopingChanges = false; - - private IR cachedIR; - - private DefUse cachedDU; - - private AstCGNode(IMethod method, Context context) { - super(method, context); - } - - private void fireCallbacks() { - if (callbacks != null) { - boolean done = false; - while (!done) { - try { - for (Iterator> x = callbacks.iterator(); x.hasNext();) { - x.next().apply(null); - } - } catch (ConcurrentModificationException e) { - done = false; - continue; - } - done = true; - } - } - } - - private boolean hasCallback(Function callback) { - return callbacks != null && callbacks.contains(callback); - } - - private boolean hasAllCallbacks(Set> callbacks) { - return callbacks != null && callbacks.containsAll(callbacks); - } - - public void addCallback(Function callback) { - if (!hasCallback(callback)) { - if (callbacks == null) { - callbacks = HashSetFactory.make(1); - } - - callbacks.add(callback); - - for (Iterator ps = getCallGraph().getPredNodes(this); ps.hasNext();) { - ((AstCGNode) ps.next()).addCallback(callback); - } - } - } - - public void addAllCallbacks(Set> callback) { - if (!hasAllCallbacks(callbacks)) { - if (callbacks == null) { - callbacks = HashSetFactory.make(1); - } - - callbacks.addAll(callback); - - for (Iterator ps = getCallGraph().getPredNodes(this); ps.hasNext();) { - ((AstCGNode) ps.next()).addAllCallbacks(callback); - } - } - } - - public void setLexicallyMutatedIR(IR ir) { - lexicalScopingChanges = true; - cachedIR = ir; - cachedDU = null; - } - - public void clearMutatedCache(CallSiteReference cs) { - targets.remove(cs.getProgramCounter()); - } - - public IR getLexicallyMutatedIR() { - if (lexicalScopingChanges) { - return cachedIR; - } else { - return null; - } - } - - public DefUse getLexicallyMutatedDU() { - if (lexicalScopingChanges) { - if (cachedDU == null) { - cachedDU = new DefUse(cachedIR); - } - return cachedDU; - } else { - return null; - } - } - - public boolean addTarget(CallSiteReference site, CGNode node) { - if (super.addTarget(site, node)) { - if (((AstCGNode) node).callbacks != null) { - ((AstCGNode) node).fireCallbacks(); - addAllCallbacks(((AstCGNode) node).callbacks); - } - return true; - } else { - return false; - } - } - } - - protected ExplicitNode makeNode(IMethod method, Context context) { - return new AstCGNode(method, context); - } - - protected CGNode makeFakeRootNode() throws CancelException { - return findOrCreateNode(new AstFakeRoot(FakeRootMethod.rootMethod, cha, options, getAnalysisCache()), Everywhere.EVERYWHERE); - } - -} +/****************************************************************************** + * Copyright (c) 2002 - 2006 IBM Corporation. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *****************************************************************************/ +package com.ibm.wala.cast.ipa.callgraph; + +import java.util.ConcurrentModificationException; +import java.util.Iterator; +import java.util.Set; + +import com.ibm.wala.cast.ir.cfg.AstInducedCFG; +import com.ibm.wala.cast.ir.ssa.AstLexicalRead; +import com.ibm.wala.cfg.InducedCFG; +import com.ibm.wala.classLoader.CallSiteReference; +import com.ibm.wala.classLoader.IClass; +import com.ibm.wala.classLoader.IMethod; +import com.ibm.wala.ipa.callgraph.AnalysisCache; +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.impl.AbstractRootMethod; +import com.ibm.wala.ipa.callgraph.impl.Everywhere; +import com.ibm.wala.ipa.callgraph.impl.ExplicitCallGraph; +import com.ibm.wala.ipa.callgraph.impl.FakeRootMethod; +import com.ibm.wala.ipa.cha.IClassHierarchy; +import com.ibm.wala.ssa.DefUse; +import com.ibm.wala.ssa.IR; +import com.ibm.wala.ssa.SSAAbstractInvokeInstruction; +import com.ibm.wala.ssa.SSAInstruction; +import com.ibm.wala.types.MethodReference; +import com.ibm.wala.types.TypeReference; +import com.ibm.wala.util.CancelException; +import com.ibm.wala.util.collections.HashSetFactory; +import com.ibm.wala.util.functions.Function; + +public class AstCallGraph extends ExplicitCallGraph { + public AstCallGraph(IClassHierarchy cha, AnalysisOptions options, AnalysisCache cache) { + super(cha, options, cache); + } + + public static class AstFakeRoot extends AbstractRootMethod { + + public AstFakeRoot(MethodReference rootMethod, IClass declaringClass, IClassHierarchy cha, AnalysisOptions options, AnalysisCache cache) { + super(rootMethod, declaringClass, cha, options, cache); + } + + public AstFakeRoot(MethodReference rootMethod, IClassHierarchy cha, AnalysisOptions options, AnalysisCache cache) { + super(rootMethod, cha, options, cache); + } + + public InducedCFG makeControlFlowGraph(SSAInstruction[] statements) { + return new AstInducedCFG(statements, this, Everywhere.EVERYWHERE); + } + + public AstLexicalRead addGlobalRead(TypeReference type, String name) { + AstLexicalRead s = new AstLexicalRead(nextLocal++, null, name); + statements.add(s); + return s; + } + } + + public static abstract class ScriptFakeRoot extends AstFakeRoot { + + public ScriptFakeRoot(MethodReference rootMethod, IClass declaringClass, IClassHierarchy cha, AnalysisOptions options, AnalysisCache cache) { + super(rootMethod, declaringClass, cha, options, cache); + } + + public ScriptFakeRoot(MethodReference rootMethod, IClassHierarchy cha, AnalysisOptions options, AnalysisCache cache) { + super(rootMethod, cha, options, cache); + } + + public abstract SSAAbstractInvokeInstruction addDirectCall(int functionVn, int[] argVns, CallSiteReference callSite); + + } + + public class AstCGNode extends ExplicitNode { + private Set> callbacks; + + private boolean lexicalScopingChanges = false; + + private IR cachedIR; + + private DefUse cachedDU; + + private AstCGNode(IMethod method, Context context) { + super(method, context); + } + + private void fireCallbacks() { + if (callbacks != null) { + boolean done = false; + while (!done) { + try { + for (Iterator> x = callbacks.iterator(); x.hasNext();) { + x.next().apply(null); + } + } catch (ConcurrentModificationException e) { + done = false; + continue; + } + done = true; + } + } + } + + private boolean hasCallback(Function callback) { + return callbacks != null && callbacks.contains(callback); + } + + private boolean hasAllCallbacks(Set> callbacks) { + return callbacks != null && callbacks.containsAll(callbacks); + } + + public void addCallback(Function callback) { + if (!hasCallback(callback)) { + if (callbacks == null) { + callbacks = HashSetFactory.make(1); + } + + callbacks.add(callback); + + for (Iterator ps = getCallGraph().getPredNodes(this); ps.hasNext();) { + ((AstCGNode) ps.next()).addCallback(callback); + } + } + } + + public void addAllCallbacks(Set> callback) { + if (!hasAllCallbacks(callbacks)) { + if (callbacks == null) { + callbacks = HashSetFactory.make(1); + } + + callbacks.addAll(callback); + + for (Iterator ps = getCallGraph().getPredNodes(this); ps.hasNext();) { + ((AstCGNode) ps.next()).addAllCallbacks(callback); + } + } + } + + public void setLexicallyMutatedIR(IR ir) { + lexicalScopingChanges = true; + cachedIR = ir; + cachedDU = null; + } + + public void clearMutatedCache(CallSiteReference cs) { + targets.remove(cs.getProgramCounter()); + } + + public IR getLexicallyMutatedIR() { + if (lexicalScopingChanges) { + return cachedIR; + } else { + return null; + } + } + + public DefUse getLexicallyMutatedDU() { + if (lexicalScopingChanges) { + if (cachedDU == null) { + cachedDU = new DefUse(cachedIR); + } + return cachedDU; + } else { + return null; + } + } + + public boolean addTarget(CallSiteReference site, CGNode node) { + if (super.addTarget(site, node)) { + if (((AstCGNode) node).callbacks != null) { + ((AstCGNode) node).fireCallbacks(); + addAllCallbacks(((AstCGNode) node).callbacks); + } + return true; + } else { + return false; + } + } + } + + protected ExplicitNode makeNode(IMethod method, Context context) { + return new AstCGNode(method, context); + } + + protected CGNode makeFakeRootNode() throws CancelException { + return findOrCreateNode(new AstFakeRoot(FakeRootMethod.rootMethod, cha, options, getAnalysisCache()), Everywhere.EVERYWHERE); + } + +} diff --git a/com.ibm.wala.cast/source/java/com/ibm/wala/cast/ipa/callgraph/CrossLanguageCallGraph.java b/com.ibm.wala.cast/source/java/com/ibm/wala/cast/ipa/callgraph/CrossLanguageCallGraph.java index a02ac2404..baea5d530 100644 --- a/com.ibm.wala.cast/source/java/com/ibm/wala/cast/ipa/callgraph/CrossLanguageCallGraph.java +++ b/com.ibm.wala.cast/source/java/com/ibm/wala/cast/ipa/callgraph/CrossLanguageCallGraph.java @@ -1,168 +1,168 @@ -/****************************************************************************** - * Copyright (c) 2002 - 2006 IBM Corporation. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * IBM Corporation - initial API and implementation - *****************************************************************************/ -package com.ibm.wala.cast.ipa.callgraph; - -import java.util.Iterator; -import java.util.Map; -import java.util.Set; - -import com.ibm.wala.cast.ir.ssa.AstLexicalRead; -import com.ibm.wala.cast.util.TargetLanguageSelector; -import com.ibm.wala.classLoader.CallSiteReference; -import com.ibm.wala.classLoader.IClass; -import com.ibm.wala.classLoader.IMethod; -import com.ibm.wala.ipa.callgraph.AnalysisCache; -import com.ibm.wala.ipa.callgraph.AnalysisOptions; -import com.ibm.wala.ipa.callgraph.CGNode; -import com.ibm.wala.ipa.callgraph.impl.AbstractRootMethod; -import com.ibm.wala.ipa.callgraph.impl.Everywhere; -import com.ibm.wala.ipa.callgraph.impl.FakeRootMethod; -import com.ibm.wala.ipa.cha.IClassHierarchy; -import com.ibm.wala.shrikeBT.IInvokeInstruction; -import com.ibm.wala.ssa.SSAAbstractInvokeInstruction; -import com.ibm.wala.ssa.SSAInvokeInstruction; -import com.ibm.wala.ssa.SSANewInstruction; -import com.ibm.wala.types.FieldReference; -import com.ibm.wala.types.TypeReference; -import com.ibm.wala.util.CancelException; -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.strings.Atom; - -/** - * A CallGraph implementation adapted to work for graphs that contain code - * entities from multiple languages, and hence multiple specialized forms of IR. - * The root node delegates to one of several language-specific root nodes, - * allowing each language to use its own specialized IR constructs for entry - * points. - * - * @author Julian Dolby (dolby@us.ibm.com) - */ -public class CrossLanguageCallGraph extends AstCallGraph { - - public CrossLanguageCallGraph(TargetLanguageSelector roots, IClassHierarchy cha, - AnalysisOptions options, AnalysisCache cache) { - super(cha, options, cache); - this.roots = roots; - } - - private final TargetLanguageSelector roots; - - private final Set languageRootNodes = HashSetFactory.make(); - - private final Map languageRoots = HashMapFactory.make(); - - @SuppressWarnings("deprecation") - public AbstractRootMethod getLanguageRoot(Atom language){ - if (!languageRoots.containsKey(language)) { - AbstractRootMethod languageRoot = roots.get(language, this); - - CGNode languageRootNode = null; - try { - languageRootNode = findOrCreateNode(languageRoot, Everywhere.EVERYWHERE); - } catch (CancelException e) { - e.printStackTrace(); - Assertions.UNREACHABLE(); - } - - languageRootNodes.add(languageRootNode); - - CallSiteReference site = CallSiteReference.make(1, languageRoot.getReference(), IInvokeInstruction.Dispatch.STATIC); - - CGNode fakeRootNode = getFakeRootNode(); - CrossLanguageFakeRoot fakeRootMethod = (CrossLanguageFakeRoot) fakeRootNode.getMethod(); - - site = fakeRootMethod.addInvocationInternal(new int[0], site).getCallSite(); - - fakeRootNode.addTarget(site, languageRootNode); - - languageRoots.put(language, languageRoot); - } - - return (AbstractRootMethod) languageRoots.get(language); - } - - public class CrossLanguageFakeRoot extends ScriptFakeRoot { - - public CrossLanguageFakeRoot(IClass declaringClass, IClassHierarchy cha, AnalysisOptions options, AnalysisCache cache) { - super(FakeRootMethod.rootMethod, declaringClass, cha, options, cache); - } - - public CrossLanguageFakeRoot(IClassHierarchy cha, AnalysisOptions options, AnalysisCache cache) { - super(FakeRootMethod.rootMethod, cha, options, cache); - } - - public int addPhi(TypeReference type, int[] values) { - Atom language = type.getClassLoader().getLanguage(); - AbstractRootMethod root = getLanguageRoot(language); - return root.addPhi(values); - } - - public int addGetInstance(FieldReference ref, int object) { - TypeReference type = ref.getDeclaringClass(); - Atom language = type.getClassLoader().getLanguage(); - AbstractRootMethod root = getLanguageRoot(language); - return root.addGetInstance(ref, object); - } - - public int addGetStatic(FieldReference ref) { - TypeReference type = ref.getDeclaringClass(); - Atom language = type.getClassLoader().getLanguage(); - AbstractRootMethod root = getLanguageRoot(language); - return root.addGetStatic(ref); - } - - public int addCheckcast(TypeReference[] type, int rv, boolean isPEI) { - Atom language = type[0].getClassLoader().getLanguage(); - AbstractRootMethod root = getLanguageRoot(language); - return root.addCheckcast(type, rv, isPEI); - } - - public SSANewInstruction addAllocation(TypeReference type) { - Atom language = type.getClassLoader().getLanguage(); - AbstractRootMethod root = getLanguageRoot(language); - return root.addAllocation(type); - } - - public SSAInvokeInstruction addInvocation(int[] params, CallSiteReference site) { - TypeReference type = site.getDeclaredTarget().getDeclaringClass(); - Atom language = type.getClassLoader().getLanguage(); - AbstractRootMethod root = getLanguageRoot(language); - return root.addInvocation(params, site); - } - - public SSAInvokeInstruction addInvocationInternal(int[] params, CallSiteReference site) { - return super.addInvocation(params, site); - } - - public AstLexicalRead addGlobalRead(TypeReference type, String name) { - Atom language = type.getClassLoader().getLanguage(); - AbstractRootMethod root = getLanguageRoot(language); - return ((AstFakeRoot) root).addGlobalRead(type, name); - } - - public SSAAbstractInvokeInstruction addDirectCall(int functionVn, int[] argVns, CallSiteReference callSite) { - TypeReference type = callSite.getDeclaredTarget().getDeclaringClass(); - Atom language = type.getClassLoader().getLanguage(); - AbstractRootMethod root = getLanguageRoot(language); - return ((ScriptFakeRoot) root).addDirectCall(functionVn, argVns, callSite); - } - } - - Iterator getLanguageRoots() { - return languageRootNodes.iterator(); - } - - protected CGNode makeFakeRootNode() throws CancelException { - return findOrCreateNode(new CrossLanguageFakeRoot(cha, options, getAnalysisCache()), Everywhere.EVERYWHERE); - } -} +/****************************************************************************** + * Copyright (c) 2002 - 2006 IBM Corporation. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *****************************************************************************/ +package com.ibm.wala.cast.ipa.callgraph; + +import java.util.Iterator; +import java.util.Map; +import java.util.Set; + +import com.ibm.wala.cast.ir.ssa.AstLexicalRead; +import com.ibm.wala.cast.util.TargetLanguageSelector; +import com.ibm.wala.classLoader.CallSiteReference; +import com.ibm.wala.classLoader.IClass; +import com.ibm.wala.classLoader.IMethod; +import com.ibm.wala.ipa.callgraph.AnalysisCache; +import com.ibm.wala.ipa.callgraph.AnalysisOptions; +import com.ibm.wala.ipa.callgraph.CGNode; +import com.ibm.wala.ipa.callgraph.impl.AbstractRootMethod; +import com.ibm.wala.ipa.callgraph.impl.Everywhere; +import com.ibm.wala.ipa.callgraph.impl.FakeRootMethod; +import com.ibm.wala.ipa.cha.IClassHierarchy; +import com.ibm.wala.shrikeBT.IInvokeInstruction; +import com.ibm.wala.ssa.SSAAbstractInvokeInstruction; +import com.ibm.wala.ssa.SSAInvokeInstruction; +import com.ibm.wala.ssa.SSANewInstruction; +import com.ibm.wala.types.FieldReference; +import com.ibm.wala.types.TypeReference; +import com.ibm.wala.util.CancelException; +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.strings.Atom; + +/** + * A CallGraph implementation adapted to work for graphs that contain code + * entities from multiple languages, and hence multiple specialized forms of IR. + * The root node delegates to one of several language-specific root nodes, + * allowing each language to use its own specialized IR constructs for entry + * points. + * + * @author Julian Dolby (dolby@us.ibm.com) + */ +public class CrossLanguageCallGraph extends AstCallGraph { + + public CrossLanguageCallGraph(TargetLanguageSelector roots, IClassHierarchy cha, + AnalysisOptions options, AnalysisCache cache) { + super(cha, options, cache); + this.roots = roots; + } + + private final TargetLanguageSelector roots; + + private final Set languageRootNodes = HashSetFactory.make(); + + private final Map languageRoots = HashMapFactory.make(); + + @SuppressWarnings("deprecation") + public AbstractRootMethod getLanguageRoot(Atom language){ + if (!languageRoots.containsKey(language)) { + AbstractRootMethod languageRoot = roots.get(language, this); + + CGNode languageRootNode = null; + try { + languageRootNode = findOrCreateNode(languageRoot, Everywhere.EVERYWHERE); + } catch (CancelException e) { + e.printStackTrace(); + Assertions.UNREACHABLE(); + } + + languageRootNodes.add(languageRootNode); + + CallSiteReference site = CallSiteReference.make(1, languageRoot.getReference(), IInvokeInstruction.Dispatch.STATIC); + + CGNode fakeRootNode = getFakeRootNode(); + CrossLanguageFakeRoot fakeRootMethod = (CrossLanguageFakeRoot) fakeRootNode.getMethod(); + + site = fakeRootMethod.addInvocationInternal(new int[0], site).getCallSite(); + + fakeRootNode.addTarget(site, languageRootNode); + + languageRoots.put(language, languageRoot); + } + + return (AbstractRootMethod) languageRoots.get(language); + } + + public class CrossLanguageFakeRoot extends ScriptFakeRoot { + + public CrossLanguageFakeRoot(IClass declaringClass, IClassHierarchy cha, AnalysisOptions options, AnalysisCache cache) { + super(FakeRootMethod.rootMethod, declaringClass, cha, options, cache); + } + + public CrossLanguageFakeRoot(IClassHierarchy cha, AnalysisOptions options, AnalysisCache cache) { + super(FakeRootMethod.rootMethod, cha, options, cache); + } + + public int addPhi(TypeReference type, int[] values) { + Atom language = type.getClassLoader().getLanguage(); + AbstractRootMethod root = getLanguageRoot(language); + return root.addPhi(values); + } + + public int addGetInstance(FieldReference ref, int object) { + TypeReference type = ref.getDeclaringClass(); + Atom language = type.getClassLoader().getLanguage(); + AbstractRootMethod root = getLanguageRoot(language); + return root.addGetInstance(ref, object); + } + + public int addGetStatic(FieldReference ref) { + TypeReference type = ref.getDeclaringClass(); + Atom language = type.getClassLoader().getLanguage(); + AbstractRootMethod root = getLanguageRoot(language); + return root.addGetStatic(ref); + } + + public int addCheckcast(TypeReference[] type, int rv, boolean isPEI) { + Atom language = type[0].getClassLoader().getLanguage(); + AbstractRootMethod root = getLanguageRoot(language); + return root.addCheckcast(type, rv, isPEI); + } + + public SSANewInstruction addAllocation(TypeReference type) { + Atom language = type.getClassLoader().getLanguage(); + AbstractRootMethod root = getLanguageRoot(language); + return root.addAllocation(type); + } + + public SSAInvokeInstruction addInvocation(int[] params, CallSiteReference site) { + TypeReference type = site.getDeclaredTarget().getDeclaringClass(); + Atom language = type.getClassLoader().getLanguage(); + AbstractRootMethod root = getLanguageRoot(language); + return root.addInvocation(params, site); + } + + public SSAInvokeInstruction addInvocationInternal(int[] params, CallSiteReference site) { + return super.addInvocation(params, site); + } + + public AstLexicalRead addGlobalRead(TypeReference type, String name) { + Atom language = type.getClassLoader().getLanguage(); + AbstractRootMethod root = getLanguageRoot(language); + return ((AstFakeRoot) root).addGlobalRead(type, name); + } + + public SSAAbstractInvokeInstruction addDirectCall(int functionVn, int[] argVns, CallSiteReference callSite) { + TypeReference type = callSite.getDeclaredTarget().getDeclaringClass(); + Atom language = type.getClassLoader().getLanguage(); + AbstractRootMethod root = getLanguageRoot(language); + return ((ScriptFakeRoot) root).addDirectCall(functionVn, argVns, callSite); + } + } + + Iterator getLanguageRoots() { + return languageRootNodes.iterator(); + } + + protected CGNode makeFakeRootNode() throws CancelException { + return findOrCreateNode(new CrossLanguageFakeRoot(cha, options, getAnalysisCache()), Everywhere.EVERYWHERE); + } +} diff --git a/com.ibm.wala.cast/source/java/com/ibm/wala/cast/ir/ssa/AbstractLexicalInvoke.java b/com.ibm.wala.cast/source/java/com/ibm/wala/cast/ir/ssa/AbstractLexicalInvoke.java index cc44a0ac9..d757cd8a1 100644 --- a/com.ibm.wala.cast/source/java/com/ibm/wala/cast/ir/ssa/AbstractLexicalInvoke.java +++ b/com.ibm.wala.cast/source/java/com/ibm/wala/cast/ir/ssa/AbstractLexicalInvoke.java @@ -1,162 +1,162 @@ -/****************************************************************************** - * Copyright (c) 2002 - 2006 IBM Corporation. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * IBM Corporation - initial API and implementation - *****************************************************************************/ -package com.ibm.wala.cast.ir.ssa; - -import com.ibm.wala.cast.ir.ssa.AstLexicalAccess.Access; -import com.ibm.wala.classLoader.CallSiteReference; -import com.ibm.wala.ssa.SymbolTable; - -/** - * This abstract class adds to invoke instructions the ability to handle lexical uses and definitions during call graph - * construction. The lexical uses and definitions of these objects are initially empty, and get filled in by the - * AstSSAPropagationCallGraphBuilder, particularly its LexicalOperator objects. This class is still abstract since the - * lexical scoping functionality is used by multiple languages, each of which has further specializations of invoke - * instructions. - * - * @author Julian Dolby (dolby@us.ibm.com) - * - */ -public abstract class AbstractLexicalInvoke extends MultiReturnValueInvokeInstruction { - - protected Access[] lexicalReads = null; - - protected Access[] lexicalWrites = null; - - protected AbstractLexicalInvoke(int results[], int exception, CallSiteReference site) { - super(results, exception, site); - } - - protected AbstractLexicalInvoke(int result, int exception, CallSiteReference site) { - this(new int[] { result }, exception, site); - } - - protected AbstractLexicalInvoke(int results[], int exception, CallSiteReference site, Access[] lexicalReads, - Access[] lexicalWrites) { - this(results, exception, site); - this.lexicalReads = lexicalReads; - this.lexicalWrites = lexicalWrites; - } - - public int getNumberOfUses() { - if (lexicalReads == null) - return getNumberOfParameters(); - else - return getNumberOfParameters() + lexicalReads.length; - } - - public int getNumberOfLexicalWrites(){ - if(lexicalWrites == null){ - return 0; - } else { - return lexicalWrites.length; - } - } - - public int getNumberOfLexicalReads() { - if(lexicalReads == null){ - return 0; - } else { - return lexicalReads.length; - } - } - - public final int getLastLexicalUse() { - if (lexicalReads == null) { - return -1; - } else { - return getNumberOfParameters() + lexicalReads.length - 1; - } - } - - public int getUse(int j) { - assert j >= getNumberOfParameters(); - assert lexicalReads != null; - assert lexicalReads[j - getNumberOfParameters()] != null; - return lexicalReads[j - getNumberOfParameters()].valueNumber; - } - - public int getNumberOfDefs() { - if (lexicalWrites == null) - return super.getNumberOfDefs(); - else - return super.getNumberOfDefs() + lexicalWrites.length; - } - - public int getDef(int j) { - if (j < super.getNumberOfDefs()) - return super.getDef(j); - else - return lexicalWrites[j - super.getNumberOfDefs()].valueNumber; - } - - private Access[] addAccess(Access[] array, Access access) { - if (array == null) - return new Access[] { access }; - else { - Access[] result = new Access[array.length + 1]; - System.arraycopy(array, 0, result, 0, array.length); - result[array.length] = access; - return result; - } - } - - public boolean isLexicalUse(int use) { - return use >= getNumberOfParameters(); - } - - public void addLexicalUse(Access use) { - lexicalReads = addAccess(lexicalReads, use); - } - - public Access getLexicalUse(int i) { - return lexicalReads[i - getNumberOfParameters()]; - } - - public boolean isLexicalDef(int def) { - return def >= super.getNumberOfDefs(); - } - - public void addLexicalDef(Access def) { - lexicalWrites = addAccess(lexicalWrites, def); - } - - public Access getLexicalDef(int i) { - return lexicalWrites[i - super.getNumberOfDefs()]; - } - - public int hashCode() { - return site.hashCode() * 7529; - } - - public String toString(SymbolTable symbolTable) { - StringBuffer s = new StringBuffer(super.toString(symbolTable)); - - if (lexicalReads != null) { - s.append(" (reads:"); - for (int i = 0; i < lexicalReads.length; i++) { - s.append(" ").append(lexicalReads[i].variableName).append(":").append( - getValueString(symbolTable, lexicalReads[i].valueNumber)); - } - s.append(")"); - } - - if (lexicalWrites != null) { - s.append(" (writes:"); - for (int i = 0; i < lexicalWrites.length; i++) { - s.append(" ").append(lexicalWrites[i].variableName).append(":").append( - getValueString(symbolTable, lexicalWrites[i].valueNumber)); - } - s.append(")"); - } - - return s.toString(); - } -} +/****************************************************************************** + * Copyright (c) 2002 - 2006 IBM Corporation. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *****************************************************************************/ +package com.ibm.wala.cast.ir.ssa; + +import com.ibm.wala.cast.ir.ssa.AstLexicalAccess.Access; +import com.ibm.wala.classLoader.CallSiteReference; +import com.ibm.wala.ssa.SymbolTable; + +/** + * This abstract class adds to invoke instructions the ability to handle lexical uses and definitions during call graph + * construction. The lexical uses and definitions of these objects are initially empty, and get filled in by the + * AstSSAPropagationCallGraphBuilder, particularly its LexicalOperator objects. This class is still abstract since the + * lexical scoping functionality is used by multiple languages, each of which has further specializations of invoke + * instructions. + * + * @author Julian Dolby (dolby@us.ibm.com) + * + */ +public abstract class AbstractLexicalInvoke extends MultiReturnValueInvokeInstruction { + + protected Access[] lexicalReads = null; + + protected Access[] lexicalWrites = null; + + protected AbstractLexicalInvoke(int results[], int exception, CallSiteReference site) { + super(results, exception, site); + } + + protected AbstractLexicalInvoke(int result, int exception, CallSiteReference site) { + this(new int[] { result }, exception, site); + } + + protected AbstractLexicalInvoke(int results[], int exception, CallSiteReference site, Access[] lexicalReads, + Access[] lexicalWrites) { + this(results, exception, site); + this.lexicalReads = lexicalReads; + this.lexicalWrites = lexicalWrites; + } + + public int getNumberOfUses() { + if (lexicalReads == null) + return getNumberOfParameters(); + else + return getNumberOfParameters() + lexicalReads.length; + } + + public int getNumberOfLexicalWrites(){ + if(lexicalWrites == null){ + return 0; + } else { + return lexicalWrites.length; + } + } + + public int getNumberOfLexicalReads() { + if(lexicalReads == null){ + return 0; + } else { + return lexicalReads.length; + } + } + + public final int getLastLexicalUse() { + if (lexicalReads == null) { + return -1; + } else { + return getNumberOfParameters() + lexicalReads.length - 1; + } + } + + public int getUse(int j) { + assert j >= getNumberOfParameters(); + assert lexicalReads != null; + assert lexicalReads[j - getNumberOfParameters()] != null; + return lexicalReads[j - getNumberOfParameters()].valueNumber; + } + + public int getNumberOfDefs() { + if (lexicalWrites == null) + return super.getNumberOfDefs(); + else + return super.getNumberOfDefs() + lexicalWrites.length; + } + + public int getDef(int j) { + if (j < super.getNumberOfDefs()) + return super.getDef(j); + else + return lexicalWrites[j - super.getNumberOfDefs()].valueNumber; + } + + private Access[] addAccess(Access[] array, Access access) { + if (array == null) + return new Access[] { access }; + else { + Access[] result = new Access[array.length + 1]; + System.arraycopy(array, 0, result, 0, array.length); + result[array.length] = access; + return result; + } + } + + public boolean isLexicalUse(int use) { + return use >= getNumberOfParameters(); + } + + public void addLexicalUse(Access use) { + lexicalReads = addAccess(lexicalReads, use); + } + + public Access getLexicalUse(int i) { + return lexicalReads[i - getNumberOfParameters()]; + } + + public boolean isLexicalDef(int def) { + return def >= super.getNumberOfDefs(); + } + + public void addLexicalDef(Access def) { + lexicalWrites = addAccess(lexicalWrites, def); + } + + public Access getLexicalDef(int i) { + return lexicalWrites[i - super.getNumberOfDefs()]; + } + + public int hashCode() { + return site.hashCode() * 7529; + } + + public String toString(SymbolTable symbolTable) { + StringBuffer s = new StringBuffer(super.toString(symbolTable)); + + if (lexicalReads != null) { + s.append(" (reads:"); + for (int i = 0; i < lexicalReads.length; i++) { + s.append(" ").append(lexicalReads[i].variableName).append(":").append( + getValueString(symbolTable, lexicalReads[i].valueNumber)); + } + s.append(")"); + } + + if (lexicalWrites != null) { + s.append(" (writes:"); + for (int i = 0; i < lexicalWrites.length; i++) { + s.append(" ").append(lexicalWrites[i].variableName).append(":").append( + getValueString(symbolTable, lexicalWrites[i].valueNumber)); + } + s.append(")"); + } + + return s.toString(); + } +} diff --git a/com.ibm.wala.cast/source/java/com/ibm/wala/cast/ir/ssa/analysis/LiveAnalysis.java b/com.ibm.wala.cast/source/java/com/ibm/wala/cast/ir/ssa/analysis/LiveAnalysis.java index f83602bf0..17fe6ba00 100644 --- a/com.ibm.wala.cast/source/java/com/ibm/wala/cast/ir/ssa/analysis/LiveAnalysis.java +++ b/com.ibm.wala.cast/source/java/com/ibm/wala/cast/ir/ssa/analysis/LiveAnalysis.java @@ -1,317 +1,317 @@ -/****************************************************************************** - * Copyright (c) 2002 - 2006 IBM Corporation. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * IBM Corporation - initial API and implementation - *****************************************************************************/ -package com.ibm.wala.cast.ir.ssa.analysis; - -import java.util.Iterator; - -import com.ibm.wala.cfg.ControlFlowGraph; -import com.ibm.wala.dataflow.graph.AbstractMeetOperator; -import com.ibm.wala.dataflow.graph.BitVectorSolver; -import com.ibm.wala.dataflow.graph.BitVectorUnion; -import com.ibm.wala.dataflow.graph.IKilldallFramework; -import com.ibm.wala.dataflow.graph.ITransferFunctionProvider; -import com.ibm.wala.fixpoint.BitVectorVariable; -import com.ibm.wala.fixpoint.UnaryOperator; -import com.ibm.wala.ssa.IR; -import com.ibm.wala.ssa.ISSABasicBlock; -import com.ibm.wala.ssa.SSAInstruction; -import com.ibm.wala.ssa.SSAPhiInstruction; -import com.ibm.wala.ssa.SymbolTable; -import com.ibm.wala.util.CancelException; -import com.ibm.wala.util.CancelRuntimeException; -import com.ibm.wala.util.debug.Assertions; -import com.ibm.wala.util.graph.Graph; -import com.ibm.wala.util.graph.impl.GraphInverter; -import com.ibm.wala.util.intset.BitVector; -import com.ibm.wala.util.intset.BitVectorIntSet; -import com.ibm.wala.util.intset.IntSet; - -/** - * @author Julian Dolby - * - * Live-value analysis for a method's IR (or {@link ControlFlowGraph} and {@link SymbolTable}) using a {@link IKilldallFramework} - * based implementation. - * - * Pre-requisites - * - Knowledge of SSA form: control flow graphs, basic blocks, Phi instructions - * - Knowledge of data flow analysis theory: see http://en.wikipedia.org/wiki/Data_flow_analysis - * - * Implementation notes: - * - * - The solver uses node transfer functions only. - * - Performance: inverts the CFG to traverse backwards (backward analysis). - */ -public class LiveAnalysis { - - public interface Result { - boolean isLiveEntry(ISSABasicBlock bb, int valueNumber); - - boolean isLiveExit(ISSABasicBlock bb, int valueNumber); - - BitVector getLiveBefore(int instr); - } - - /** - * - */ - public static Result perform(IR ir) { - return perform(ir.getControlFlowGraph(), ir.getSymbolTable()); - } - - /** - * - */ - public static Result perform(final ControlFlowGraph cfg, final SymbolTable symtab) { - return perform(cfg, symtab, new BitVector()); - } - - /** - * @param considerLiveAtExit given set (of variables) to consider to be live after the exit. - * - * todo: used once in {@link com.ibm.wala.cast.ir.ssa.SSAConversion}; Explain better the purpose. - */ - public static Result perform(final ControlFlowGraph cfg, final SymbolTable symtab, final BitVector considerLiveAtExit) { - final BitVectorIntSet liveAtExit = new BitVectorIntSet(considerLiveAtExit); - final SSAInstruction[] instructions = (SSAInstruction[]) cfg.getInstructions(); - - /** - * Gen/kill operator specific to exit basic blocks - */ - final class ExitBlockGenKillOperator extends UnaryOperator { - public String toString() { - return "ExitGenKill"; - } - - public boolean equals(Object o) { - return o == this; - } - - public int hashCode() { - return 37721; - } - - /** - * Evaluate the transfer between two nodes in the flow graph within an exit block. - */ - public byte evaluate(BitVectorVariable lhs, BitVectorVariable rhs) { - boolean changed = lhs.getValue() == null ? !considerLiveAtExit.isZero() : !lhs.getValue().sameValue(liveAtExit); - - lhs.addAll(considerLiveAtExit); - - return changed ? CHANGED : NOT_CHANGED; - } - } - - /** - * Gen/kill operator for a regular basic block. - */ - final class BlockValueGenKillOperator extends UnaryOperator { - private final ISSABasicBlock block; - - BlockValueGenKillOperator(ISSABasicBlock block) { - this.block = block; - } - - public String toString() { - return "GenKill:" + block; - } - - public boolean equals(Object o) { - return (o instanceof BlockValueGenKillOperator) && ((BlockValueGenKillOperator) o).block.equals(block); - } - - public int hashCode() { - return block.hashCode() * 17; - } - - /** - * Kills the definitions (variables written to). - */ - private void processDefs(SSAInstruction inst, BitVector bits) { - for (int j = 0; j < inst.getNumberOfDefs(); j++) { - bits.clear(inst.getDef(j)); - } - } - - /** - * Generates variables that are read (skips constants). - */ - private void processUses(SSAInstruction inst, BitVector bits) { - for (int j = 0; j < inst.getNumberOfUses(); j++) { - assert inst.getUse(j) != -1 : inst.toString(); - if (!symtab.isConstant(inst.getUse(j))) { - bits.set(inst.getUse(j)); - } - } - } - - /** - * Evaluate the transfer between two nodes in the flow graph within one basic block. - */ - public byte evaluate(BitVectorVariable lhs, BitVectorVariable rhs) { - // Calculate here the result of the transfer - BitVectorIntSet bits = new BitVectorIntSet(); - - IntSet s = rhs.getValue(); - if (s != null) { - bits.addAll(s); - } - // Include all uses generated by the current basic block into the successor's Phi instructions todo: rephrase - for (Iterator succBBs = cfg.getSuccNodes(block); succBBs.hasNext();) { - ISSABasicBlock succBB = succBBs.next(); - - int rval = com.ibm.wala.cast.ir.cfg.Util.whichPred(cfg, succBB, block); - for (Iterator sphis = succBB.iteratePhis(); sphis.hasNext();) { - bits.add(sphis.next().getUse(rval)); - } - } - // For all instructions, in reverse order, 'kill' variables written to and 'gen' variables read. - for (int i = block.getLastInstructionIndex(); i >= block.getFirstInstructionIndex(); i--) { - SSAInstruction inst = instructions[i]; - if (inst != null) { - processDefs(inst, bits.getBitVector()); - processUses(inst, bits.getBitVector()); - } - } - // 'kill' the variables defined by the Phi instructions in the current block. - for (Iterator SS = block.iteratePhis(); SS.hasNext();) { - processDefs(SS.next(), bits.getBitVector()); - } - - BitVectorVariable U = new BitVectorVariable(); - U.addAll(bits.getBitVector()); - - if (!lhs.sameValue(U)) { - lhs.copyState(U); - return CHANGED; - } else { - return NOT_CHANGED; - } - } - } - - /** - * Create the solver - */ - final BitVectorSolver S = new BitVectorSolver(new IKilldallFramework() { - private final Graph G = GraphInverter.invert(cfg); - - public Graph getFlowGraph() { - return G; - } - - public ITransferFunctionProvider getTransferFunctionProvider() { - return new ITransferFunctionProvider() { - - public boolean hasNodeTransferFunctions() { - return true; - } - - public boolean hasEdgeTransferFunctions() { - return false; - } - - /** - * Create the specialized operator for regular and exit basic blocks. - */ - public UnaryOperator getNodeTransferFunction(ISSABasicBlock node) { - if (node.isExitBlock()) { - return new ExitBlockGenKillOperator(); - } else { - return new BlockValueGenKillOperator(node); - } - } - - public UnaryOperator getEdgeTransferFunction(ISSABasicBlock s, ISSABasicBlock d) { - Assertions.UNREACHABLE(); - return null; - } - - /** - * Live analysis uses 'union' as 'meet operator' - */ - public AbstractMeetOperator getMeetOperator() { - return BitVectorUnion.instance(); - } - }; - } - }); - - /** - * Solve the analysis problem - */ - try { - S.solve(null); - } catch (CancelException e) { - throw new CancelRuntimeException(e); - } - - /** - * Prepare the lazy result with a closure. - */ - return new Result() { - - public String toString() { - StringBuffer s = new StringBuffer(); - for (int i = 0; i < cfg.getNumberOfNodes(); i++) { - ISSABasicBlock bb = cfg.getNode(i); - s.append("live entering ").append(bb).append(":").append(S.getOut(bb)).append("\n"); - s.append("live exiting ").append(bb).append(":").append(S.getIn(bb)).append("\n"); - } - - return s.toString(); - } - - public boolean isLiveEntry(ISSABasicBlock bb, int valueNumber) { - return S.getOut(bb).get(valueNumber); - } - - public boolean isLiveExit(ISSABasicBlock bb, int valueNumber) { - return S.getIn(bb).get(valueNumber); - } - - /** - * Calculate set of variables live before instruction - * @param instr - * - * @see - * how the 'in' and 'out' variable sets work - */ - public BitVector getLiveBefore(int instr) { - ISSABasicBlock bb = cfg.getBlockForInstruction(instr); - - // Start with the variables live at the 'in' of the basic block of the instruction. todo??? - BitVectorIntSet bits = new BitVectorIntSet(); - IntSet s = S.getIn(bb).getValue(); - if (s != null) { - bits.addAll(s); - } - // For all instructions in the basic block, going backwards, from the last, - // up to the desired instruction, 'kill' written variables and 'gen' read variables. - for (int i = bb.getLastInstructionIndex(); i >= instr; i--) { - SSAInstruction inst = instructions[i]; - if (inst != null) { - for (int j = 0; j < inst.getNumberOfDefs(); j++) { - bits.remove(inst.getDef(j)); - } - for (int j = 0; j < inst.getNumberOfUses(); j++) { - if (!symtab.isConstant(inst.getUse(j))) { - bits.add(inst.getUse(j)); - } - } - } - } - - return bits.getBitVector(); - } - }; - } -} +/****************************************************************************** + * Copyright (c) 2002 - 2006 IBM Corporation. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *****************************************************************************/ +package com.ibm.wala.cast.ir.ssa.analysis; + +import java.util.Iterator; + +import com.ibm.wala.cfg.ControlFlowGraph; +import com.ibm.wala.dataflow.graph.AbstractMeetOperator; +import com.ibm.wala.dataflow.graph.BitVectorSolver; +import com.ibm.wala.dataflow.graph.BitVectorUnion; +import com.ibm.wala.dataflow.graph.IKilldallFramework; +import com.ibm.wala.dataflow.graph.ITransferFunctionProvider; +import com.ibm.wala.fixpoint.BitVectorVariable; +import com.ibm.wala.fixpoint.UnaryOperator; +import com.ibm.wala.ssa.IR; +import com.ibm.wala.ssa.ISSABasicBlock; +import com.ibm.wala.ssa.SSAInstruction; +import com.ibm.wala.ssa.SSAPhiInstruction; +import com.ibm.wala.ssa.SymbolTable; +import com.ibm.wala.util.CancelException; +import com.ibm.wala.util.CancelRuntimeException; +import com.ibm.wala.util.debug.Assertions; +import com.ibm.wala.util.graph.Graph; +import com.ibm.wala.util.graph.impl.GraphInverter; +import com.ibm.wala.util.intset.BitVector; +import com.ibm.wala.util.intset.BitVectorIntSet; +import com.ibm.wala.util.intset.IntSet; + +/** + * @author Julian Dolby + * + * Live-value analysis for a method's IR (or {@link ControlFlowGraph} and {@link SymbolTable}) using a {@link IKilldallFramework} + * based implementation. + * + * Pre-requisites + * - Knowledge of SSA form: control flow graphs, basic blocks, Phi instructions + * - Knowledge of data flow analysis theory: see http://en.wikipedia.org/wiki/Data_flow_analysis + * + * Implementation notes: + * + * - The solver uses node transfer functions only. + * - Performance: inverts the CFG to traverse backwards (backward analysis). + */ +public class LiveAnalysis { + + public interface Result { + boolean isLiveEntry(ISSABasicBlock bb, int valueNumber); + + boolean isLiveExit(ISSABasicBlock bb, int valueNumber); + + BitVector getLiveBefore(int instr); + } + + /** + * + */ + public static Result perform(IR ir) { + return perform(ir.getControlFlowGraph(), ir.getSymbolTable()); + } + + /** + * + */ + public static Result perform(final ControlFlowGraph cfg, final SymbolTable symtab) { + return perform(cfg, symtab, new BitVector()); + } + + /** + * @param considerLiveAtExit given set (of variables) to consider to be live after the exit. + * + * todo: used once in {@link com.ibm.wala.cast.ir.ssa.SSAConversion}; Explain better the purpose. + */ + public static Result perform(final ControlFlowGraph cfg, final SymbolTable symtab, final BitVector considerLiveAtExit) { + final BitVectorIntSet liveAtExit = new BitVectorIntSet(considerLiveAtExit); + final SSAInstruction[] instructions = (SSAInstruction[]) cfg.getInstructions(); + + /** + * Gen/kill operator specific to exit basic blocks + */ + final class ExitBlockGenKillOperator extends UnaryOperator { + public String toString() { + return "ExitGenKill"; + } + + public boolean equals(Object o) { + return o == this; + } + + public int hashCode() { + return 37721; + } + + /** + * Evaluate the transfer between two nodes in the flow graph within an exit block. + */ + public byte evaluate(BitVectorVariable lhs, BitVectorVariable rhs) { + boolean changed = lhs.getValue() == null ? !considerLiveAtExit.isZero() : !lhs.getValue().sameValue(liveAtExit); + + lhs.addAll(considerLiveAtExit); + + return changed ? CHANGED : NOT_CHANGED; + } + } + + /** + * Gen/kill operator for a regular basic block. + */ + final class BlockValueGenKillOperator extends UnaryOperator { + private final ISSABasicBlock block; + + BlockValueGenKillOperator(ISSABasicBlock block) { + this.block = block; + } + + public String toString() { + return "GenKill:" + block; + } + + public boolean equals(Object o) { + return (o instanceof BlockValueGenKillOperator) && ((BlockValueGenKillOperator) o).block.equals(block); + } + + public int hashCode() { + return block.hashCode() * 17; + } + + /** + * Kills the definitions (variables written to). + */ + private void processDefs(SSAInstruction inst, BitVector bits) { + for (int j = 0; j < inst.getNumberOfDefs(); j++) { + bits.clear(inst.getDef(j)); + } + } + + /** + * Generates variables that are read (skips constants). + */ + private void processUses(SSAInstruction inst, BitVector bits) { + for (int j = 0; j < inst.getNumberOfUses(); j++) { + assert inst.getUse(j) != -1 : inst.toString(); + if (!symtab.isConstant(inst.getUse(j))) { + bits.set(inst.getUse(j)); + } + } + } + + /** + * Evaluate the transfer between two nodes in the flow graph within one basic block. + */ + public byte evaluate(BitVectorVariable lhs, BitVectorVariable rhs) { + // Calculate here the result of the transfer + BitVectorIntSet bits = new BitVectorIntSet(); + + IntSet s = rhs.getValue(); + if (s != null) { + bits.addAll(s); + } + // Include all uses generated by the current basic block into the successor's Phi instructions todo: rephrase + for (Iterator succBBs = cfg.getSuccNodes(block); succBBs.hasNext();) { + ISSABasicBlock succBB = succBBs.next(); + + int rval = com.ibm.wala.cast.ir.cfg.Util.whichPred(cfg, succBB, block); + for (Iterator sphis = succBB.iteratePhis(); sphis.hasNext();) { + bits.add(sphis.next().getUse(rval)); + } + } + // For all instructions, in reverse order, 'kill' variables written to and 'gen' variables read. + for (int i = block.getLastInstructionIndex(); i >= block.getFirstInstructionIndex(); i--) { + SSAInstruction inst = instructions[i]; + if (inst != null) { + processDefs(inst, bits.getBitVector()); + processUses(inst, bits.getBitVector()); + } + } + // 'kill' the variables defined by the Phi instructions in the current block. + for (Iterator SS = block.iteratePhis(); SS.hasNext();) { + processDefs(SS.next(), bits.getBitVector()); + } + + BitVectorVariable U = new BitVectorVariable(); + U.addAll(bits.getBitVector()); + + if (!lhs.sameValue(U)) { + lhs.copyState(U); + return CHANGED; + } else { + return NOT_CHANGED; + } + } + } + + /** + * Create the solver + */ + final BitVectorSolver S = new BitVectorSolver(new IKilldallFramework() { + private final Graph G = GraphInverter.invert(cfg); + + public Graph getFlowGraph() { + return G; + } + + public ITransferFunctionProvider getTransferFunctionProvider() { + return new ITransferFunctionProvider() { + + public boolean hasNodeTransferFunctions() { + return true; + } + + public boolean hasEdgeTransferFunctions() { + return false; + } + + /** + * Create the specialized operator for regular and exit basic blocks. + */ + public UnaryOperator getNodeTransferFunction(ISSABasicBlock node) { + if (node.isExitBlock()) { + return new ExitBlockGenKillOperator(); + } else { + return new BlockValueGenKillOperator(node); + } + } + + public UnaryOperator getEdgeTransferFunction(ISSABasicBlock s, ISSABasicBlock d) { + Assertions.UNREACHABLE(); + return null; + } + + /** + * Live analysis uses 'union' as 'meet operator' + */ + public AbstractMeetOperator getMeetOperator() { + return BitVectorUnion.instance(); + } + }; + } + }); + + /** + * Solve the analysis problem + */ + try { + S.solve(null); + } catch (CancelException e) { + throw new CancelRuntimeException(e); + } + + /** + * Prepare the lazy result with a closure. + */ + return new Result() { + + public String toString() { + StringBuffer s = new StringBuffer(); + for (int i = 0; i < cfg.getNumberOfNodes(); i++) { + ISSABasicBlock bb = cfg.getNode(i); + s.append("live entering ").append(bb).append(":").append(S.getOut(bb)).append("\n"); + s.append("live exiting ").append(bb).append(":").append(S.getIn(bb)).append("\n"); + } + + return s.toString(); + } + + public boolean isLiveEntry(ISSABasicBlock bb, int valueNumber) { + return S.getOut(bb).get(valueNumber); + } + + public boolean isLiveExit(ISSABasicBlock bb, int valueNumber) { + return S.getIn(bb).get(valueNumber); + } + + /** + * Calculate set of variables live before instruction + * @param instr + * + * @see + * how the 'in' and 'out' variable sets work + */ + public BitVector getLiveBefore(int instr) { + ISSABasicBlock bb = cfg.getBlockForInstruction(instr); + + // Start with the variables live at the 'in' of the basic block of the instruction. todo??? + BitVectorIntSet bits = new BitVectorIntSet(); + IntSet s = S.getIn(bb).getValue(); + if (s != null) { + bits.addAll(s); + } + // For all instructions in the basic block, going backwards, from the last, + // up to the desired instruction, 'kill' written variables and 'gen' read variables. + for (int i = bb.getLastInstructionIndex(); i >= instr; i--) { + SSAInstruction inst = instructions[i]; + if (inst != null) { + for (int j = 0; j < inst.getNumberOfDefs(); j++) { + bits.remove(inst.getDef(j)); + } + for (int j = 0; j < inst.getNumberOfUses(); j++) { + if (!symtab.isConstant(inst.getUse(j))) { + bits.add(inst.getUse(j)); + } + } + } + } + + return bits.getBitVector(); + } + }; + } +} diff --git a/com.ibm.wala.cast/source/java/com/ibm/wala/cast/ir/translator/ArrayOpHandler.java b/com.ibm.wala.cast/source/java/com/ibm/wala/cast/ir/translator/ArrayOpHandler.java index 8dac4b32e..679fea673 100644 --- a/com.ibm.wala.cast/source/java/com/ibm/wala/cast/ir/translator/ArrayOpHandler.java +++ b/com.ibm.wala.cast/source/java/com/ibm/wala/cast/ir/translator/ArrayOpHandler.java @@ -1,10 +1,10 @@ -package com.ibm.wala.cast.ir.translator; - -import com.ibm.wala.cast.ir.translator.AstTranslator.WalkContext; -import com.ibm.wala.cast.tree.CAstNode; - -public interface ArrayOpHandler { - void doArrayRead(WalkContext context, int result, int arrayValue, CAstNode arrayRef, int[] dimValues); - - void doArrayWrite(WalkContext context, int arrayValue, CAstNode arrayRef, int[] dimValues, int rval); -} +package com.ibm.wala.cast.ir.translator; + +import com.ibm.wala.cast.ir.translator.AstTranslator.WalkContext; +import com.ibm.wala.cast.tree.CAstNode; + +public interface ArrayOpHandler { + void doArrayRead(WalkContext context, int result, int arrayValue, CAstNode arrayRef, int[] dimValues); + + void doArrayWrite(WalkContext context, int arrayValue, CAstNode arrayRef, int[] dimValues, int rval); +} diff --git a/com.ibm.wala.cast/source/java/com/ibm/wala/cast/ir/translator/AstTranslator.java b/com.ibm.wala.cast/source/java/com/ibm/wala/cast/ir/translator/AstTranslator.java index ef4586f4e..4be7fee9d 100644 --- a/com.ibm.wala.cast/source/java/com/ibm/wala/cast/ir/translator/AstTranslator.java +++ b/com.ibm.wala.cast/source/java/com/ibm/wala/cast/ir/translator/AstTranslator.java @@ -1,4270 +1,4270 @@ -/****************************************************************************** - * Copyright (c) 2002 - 2006 IBM Corporation. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * IBM Corporation - initial API and implementation - *****************************************************************************/ -package com.ibm.wala.cast.ir.translator; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.HashSet; -import java.util.Iterator; -import java.util.LinkedHashMap; -import java.util.LinkedHashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; - -import com.ibm.wala.cast.ir.ssa.AssignInstruction; -import com.ibm.wala.cast.ir.ssa.AstAssertInstruction; -import com.ibm.wala.cast.ir.ssa.AstConstants; -import com.ibm.wala.cast.ir.ssa.AstEchoInstruction; -import com.ibm.wala.cast.ir.ssa.AstGlobalRead; -import com.ibm.wala.cast.ir.ssa.AstGlobalWrite; -import com.ibm.wala.cast.ir.ssa.AstIsDefinedInstruction; -import com.ibm.wala.cast.ir.ssa.AstLexicalAccess; -import com.ibm.wala.cast.ir.ssa.AstLexicalAccess.Access; -import com.ibm.wala.cast.ir.ssa.AstLexicalRead; -import com.ibm.wala.cast.ir.ssa.AstLexicalWrite; -import com.ibm.wala.cast.ir.ssa.EachElementGetInstruction; -import com.ibm.wala.cast.ir.ssa.EachElementHasNextInstruction; -import com.ibm.wala.cast.ir.ssa.SSAConversion; -import com.ibm.wala.cast.loader.AstMethod.DebuggingInformation; -import com.ibm.wala.cast.loader.AstMethod.LexicalInformation; -import com.ibm.wala.cast.loader.CAstAbstractLoader; -import com.ibm.wala.cast.tree.CAstControlFlowMap; -import com.ibm.wala.cast.tree.CAstEntity; -import com.ibm.wala.cast.tree.CAstNode; -import com.ibm.wala.cast.tree.CAstSourcePositionMap; -import com.ibm.wala.cast.tree.CAstSourcePositionMap.Position; -import com.ibm.wala.cast.tree.CAstSymbol; -import com.ibm.wala.cast.tree.CAstType; -import com.ibm.wala.cast.tree.impl.CAstCloner; -import com.ibm.wala.cast.tree.impl.CAstImpl; -import com.ibm.wala.cast.tree.impl.CAstOperator; -import com.ibm.wala.cast.tree.impl.CAstRewriter; -import com.ibm.wala.cast.tree.impl.CAstSymbolImpl; -import com.ibm.wala.cast.tree.impl.CAstSymbolImplBase; -import com.ibm.wala.cast.tree.visit.CAstVisitor; -import com.ibm.wala.cast.types.AstTypeReference; -import com.ibm.wala.cast.util.CAstPrinter; -import com.ibm.wala.cfg.AbstractCFG; -import com.ibm.wala.cfg.IBasicBlock; -import com.ibm.wala.classLoader.IClassLoader; -import com.ibm.wala.classLoader.IMethod; -import com.ibm.wala.classLoader.ModuleEntry; -import com.ibm.wala.shrikeBT.BinaryOpInstruction; -import com.ibm.wala.shrikeBT.ConditionalBranchInstruction; -import com.ibm.wala.shrikeBT.IBinaryOpInstruction; -import com.ibm.wala.shrikeBT.IConditionalBranchInstruction; -import com.ibm.wala.shrikeBT.IUnaryOpInstruction; -import com.ibm.wala.shrikeBT.ShiftInstruction; -import com.ibm.wala.ssa.SSAAbstractInvokeInstruction; -import com.ibm.wala.ssa.SSAGetCaughtExceptionInstruction; -import com.ibm.wala.ssa.SSAInstruction; -import com.ibm.wala.ssa.SSAInstructionFactory; -import com.ibm.wala.ssa.SSAMonitorInstruction; -import com.ibm.wala.ssa.SymbolTable; -import com.ibm.wala.types.FieldReference; -import com.ibm.wala.types.TypeName; -import com.ibm.wala.types.TypeReference; -import com.ibm.wala.util.collections.HashSetFactory; -import com.ibm.wala.util.collections.MapUtil; -import com.ibm.wala.util.collections.Pair; -import com.ibm.wala.util.debug.Assertions; -import com.ibm.wala.util.graph.INodeWithNumber; -import com.ibm.wala.util.graph.impl.SparseNumberedGraph; -import com.ibm.wala.util.intset.IntSet; -import com.ibm.wala.util.intset.IntSetUtil; -import com.ibm.wala.util.intset.MutableIntSet; -import com.ibm.wala.util.strings.Atom; -import com.ibm.wala.util.warnings.Warning; - -/** - * Common code to translate CAst to IR. Must be specialized by each language to - * handle semantics appropriately. - */ -public abstract class AstTranslator extends CAstVisitor implements ArrayOpHandler, TranslatorToIR { - - /** - * set to true to use new handling of lexical scoping - */ - public static final boolean NEW_LEXICAL = true; - - - /** - * does the language care about using type-appropriate default values? For - * Java, the answer is yes (ints should get a default value of 0, null for - * pointers, etc.). For JavaScript, the answer is no, as any variable can hold - * the value 'undefined'. - */ - protected abstract boolean useDefaultInitValues(); - - /** - * can lexical reads / writes access globals? - */ - protected abstract boolean treatGlobalsAsLexicallyScoped(); - - /** - * given accesses in a method to variables defined in an enclosing lexical - * scope, is it legal to read the variable into a local l once at the - * beginning of the method, operate on l through the method body (rather than - * performing separate lexical read / write operations), and write back the - * value in l (if necessary) at the end of the method? - */ - protected abstract boolean useLocalValuesForLexicalVars(); - - protected boolean topLevelFunctionsInGlobalScope() { - return true; - } - - /** - * for a block that catches all exceptions, what is the root exception type - * that it can catch? E.g., for Java, java.lang.Throwable - */ - protected abstract TypeReference defaultCatchType(); - - protected abstract TypeReference makeType(CAstType type); - - /** - * define a new (presumably nested) type. return true if type was successfully - * defined, false otherwise - */ - protected abstract boolean defineType(CAstEntity type, WalkContext wc); - - /** - * declare a new function, represented by N - */ - protected abstract void declareFunction(CAstEntity N, WalkContext context); - - /** - * fully define a function. invoked after all the code of the function has - * been processed - */ - protected abstract void defineFunction(CAstEntity N, WalkContext definingContext, AbstractCFG cfg, SymbolTable symtab, - boolean hasCatchBlock, TypeReference[][] caughtTypes, boolean hasMonitorOp, AstLexicalInformation lexicalInfo, - DebuggingInformation debugInfo); - - /** - * define a new field fieldEntity within topEntity - */ - protected abstract void defineField(CAstEntity topEntity, WalkContext context, CAstEntity fieldEntity); - - /** - * create the language-appropriate name for f - */ - protected abstract String composeEntityName(WalkContext parent, CAstEntity f); - - /** - * generate IR for a CAst throw expression, updating context.cfg() - */ - protected abstract void doThrow(WalkContext context, int exception); - - /** - * generate IR for a CAst array read, updating context.cfg() - */ - public abstract void doArrayRead(WalkContext context, int result, int arrayValue, CAstNode arrayRef, int[] dimValues); - - /** - * generate IR for a CAst array write, updating context.cfg() - */ - public abstract void doArrayWrite(WalkContext context, int arrayValue, CAstNode arrayRef, int[] dimValues, int rval); - - /** - * generate IR for a CAst field read, updating context.cfg() - */ - protected abstract void doFieldRead(WalkContext context, int result, int receiver, CAstNode elt, CAstNode parent); - - /** - * generate IR for a CAst field write, updating context.cfg() - */ - protected abstract void doFieldWrite(WalkContext context, int receiver, CAstNode elt, CAstNode parent, int rval); - - /** - * generate IR for a CAst function expression, updating context.cfg() - */ - protected abstract void doMaterializeFunction(CAstNode node, WalkContext context, int result, int exception, CAstEntity fn); - - /** - * generate IR for a CAst new expression, updating context.cfg() - */ - protected abstract void doNewObject(WalkContext context, CAstNode newNode, int result, Object type, int[] arguments); - - /** - * generate IR for a CAst method call expression, updating context.cfg() - */ - protected abstract void doCall(WalkContext context, CAstNode call, int result, int exception, CAstNode name, int receiver, - int[] arguments); - - /** - * used to generate instructions for array operations; defaults to this - */ - private ArrayOpHandler arrayOpHandler; - - protected boolean isExceptionLabel(Object label) { - if (label == null) - return false; - if (label instanceof Boolean) - return false; - if (label instanceof Number) - return false; - if (label == CAstControlFlowMap.SWITCH_DEFAULT) - return false; - return true; - } - - /** - * If this returns true, new global declarations get created for any attempt - * to access a non-existent variable (believe it or not, JavaScript actually - * does this!) - */ - protected boolean hasImplicitGlobals() { - return false; - } - - /** - * If this returns true, then attempts to lookup non-existent names return - * `null' rather than tripping an assertion. This can be used when special - * handling is needed for built-in names. (PHP does this) - */ - protected boolean hasSpecialUndeclaredVariables() { - return false; - } - - /** - * some languages let you omit initialization of certain fields when writing - * an object literal (e.g., PHP). This method should be overridden to handle - * such cases. - */ - protected void handleUnspecifiedLiteralKey(WalkContext context, CAstNode objectLiteralNode, int unspecifiedLiteralIndex, - CAstVisitor visitor) { - Assertions.UNREACHABLE(); - } - - /** - * generate prologue code for each function body - */ - protected void doPrologue(WalkContext context) { - // if we are SSA converting lexical accesses, add a placeholder instruction - // eventually (via mutation of its Access array) reads all relevant lexical - // variables at the beginning of the method. - if (useLocalValuesForLexicalVars()) { - context.cfg().addInstruction(new AstLexicalRead(new Access[0])); - } else { - // perform a lexical write to copy the value stored in the local - // associated with each parameter to the lexical name - final CAstEntity entity = context.top(); - Set exposedNames = entity2ExposedNames.get(entity); - if (exposedNames != null) { - for (String arg : entity.getArgumentNames()) { - if (exposedNames.contains(arg)) { - final Scope currentScope = context.currentScope(); - Symbol symbol = currentScope.lookup(arg); - assert symbol.getDefiningScope() == currentScope; - int argVN = symbol.valueNumber(); - Access A = new Access(arg, context.getEntityName(entity), argVN); - context.cfg().addInstruction(new AstLexicalWrite(A)); - } - } - } - } - } - - /** - * generate IR for call modeling creation of primitive value, updating - * context.cfg() - */ - protected abstract void doPrimitive(int resultVal, WalkContext context, CAstNode primitiveCall); - - /** - * get the value number for a name defined locally (i.e., within the current - * method) by looking up the name in context.currentScope(). Note that the - * caller is responsible for ensuring that name is defined in the local scope. - */ - protected int doLocalRead(WalkContext context, String name) { - if (!useLocalValuesForLexicalVars()) { - CAstEntity entity = context.top(); - Set exposed = entity2ExposedNames.get(entity); - if (exposed != null && exposed.contains(name)) { - return doLexReadHelper(context, name); - } - } - return context.currentScope().lookup(name).valueNumber(); - } - - /** - * add an {@link AssignInstruction} to context.cfg() that copies rval to the - * value number of local nm. Note that the caller is responsible for ensuring - * that nm is defined in the local scope. - */ - protected void doLocalWrite(WalkContext context, String nm, int rval) { - if (!useLocalValuesForLexicalVars()) { - CAstEntity entity = context.top(); - Set exposed = entity2ExposedNames.get(entity); - if (exposed != null && exposed.contains(nm)) { - // use a lexical write - doLexicallyScopedWrite(context, nm, rval); - return; - } - } - int lval = context.currentScope().lookup(nm).valueNumber(); - if (lval != rval) { - context.cfg().addInstruction(new AssignInstruction(lval, rval)); - } - } - - /** - * Note that the caller is responsible for ensuring that name is defined in a - * lexical scope. - * - * @param node - * the AST node representing the read - * @param context - * @param name - * @return - */ - protected int doLexicallyScopedRead(CAstNode node, WalkContext context, final String name) { - return doLexReadHelper(context, name); - } - - /** - * we only have this method to avoid having to pass a node parameter at other - * call sites, as would be required for - * {@link #doLexicallyScopedRead(CAstNode, WalkContext, String)} - */ - private int doLexReadHelper(WalkContext context, final String name) { - Symbol S = context.currentScope().lookup(name); - Scope definingScope = S.getDefiningScope(); - CAstEntity E = definingScope.getEntity(); - // record in declaring scope that the name is exposed to a nested scope -//<<<<<<< .mine -// Symbol S = context.currentScope().lookup(name); -// CAstEntity E = S.getDefiningScope().getEntity(); -// addExposedName(E, E, name, S.getDefiningScope().lookup(name).valueNumber(), false, context); -//======= - addExposedName(E, E, name, definingScope.lookup(name).valueNumber(), false, context); -//>>>>>>> .r4421 - - final String entityName = context.getEntityName(E); - if (useLocalValuesForLexicalVars()) { - // lexically-scoped variables can be given a single vn in a method -//<<<<<<< .mine -// Access A = new Access(name, context.getEntityName(E), vn); -//======= -//>>>>>>> .r4421 - -//<<<<<<< .mine - // (context.top() is current entity) - // record the name as exposed for the current entity, since if the name is - // updated via a call to a nested function, SSA for the current entity may - // need to be updated with the new definition -// addExposedName(context.top(), E, name, vn, false, context); -//======= - markExposedInEnclosingEntities(context, name, definingScope, E, entityName, false); -//>>>>>>> .r4421 - -//<<<<<<< .mine - // record the access; later, the Accesses in the instruction - // defining vn will be adjusted based on this information; see - // patchLexicalAccesses() -// addAccess(context, context.top(), A); -//======= - return S.valueNumber(); -//>>>>>>> .r4421 - - } else { - // lexically-scoped variables should be read from their scope each time - int result = context.currentScope().allocateTempValue(); -//<<<<<<< .mine -// Access A = new Access(name, context.getEntityName(E), result); -//======= - Access A = new Access(name, entityName, result); -//>>>>>>> .r4421 - context.cfg().addInstruction(new AstLexicalRead(A)); - markExposedInEnclosingEntities(context, name, definingScope, E, entityName, false); - return result; - } - } - - /** - * record name as exposed for the current entity and for all enclosing - * entities up to that of the defining scope, since if the name is updated via - * a call to a nested function, SSA for these entities may need to be updated - * with the new definition - * - * @param context - * @param name - * @param definingScope - * @param E - * @param entityName - * @param isWrite - */ - private void markExposedInEnclosingEntities(WalkContext context, final String name, Scope definingScope, CAstEntity E, - final String entityName, boolean isWrite) { - Scope curScope = context.currentScope(); - while (!curScope.equals(definingScope)) { - final Symbol curSymbol = curScope.lookup(name); - final int vn = curSymbol.valueNumber(); - final Access A = new Access(name, entityName, vn); - final CAstEntity entity = curScope.getEntity(); - if (entity != definingScope.getEntity()) { - addExposedName(entity, E, name, vn, isWrite, context); - // record the access; later, the Accesses in the instruction - // defining vn will be adjusted based on this information; see - // patchLexicalAccesses() - addAccess(context, entity, A); - } - curScope = curScope.getParent(); - } - } - - /** - * Note that the caller is responsible for ensuring that name is defined in a - * lexical scope. - * - */ - protected void doLexicallyScopedWrite(WalkContext context, String name, int rval) { - Symbol S = context.currentScope().lookup(name); - Scope definingScope = S.getDefiningScope(); - CAstEntity E = definingScope.getEntity(); - // record in declaring scope that the name is exposed to a nested scope - addExposedName(E, E, name, definingScope.lookup(name).valueNumber(), true, context); - - if (useLocalValuesForLexicalVars()) { - // lexically-scoped variables can be given a single vn in a method - - markExposedInEnclosingEntities(context, name, definingScope, E, context.getEntityName(E), true); - - context.cfg().addInstruction(new AssignInstruction(S.valueNumber(), rval)); - // we add write instructions at every access for now - // eventually, we may restructure the method to do a single combined write - // before exit - Access A = new Access(name, context.getEntityName(E), rval); - context.cfg().addInstruction(new AstLexicalWrite(A)); - - } else { - // lexically-scoped variables must be written in their scope each time - Access A = new Access(name, context.getEntityName(E), rval); - context.cfg().addInstruction(new AstLexicalWrite(A)); - markExposedInEnclosingEntities(context, name, definingScope, E, context.getEntityName(E), true); - } - } - - /** - * generate instructions for a read of a global - */ - protected int doGlobalRead(CAstNode node, WalkContext context, String name) { - Symbol S = context.currentScope().lookup(name); - - // Global variables can be treated as lexicals defined in the CG root, or - if (treatGlobalsAsLexicallyScoped()) { - - // lexically-scoped variables can be given a single vn in a method, or - if (useLocalValuesForLexicalVars()) { - int vn = S.valueNumber(); - Access A = new Access(name, null, vn); - - addExposedName(context.top(), null, name, vn, false, context); - addAccess(context, context.top(), A); - - return vn; - - // lexically-scoped variables can be read from their scope each time - } else { - int result = context.currentScope().allocateTempValue(); - Access A = new Access(name, null, result); - context.cfg().addInstruction(new AstLexicalRead(A)); - addAccess(context, context.top(), A); - return result; - } - - // globals can be treated as a single static location - } else { - int result = context.currentScope().allocateTempValue(); - FieldReference global = makeGlobalRef(name); - context.cfg().addInstruction(new AstGlobalRead(result, global)); - return result; - } - } - - /** - * generate instructions for a write of a global - */ - protected void doGlobalWrite(WalkContext context, String name, int rval) { - Symbol S = context.currentScope().lookup(name); - - // Global variables can be treated as lexicals defined in the CG root, or - if (treatGlobalsAsLexicallyScoped()) { - - // lexically-scoped variables can be given a single vn in a method, or - if (useLocalValuesForLexicalVars()) { - int vn = S.valueNumber(); - Access A = new Access(name, null, vn); - - addExposedName(context.top(), null, name, vn, true, context); - addAccess(context, context.top(), A); - - context.cfg().addInstruction(new AssignInstruction(vn, rval)); - context.cfg().addInstruction(new AstLexicalWrite(A)); - - // lexically-scoped variables can be read from their scope each time - } else { - Access A = new Access(name, null, rval); - context.cfg().addInstruction(new AstLexicalWrite(A)); - addAccess(context, context.top(), A); - } - - // globals can be treated as a single static location - } else { - FieldReference global = makeGlobalRef(name); - context.cfg().addInstruction(new AstGlobalWrite(global, rval)); - } - } - - /** - * generate instructions to check if ref has field, storing answer in result - */ - protected void doIsFieldDefined(WalkContext context, int result, int ref, CAstNode field) { - Assertions.UNREACHABLE(); - } - - /** - * creates a reference to a global named globalName. the declaring type and - * type of the global are both the root type. - */ - protected FieldReference makeGlobalRef(String globalName) { - TypeReference rootTypeRef = TypeReference.findOrCreate(loader.getReference(), AstTypeReference.rootTypeName); - return FieldReference.findOrCreate(rootTypeRef, Atom.findOrCreateUnicodeAtom("global " + globalName), rootTypeRef); - } - - protected final IClassLoader loader; - - /** - * for handling languages that let you include other source files named - * statically (e.g., ABAP) - */ - protected final Map namedEntityResolver; - - protected final SSAInstructionFactory insts; - - protected AstTranslator(IClassLoader loader, Map namedEntityResolver, ArrayOpHandler arrayOpHandler) { - this.loader = loader; - this.namedEntityResolver = namedEntityResolver; - this.arrayOpHandler = arrayOpHandler!=null? arrayOpHandler: this; - this.insts = loader.getInstructionFactory(); - } - - protected AstTranslator(IClassLoader loader, Map namedEntityResolver) { - this(loader, namedEntityResolver, null); - } - - protected AstTranslator(IClassLoader loader) { - this(loader, null); - } - - /** - * for keeping position information for the generated SSAInstructions and SSA - * locals - */ - private static class AstDebuggingInformation implements DebuggingInformation { - private Position codeBodyPosition; - - private String[][] valueNumberNames; - - private Position[] instructionPositions; - - AstDebuggingInformation(Position codeBodyPosition, Position[] instructionPositions, String[] names) { - this.codeBodyPosition = codeBodyPosition; - - this.instructionPositions = instructionPositions; - - valueNumberNames = new String[names.length][]; - for (int i = 0; i < names.length; i++) { - if (names[i] != null) { - valueNumberNames[i] = new String[] { names[i] }; - } else { - valueNumberNames[i] = new String[0]; - } - } - } - - public Position getCodeBodyPosition() { - return codeBodyPosition; - } - - public Position getInstructionPosition(int instructionOffset) { - return instructionPositions[instructionOffset]; - } - - public String[][] getSourceNamesForValues() { - return valueNumberNames; - } - } - - public static final boolean DEBUG_ALL = false; - - public static final boolean DEBUG_TOP = DEBUG_ALL || false; - - public static final boolean DEBUG_CFG = DEBUG_ALL || false; - - public static final boolean DEBUG_NAMES = DEBUG_ALL || false; - - public static final boolean DEBUG_LEXICAL = DEBUG_ALL || false; - - /** - * basic block implementation used in the CFGs constructed during the - * IR-generating AST traversal - */ - protected final static class PreBasicBlock implements INodeWithNumber, IBasicBlock { - private static final int NORMAL = 0; - - private static final int HANDLER = 1; - - private static final int ENTRY = 2; - - private static final int EXIT = 3; - - private int kind = NORMAL; - - private int number = -1; - - private int firstIndex = -1; - - private int lastIndex = -2; - - private final List instructions = new ArrayList(); - - public int getNumber() { - return getGraphNodeId(); - } - - public int getGraphNodeId() { - return number; - } - - public void setGraphNodeId(int number) { - this.number = number; - } - - public int getFirstInstructionIndex() { - return firstIndex; - } - - void setFirstIndex(int firstIndex) { - this.firstIndex = firstIndex; - } - - public int getLastInstructionIndex() { - return lastIndex; - } - - void setLastIndex(int lastIndex) { - this.lastIndex = lastIndex; - } - - void makeExitBlock() { - kind = EXIT; - } - - void makeEntryBlock() { - kind = ENTRY; - } - - void makeHandlerBlock() { - kind = HANDLER; - } - - public boolean isEntryBlock() { - return kind == ENTRY; - } - - public boolean isExitBlock() { - return kind == EXIT; - } - - public boolean isHandlerBlock() { - return kind == HANDLER; - } - - public String toString() { - return "PreBB" + number + ":" + firstIndex + ".." + lastIndex; - } - - List instructions() { - return instructions; - } - - public boolean isCatchBlock() { - return (lastIndex > -1) && (instructions.get(0) instanceof SSAGetCaughtExceptionInstruction); - } - - public IMethod getMethod() { - return null; - } - - public Iterator iterator() { - return instructions.iterator(); - } - } - - protected final class UnwindState { - final CAstNode unwindAst; - - final WalkContext astContext; - - final CAstVisitor astVisitor; - - UnwindState(CAstNode unwindAst, WalkContext astContext, CAstVisitor astVisitor) { - this.unwindAst = unwindAst; - this.astContext = astContext; - this.astVisitor = astVisitor; - } - - public UnwindState getParent() { - return astContext.getUnwindState(); - } - - public int hashCode() { - return astContext.hashCode() * unwindAst.hashCode() * astVisitor.hashCode(); - } - - public boolean equals(Object o) { - if (o instanceof UnwindState) { - if (((UnwindState) o).unwindAst != unwindAst) - return false; - if (((UnwindState) o).astVisitor != astVisitor) - return false; - if (getParent() == null) { - return ((UnwindState) o).getParent() == null; - } else { - return getParent().equals(((UnwindState) o).getParent()); - } - } - - return false; - } - - boolean covers(UnwindState other) { - if (equals(other)) - return true; - if (getParent() != null) - return getParent().covers(other); - return false; - } - } - - /** - * holds the control-flow graph as it is being constructed. When construction - * is complete, information is stored in an {@link AstCFG} - */ - public final class IncipientCFG extends SparseNumberedGraph { - - protected class Unwind { - private final Map unwindData = new LinkedHashMap(); - - /** - * a cache of generated blocks - */ - private final Map>, PreBasicBlock> code = new LinkedHashMap>, PreBasicBlock>(); - - void setUnwindState(PreBasicBlock block, UnwindState context) { - unwindData.put(block, context); - } - - void setUnwindState(CAstNode node, UnwindState context) { - unwindData.put(nodeToBlock.get(node), context); - } - - /** - * When adding an edge from source to target, it is possible that certain - * exception-handling code needs to be executed before the control is - * actually transfered to target. This method determines if this is the - * case, and if so, it generates the exception handler blocks and adds an - * appropriate edge to the target. It returns the basic block that should - * be the target of the edge from source (target itself if there is no - * exception-handling code, the initial catch block otherwise) - */ - public PreBasicBlock findOrCreateCode(PreBasicBlock source, PreBasicBlock target, final boolean exception) { - UnwindState sourceContext = unwindData.get(source); - final CAstNode dummy = exception ? (new CAstImpl()).makeNode(CAstNode.EMPTY) : null; - - // no unwinding is needed, so jump to target block directly - if (sourceContext == null) - return target; - - WalkContext astContext = sourceContext.astContext; - UnwindState targetContext = null; - if (target != null) - targetContext = unwindData.get(target); - - // in unwind context, but catch in same (or inner) unwind context - if (targetContext != null && targetContext.covers(sourceContext)) - return target; - - Pair> key = Pair.make(sourceContext, Pair.make(target, exception)); - - if (code.containsKey(key)) { - return code.get(key); - - } else { - int e = -1; - PreBasicBlock currentBlock = getCurrentBlock(); - if (!isDeadBlock(currentBlock)) { - addInstruction(insts.GotoInstruction()); - newBlock(false); - } - PreBasicBlock startBlock = getCurrentBlock(); - if (exception) { - setCurrentBlockAsHandler(); - e = sourceContext.astContext.currentScope().allocateTempValue(); - addInstruction(insts.GetCaughtExceptionInstruction(startBlock.getNumber(), e)); - sourceContext.astContext.setCatchType(startBlock.getNumber(), defaultCatchType()); - } - - while (sourceContext != null && (targetContext == null || !targetContext.covers(sourceContext))) { - final CAstRewriter.Rewrite ast = (new CAstCloner(new CAstImpl()) { - protected CAstNode flowOutTo(Map, CAstNode> nodeMap, CAstNode oldSource, Object label, - CAstNode oldTarget, CAstControlFlowMap orig, CAstSourcePositionMap src) { - if (exception && !isExceptionLabel(label)) { - return dummy; - } else { - return oldTarget; - } - } - }).copy(sourceContext.unwindAst, sourceContext.astContext.getControlFlow(), sourceContext.astContext.getSourceMap(), - sourceContext.astContext.top().getNodeTypeMap(), sourceContext.astContext.top().getAllScopedEntities()); - sourceContext.astVisitor.visit(ast.newRoot(), new DelegatingContext(sourceContext.astContext) { - public CAstSourcePositionMap getSourceMap() { - return ast.newPos(); - } - - public CAstControlFlowMap getControlFlow() { - return ast.newCfg(); - } - }, sourceContext.astVisitor); - - sourceContext = sourceContext.getParent(); - } - - PreBasicBlock endBlock = getCurrentBlock(); - if (exception) { - addPreNode(dummy); - doThrow(astContext, e); - } else { - addInstruction(insts.GotoInstruction()); - } - newBlock(false); - - addEdge(currentBlock, getCurrentBlock()); - if (target != null) { - addEdge(endBlock, target); - - // `null' target is idiom for branch/throw to exit - } else { - addDelayedEdge(endBlock, exitMarker, exception); - } - - code.put(key, startBlock); - return startBlock; - } - } - } - - private Unwind unwind = null; - - private final List blocks = new ArrayList(); - - private final Map nodeToBlock = new LinkedHashMap(); - - private final Map>> delayedEdges = new LinkedHashMap>>(); - - private final Object exitMarker = new Object(); - - private final Set deadBlocks = new LinkedHashSet(); - - private final Set normalToExit = new LinkedHashSet(); - - private final Set exceptionalToExit = new LinkedHashSet(); - - private Position[] linePositions = new Position[10]; - - private boolean hasCatchBlock = false; - - /** - * does the method have any monitor operations? - */ - private boolean hasMonitorOp = false; - - private int currentInstruction = 0; - - private PreBasicBlock currentBlock; - - public int getCurrentInstruction() { - return currentInstruction; - } - - public PreBasicBlock getCurrentBlock() { - return currentBlock; - } - - boolean hasCatchBlock() { - return hasCatchBlock; - } - - boolean hasMonitorOp() { - return hasMonitorOp; - } - - void noteCatchBlock() { - hasCatchBlock = true; - } - - Position[] getLinePositionMap() { - return linePositions; - } - - /** - * create a new basic block, and set it as the current block. - * - * @param fallThruFromPrior - * should a fall-through edge be added from the previous block - * (value of currentBlock at entry)? if false, the newly created - * block is marked as a dead block, as it has no incoming edges. - * @return the new block - */ - public PreBasicBlock newBlock(boolean fallThruFromPrior) { - // optimization: if we have a fall-through from an empty block, just - // return the empty block - if (fallThruFromPrior && !currentBlock.isEntryBlock() && currentBlock.instructions().size() == 0) { - return currentBlock; - } - - PreBasicBlock previous = currentBlock; - currentBlock = new PreBasicBlock(); - addNode(currentBlock); - blocks.add(currentBlock); - - if (DEBUG_CFG) - System.err.println(("adding new block (node) " + currentBlock)); - if (fallThruFromPrior) { - if (DEBUG_CFG) - System.err.println(("adding fall-thru edge " + previous + " --> " + currentBlock)); - addEdge(previous, currentBlock); - } else { - deadBlocks.add(currentBlock); - } - - return currentBlock; - } - - /** - * record a delayed edge addition from src to dst. Edge will be added when - * appropriate; see {@link #checkForRealizedEdges(CAstNode)} and - * {@link #checkForRealizedExitEdges(PreBasicBlock)} - */ - private void addDelayedEdge(PreBasicBlock src, Object dst, boolean exception) { - MapUtil.findOrCreateSet(delayedEdges, dst).add(Pair.make(src, exception)); - } - - void makeEntryBlock(PreBasicBlock bb) { - bb.makeEntryBlock(); - } - - void makeExitBlock(PreBasicBlock bb) { - bb.makeExitBlock(); - - for (Iterator ps = getPredNodes(bb); ps.hasNext();) - normalToExit.add(ps.next()); - - // now that we have created the exit block, add the delayed edges to the - // exit - checkForRealizedExitEdges(bb); - } - - void setCurrentBlockAsHandler() { - currentBlock.makeHandlerBlock(); - } - - boolean hasDelayedEdges(CAstNode n) { - return delayedEdges.containsKey(n); - } - - /** - * given some n which is now mapped by nodeToBlock, add any delayed edges to - * n's block - */ - private void checkForRealizedEdges(CAstNode n) { - if (delayedEdges.containsKey(n)) { - for (Iterator> ss = delayedEdges.get(n).iterator(); ss.hasNext();) { - Pair s = ss.next(); - PreBasicBlock src = s.fst; - boolean exception = s.snd; - if (unwind == null) { - addEdge(src, nodeToBlock.get(n)); - } else { - PreBasicBlock target = nodeToBlock.get(n); - addEdge(src, unwind.findOrCreateCode(src, target, exception)); - } - } - - delayedEdges.remove(n); - } - } - - /** - * add any delayed edges to the exit block - */ - private void checkForRealizedExitEdges(PreBasicBlock exitBlock) { - if (delayedEdges.containsKey(exitMarker)) { - for (Iterator> ss = delayedEdges.get(exitMarker).iterator(); ss.hasNext();) { - Pair s = ss.next(); - PreBasicBlock src = s.fst; - boolean exception = s.snd; - addEdge(src, exitBlock); - if (exception) - exceptionalToExit.add(src); - else - normalToExit.add(src); - } - - delayedEdges.remove(exitMarker); - } - } - - private void setUnwindState(CAstNode node, UnwindState context) { - if (unwind == null) - unwind = new Unwind(); - unwind.setUnwindState(node, context); - } - - public void addPreNode(CAstNode n) { - addPreNode(n, null); - } - - /** - * associate n with the current block, and update the current unwind state - */ - public void addPreNode(CAstNode n, UnwindState context) { - if (DEBUG_CFG) - System.err.println(("adding pre-node " + n)); - nodeToBlock.put(n, currentBlock); - deadBlocks.remove(currentBlock); - if (context != null) - setUnwindState(n, context); - // now that we've associated n with a block, add associated delayed edges - checkForRealizedEdges(n); - } - - public void addPreEdge(CAstNode src, CAstNode dst, boolean exception) { - assert nodeToBlock.containsKey(src); - addPreEdge(nodeToBlock.get(src), dst, exception); - } - - /** - * if dst is associated with a basic block b, add an edge from src to b. - * otherwise, record the edge addition as delayed. - */ - public void addPreEdge(PreBasicBlock src, CAstNode dst, boolean exception) { - if (dst == CAstControlFlowMap.EXCEPTION_TO_EXIT) { - assert exception; - addPreEdgeToExit(src, exception); - } else if (nodeToBlock.containsKey(dst)) { - PreBasicBlock target = nodeToBlock.get(dst); - if (DEBUG_CFG) - System.err.println(("adding pre-edge " + src + " --> " + dst)); - if (unwind == null) { - addEdge(src, target); - } else { - addEdge(src, unwind.findOrCreateCode(src, target, exception)); - } - } else { - if (DEBUG_CFG) - System.err.println(("adding delayed pre-edge " + src + " --> " + dst)); - addDelayedEdge(src, dst, exception); - } - } - - public void addPreEdgeToExit(CAstNode src, boolean exception) { - assert nodeToBlock.containsKey(src); - addPreEdgeToExit(nodeToBlock.get(src), exception); - } - - public void addPreEdgeToExit(PreBasicBlock src, boolean exception) { - if (unwind != null) { - PreBasicBlock handlers = unwind.findOrCreateCode(src, null, exception); - if (handlers != null) { - addEdge(src, handlers); - return; - } - } - - addDelayedEdge(src, exitMarker, exception); - } - - public void addEdge(PreBasicBlock src, PreBasicBlock dst) { - super.addEdge(src, dst); - deadBlocks.remove(dst); - } - - boolean isDeadBlock(PreBasicBlock block) { - return deadBlocks.contains(block); - } - - public PreBasicBlock getBlock(CAstNode n) { - return nodeToBlock.get(n); - } - - /** - * mark the current position as the position for the instruction - */ - private void noteLinePosition(int instruction) { - if (linePositions.length < (instruction + 1)) { - Position[] newData = new Position[instruction * 2 + 1]; - System.arraycopy(linePositions, 0, newData, 0, linePositions.length); - linePositions = newData; - } - - linePositions[instruction] = getCurrentPosition(); - } - - public void addInstruction(SSAInstruction n) { - deadBlocks.remove(currentBlock); - - int inst = currentInstruction++; - - noteLinePosition(inst); - - if (currentBlock.instructions().size() == 0) { - currentBlock.setFirstIndex(inst); - } else { - assert !(n instanceof SSAGetCaughtExceptionInstruction); - } - - if (DEBUG_CFG) { - System.err.println(("adding " + n + " at " + inst + " to " + currentBlock)); - } - - if (n instanceof SSAMonitorInstruction) { - hasMonitorOp = true; - } - - currentBlock.instructions().add(n); - - currentBlock.setLastIndex(inst); - } - } - - /** - * data structure for the final CFG for a method, based on the information in - * an {@link IncipientCFG} - */ - protected final static class AstCFG extends AbstractCFG { - private final SSAInstruction[] instructions; - - private final int[] instructionToBlockMap; - - private final String functionName; - - private final SymbolTable symtab; - - AstCFG(CAstEntity n, IncipientCFG icfg, SymbolTable symtab) { - super(null); - List blocks = icfg.blocks; - - this.symtab = symtab; - functionName = n.getName(); - instructionToBlockMap = new int[blocks.size()]; - - for (int i = 0; i < blocks.size(); i++) - instructionToBlockMap[i] = blocks.get(i).getLastInstructionIndex(); - - for (int i = 0; i < blocks.size(); i++) { - PreBasicBlock block = blocks.get(i); - this.addNode(block); - if (block.isCatchBlock()) { - setCatchBlock(i); - } - - if (DEBUG_CFG) - System.err.println(("added " + blocks.get(i) + " to final CFG as " + getNumber(blocks.get(i)))); - } - if (DEBUG_CFG) - System.err.println((getMaxNumber() + " blocks total")); - - init(); - - for (int i = 0; i < blocks.size(); i++) { - PreBasicBlock src = blocks.get(i); - for (Iterator j = icfg.getSuccNodes(src); j.hasNext();) { - PreBasicBlock dst = (PreBasicBlock) j.next(); - if (isCatchBlock(dst.getNumber()) || (dst.isExitBlock() && icfg.exceptionalToExit.contains(src))) { - if (DEBUG_CFG) - System.err.println(("exceptonal edge " + src + " -> " + dst)); - addExceptionalEdge(src, dst); - } - - if (dst.isExitBlock() ? icfg.normalToExit.contains(src) : !isCatchBlock(dst.getNumber())) { - if (DEBUG_CFG) - System.err.println(("normal edge " + src + " -> " + dst)); - addNormalEdge(src, dst); - } - } - } - - int x = 0; - instructions = new SSAInstruction[icfg.currentInstruction]; - for (int i = 0; i < blocks.size(); i++) { - List bi = blocks.get(i).instructions(); - for (int j = 0; j < bi.size(); j++) { - instructions[x++] = bi.get(j); - } - } - } - - public int hashCode() { - return functionName.hashCode(); - } - - public boolean equals(Object o) { - return (o instanceof AstCFG) && functionName.equals(((AstCFG) o).functionName); - } - - public PreBasicBlock getBlockForInstruction(int index) { - for (int i = 1; i < getNumberOfNodes() - 1; i++) - if (index <= instructionToBlockMap[i]) - return getNode(i); - - return null; - } - - public SSAInstruction[] getInstructions() { - return instructions; - } - - public int getProgramCounter(int index) { - return index; - } - - public String toString() { - SSAInstruction[] insts = (SSAInstruction[]) getInstructions(); - StringBuffer s = new StringBuffer("CAst CFG of " + functionName); - int params[] = symtab.getParameterValueNumbers(); - for (int i = 0; i < params.length; i++) - s.append(" ").append(params[i]); - s.append("\n"); - - for (int i = 0; i < getNumberOfNodes(); i++) { - PreBasicBlock bb = (PreBasicBlock) getNode(i); - s.append(bb).append("\n"); - - for (Iterator ss = getSuccNodes(bb); ss.hasNext();) - s.append(" -->" + ss.next() + "\n"); - - for (int j = bb.getFirstInstructionIndex(); j <= bb.getLastInstructionIndex(); j++) - if (insts[j] != null) - s.append(" " + insts[j].toString(symtab) + "\n"); - } - - s.append("-- END --"); - return s.toString(); - } - } - - public static enum ScopeType { - LOCAL, GLOBAL, SCRIPT, FUNCTION, TYPE - }; - - private static final boolean DEBUG = false; - - protected class FinalCAstSymbol implements CAstSymbol { - private final String _name; - - private FinalCAstSymbol(String _name) { - this._name = _name; - } - - public String name() { - return _name; - } - - public boolean isFinal() { - return true; - } - - public boolean isCaseInsensitive() { - return false; - } - - public boolean isInternalName() { - return false; - } - - public Object defaultInitValue() { - return null; - } - } - - public static class InternalCAstSymbol extends CAstSymbolImplBase { - public InternalCAstSymbol(String _name) { - super(_name, false, false, null); - } - - public InternalCAstSymbol(String _name, boolean _isFinal) { - super(_name, _isFinal, false, null); - } - - public InternalCAstSymbol(String _name, boolean _isFinal, boolean _isCaseInsensitive) { - super(_name, _isFinal, _isCaseInsensitive, null); - } - - public InternalCAstSymbol(String _name, boolean _isFinal, boolean _isCaseInsensitive, Object _defaultInitValue) { - super(_name, _isFinal, _isCaseInsensitive, _defaultInitValue); - } - - public boolean isInternalName() { - return true; - } - } - - /** - * interface for name information stored in a symbol table. - * - * @see Scope - */ - protected interface Symbol { - int valueNumber(); - - Scope getDefiningScope(); - - boolean isParameter(); - - Object constant(); - - void setConstant(Object s); - - boolean isFinal(); - - boolean isInternalName(); - - Object defaultInitValue(); - } - - /** - * a scope in the symbol table built during AST traversal - */ - public interface Scope { - - ScopeType type(); - - int allocateTempValue(); - - int getConstantValue(Object c); - - boolean isConstant(int valueNumber); - - Object getConstantObject(int valueNumber); - - void declare(CAstSymbol s); - - void declare(CAstSymbol s, int valueNumber); - - boolean isCaseInsensitive(String name); - - boolean contains(String name); - - Symbol lookup(String name); - - Iterator getAllNames(); - - int size(); - - boolean isGlobal(Symbol s); - - boolean isLexicallyScoped(Symbol s); - - CAstEntity getEntity(); - - Scope getParent(); - } - - private static abstract class AbstractSymbol implements Symbol { - private Object constantValue; - - private boolean isFinalValue; - - private final Scope definingScope; - - private Object defaultValue; - - AbstractSymbol(Scope definingScope, boolean isFinalValue, Object defaultValue) { - this.definingScope = definingScope; - this.isFinalValue = isFinalValue; - this.defaultValue = defaultValue; - } - - public boolean isFinal() { - return isFinalValue; - } - - public Object defaultInitValue() { - return defaultValue; - } - - public Object constant() { - return constantValue; - } - - public void setConstant(Object cv) { - constantValue = cv; - } - - public Scope getDefiningScope() { - return definingScope; - } - }; - - private abstract class AbstractScope implements Scope { - private final Scope parent; - - private final Map values = new LinkedHashMap(); - - private final Map caseInsensitiveNames = new LinkedHashMap(); - - protected abstract SymbolTable getUnderlyingSymtab(); - - public Scope getParent() { - return parent; - } - - public int size() { - return getUnderlyingSymtab().getMaxValueNumber() + 1; - } - - public Iterator getAllNames() { - return values.keySet().iterator(); - } - - public int allocateTempValue() { - return getUnderlyingSymtab().newSymbol(); - } - - public int getConstantValue(Object o) { - if (o instanceof Integer) { - return getUnderlyingSymtab().getConstant(((Integer) o).intValue()); - } else if (o instanceof Float) { - return getUnderlyingSymtab().getConstant(((Float) o).floatValue()); - } else if (o instanceof Double) { - return getUnderlyingSymtab().getConstant(((Double) o).doubleValue()); - } else if (o instanceof Long) { - return getUnderlyingSymtab().getConstant(((Long) o).longValue()); - } else if (o instanceof String) { - return getUnderlyingSymtab().getConstant((String) o); - } else if (o instanceof Boolean) { - return getUnderlyingSymtab().getConstant((Boolean) o); - } else if (o instanceof Character) { - return getUnderlyingSymtab().getConstant(((Character) o).charValue()); - } else if (o instanceof Byte) { - return getUnderlyingSymtab().getConstant(((Byte) o).byteValue()); - } else if (o instanceof Short) { - return getUnderlyingSymtab().getConstant(((Short) o).shortValue()); - } else if (o == null) { - return getUnderlyingSymtab().getNullConstant(); - } else if (o == CAstControlFlowMap.SWITCH_DEFAULT) { - return getUnderlyingSymtab().getConstant("__default label"); - } else { - System.err.println(("cannot handle constant " + o)); - Assertions.UNREACHABLE(); - return -1; - } - } - - public boolean isConstant(int valueNumber) { - return getUnderlyingSymtab().isConstant(valueNumber); - } - - public Object getConstantObject(int valueNumber) { - return getUnderlyingSymtab().getConstantValue(valueNumber); - } - - public void declare(CAstSymbol s, int vn) { - String nm = s.name(); - assert !contains(nm) : nm; - if (s.isCaseInsensitive()) - caseInsensitiveNames.put(nm.toLowerCase(), nm); - values.put(nm, makeSymbol(s, vn)); - } - - public void declare(CAstSymbol s) { - String nm = s.name(); - if (!contains(nm) || lookup(nm).getDefiningScope() != this) { - if (s.isCaseInsensitive()) - caseInsensitiveNames.put(nm.toLowerCase(), nm); - values.put(nm, makeSymbol(s)); - } else { - assert !s.isFinal() : "trying to redeclare " + nm; - } - } - - AbstractScope(Scope parent) { - this.parent = parent; - } - - private final String mapName(String nm) { - String mappedName = caseInsensitiveNames.get(nm.toLowerCase()); - return (mappedName == null) ? nm : mappedName; - } - - protected Symbol makeSymbol(CAstSymbol s) { - return makeSymbol(s.name(), s.isFinal(), s.isInternalName(), s.defaultInitValue(), -1, this); - } - - protected Symbol makeSymbol(CAstSymbol s, int vn) { - return makeSymbol(s.name(), s.isFinal(), s.isInternalName(), s.defaultInitValue(), vn, this); - } - - abstract protected Symbol makeSymbol(String nm, boolean isFinal, boolean isInternalName, Object defaultInitValue, int vn, - Scope parent); - - public boolean isCaseInsensitive(String nm) { - return caseInsensitiveNames.containsKey(nm.toLowerCase()); - } - - public Symbol lookup(String nm) { - if (contains(nm)) { - return values.get(mapName(nm)); - } else { - Symbol scoped = parent.lookup(nm); - if (scoped != null && getEntityScope() == this && (isGlobal(scoped) || isLexicallyScoped(scoped))) { - values.put(nm, - makeSymbol(nm, scoped.isFinal(), scoped.isInternalName(), scoped.defaultInitValue(), -1, scoped.getDefiningScope())); - if (scoped.getDefiningScope().isCaseInsensitive(nm)) { - caseInsensitiveNames.put(nm.toLowerCase(), nm); - } - return values.get(nm); - } else { - return scoped; - } - } - } - - public boolean contains(String nm) { - String mappedName = caseInsensitiveNames.get(nm.toLowerCase()); - return values.containsKey(mappedName == null ? nm : mappedName); - } - - public boolean isGlobal(Symbol s) { - return s.getDefiningScope().type() == ScopeType.GLOBAL; - } - - public abstract boolean isLexicallyScoped(Symbol s); - - protected abstract AbstractScope getEntityScope(); - - public abstract CAstEntity getEntity(); - }; - - private AbstractScope makeScriptScope(final CAstEntity s, Scope parent) { - return new AbstractScope(parent) { - SymbolTable scriptGlobalSymtab = new SymbolTable(s.getArgumentCount()); - - public SymbolTable getUnderlyingSymtab() { - return scriptGlobalSymtab; - } - - protected AbstractScope getEntityScope() { - return this; - } - - public boolean isLexicallyScoped(Symbol s) { - if (isGlobal(s)) - return false; - else - return ((AbstractScope) s.getDefiningScope()).getEntity() != getEntity(); - } - - public CAstEntity getEntity() { - return s; - } - - public ScopeType type() { - return ScopeType.SCRIPT; - } - - protected Symbol makeSymbol(final String nm, final boolean isFinal, final boolean isInternalName, - final Object defaultInitValue, int vn, Scope definer) { - final int v = vn == -1 ? getUnderlyingSymtab().newSymbol() : vn; - if (useDefaultInitValues() && defaultInitValue != null) { - if (getUnderlyingSymtab().getValue(v) == null) { - setDefaultValue(getUnderlyingSymtab(), v, defaultInitValue); - } - } - return new AbstractSymbol(definer, isFinal, defaultInitValue) { - public String toString() { - return nm + ":" + System.identityHashCode(this); - } - - public int valueNumber() { - return v; - } - - public boolean isInternalName() { - return isInternalName; - } - - public boolean isParameter() { - return false; - } - }; - } - }; - } - - protected int getArgumentCount(CAstEntity f) { - return f.getArgumentCount(); - } - - protected String[] getArgumentNames(CAstEntity f) { - return f.getArgumentNames(); - } - - private AbstractScope makeFunctionScope(final CAstEntity f, Scope parent) { - return new AbstractScope(parent) { - private final String[] params = getArgumentNames(f); - - private final SymbolTable functionSymtab = new SymbolTable(getArgumentCount(f)); - - // ctor for scope object - { - for (int i = 0; i < getArgumentCount(f); i++) { - final int yuck = i; - declare(new CAstSymbol() { - public String name() { - return params[yuck]; - } - - public boolean isFinal() { - return false; - } - - public boolean isCaseInsensitive() { - return false; - } - - public boolean isInternalName() { - return false; - } - - public Object defaultInitValue() { - return null; - } - - }); - } - } - - public SymbolTable getUnderlyingSymtab() { - return functionSymtab; - } - - protected AbstractScope getEntityScope() { - return this; - } - - public boolean isLexicallyScoped(Symbol s) { - if (isGlobal(s)) - return false; - else - return ((AbstractScope) s.getDefiningScope()).getEntity() != getEntity(); - } - - public CAstEntity getEntity() { - return f; - } - - public ScopeType type() { - return ScopeType.FUNCTION; - } - - private int find(String n) { - for (int i = 0; i < params.length; i++) { - if (n.equals(params[i])) { - return i + 1; - } - } - - return -1; - } - - protected Symbol makeSymbol(final String nm, final boolean isFinal, final boolean isInternalName, - final Object defaultInitValue, final int valueNumber, Scope definer) { - return new AbstractSymbol(definer, isFinal, defaultInitValue) { - final int vn; - - { - int x = find(nm); - if (x != -1) { - assert valueNumber == -1; - vn = x; - } else if (valueNumber != -1) { - vn = valueNumber; - } else { - vn = getUnderlyingSymtab().newSymbol(); - } - if (useDefaultInitValues() && defaultInitValue != null) { - if (getUnderlyingSymtab().getValue(vn) == null) { - setDefaultValue(getUnderlyingSymtab(), vn, defaultInitValue); - } - } - } - - public String toString() { - return nm + ":" + System.identityHashCode(this); - } - - public int valueNumber() { - return vn; - } - - public boolean isInternalName() { - return isInternalName; - } - - public boolean isParameter() { - return vn <= params.length; - } - }; - } - }; - } - - private Scope makeLocalScope(CAstNode s, final Scope parent) { - return new AbstractScope(parent) { - public ScopeType type() { - return ScopeType.LOCAL; - } - - public SymbolTable getUnderlyingSymtab() { - return ((AbstractScope) parent).getUnderlyingSymtab(); - } - - protected AbstractScope getEntityScope() { - return ((AbstractScope) parent).getEntityScope(); - } - - public boolean isLexicallyScoped(Symbol s) { - return ((AbstractScope) getEntityScope()).isLexicallyScoped(s); - } - - public CAstEntity getEntity() { - return ((AbstractScope) getEntityScope()).getEntity(); - } - - protected Symbol makeSymbol(final String nm, boolean isFinal, final boolean isInternalName, final Object defaultInitValue, - int vn, Scope definer) { - final int v = vn == -1 ? getUnderlyingSymtab().newSymbol() : vn; - if (useDefaultInitValues() && defaultInitValue != null) { - if (getUnderlyingSymtab().getValue(v) == null) { - setDefaultValue(getUnderlyingSymtab(), v, defaultInitValue); - } - } - return new AbstractSymbol(definer, isFinal, defaultInitValue) { - public String toString() { - return nm + ":" + System.identityHashCode(this); - } - - public int valueNumber() { - return v; - } - - public boolean isInternalName() { - return isInternalName; - } - - public boolean isParameter() { - return false; - } - }; - } - }; - } - - private Scope makeGlobalScope() { - final Map globalSymbols = new LinkedHashMap(); - final Map caseInsensitiveNames = new LinkedHashMap(); - return new Scope() { - private final String mapName(String nm) { - String mappedName = caseInsensitiveNames.get(nm.toLowerCase()); - return (mappedName == null) ? nm : mappedName; - } - - public Scope getParent() { - return null; - } - - public boolean isGlobal(Symbol s) { - return true; - } - - public boolean isLexicallyScoped(Symbol s) { - return false; - } - - public CAstEntity getEntity() { - return null; - } - - public int size() { - return globalSymbols.size(); - } - - public Iterator getAllNames() { - return globalSymbols.keySet().iterator(); - } - - public int allocateTempValue() { - throw new UnsupportedOperationException(); - } - - public int getConstantValue(Object c) { - throw new UnsupportedOperationException(); - } - - public boolean isConstant(int valueNumber) { - throw new UnsupportedOperationException(); - } - - public Object getConstantObject(int valueNumber) { - throw new UnsupportedOperationException(); - } - - public ScopeType type() { - return ScopeType.GLOBAL; - } - - public boolean contains(String name) { - return hasImplicitGlobals() || globalSymbols.containsKey(mapName(name)); - } - - public boolean isCaseInsensitive(String name) { - return caseInsensitiveNames.containsKey(name.toLowerCase()); - } - - public Symbol lookup(final String name) { - if (!globalSymbols.containsKey(mapName(name))) { - if (hasImplicitGlobals()) { - declare(new CAstSymbol() { - public String name() { - return name; - } - - public boolean isFinal() { - return false; - } - - public boolean isCaseInsensitive() { - return false; - } - - public boolean isInternalName() { - return false; - } - - public Object defaultInitValue() { - return null; - } - }); - } else if (hasSpecialUndeclaredVariables()) { - return null; - } else { - throw new Error("cannot find " + name); - } - } - - return globalSymbols.get(mapName(name)); - } - - public void declare(CAstSymbol s, int vn) { - assert vn == -1; - declare(s); - } - - public void declare(final CAstSymbol s) { - final String name = s.name(); - if (s.isCaseInsensitive()) { - caseInsensitiveNames.put(name.toLowerCase(), name); - } - globalSymbols.put(name, new AbstractSymbol(this, s.isFinal(), s.defaultInitValue()) { - public String toString() { - return name + ":" + System.identityHashCode(this); - } - - public boolean isParameter() { - return false; - } - - public boolean isInternalName() { - return s.isInternalName(); - } - - public int valueNumber() { - throw new UnsupportedOperationException(); - } - }); - } - }; - } - - protected Scope makeTypeScope(final CAstEntity type, final Scope parent) { - final Map typeSymbols = new LinkedHashMap(); - final Map caseInsensitiveNames = new LinkedHashMap(); - return new Scope() { - private final String mapName(String nm) { - String mappedName = caseInsensitiveNames.get(nm.toLowerCase()); - return (mappedName == null) ? nm : mappedName; - } - - public Scope getParent() { - return parent; - } - - public boolean isGlobal(Symbol s) { - return false; - } - - public boolean isLexicallyScoped(Symbol s) { - return false; - } - - public CAstEntity getEntity() { - return type; - } - - public int size() { - return typeSymbols.size(); - } - - public Iterator getAllNames() { - return typeSymbols.keySet().iterator(); - } - - public int allocateTempValue() { - throw new UnsupportedOperationException(); - } - - public int getConstantValue(Object c) { - throw new UnsupportedOperationException(); - } - - public boolean isConstant(int valueNumber) { - throw new UnsupportedOperationException(); - } - - public Object getConstantObject(int valueNumber) { - throw new UnsupportedOperationException(); - } - - public ScopeType type() { - return ScopeType.TYPE; - } - - public boolean contains(String name) { - return typeSymbols.containsKey(mapName(name)); - } - - public boolean isCaseInsensitive(String name) { - return caseInsensitiveNames.containsKey(name.toLowerCase()); - } - - public Symbol lookup(String nm) { - if (typeSymbols.containsKey(mapName(nm))) - return typeSymbols.get(mapName(nm)); - else { - return parent.lookup(nm); - } - } - - public void declare(CAstSymbol s, int vn) { - assert vn == -1; - declare(s); - } - - public void declare(final CAstSymbol s) { - final String name = s.name(); - assert !s.isFinal(); - if (s.isCaseInsensitive()) - caseInsensitiveNames.put(name.toLowerCase(), name); - typeSymbols.put(name, new AbstractSymbol(this, s.isFinal(), s.defaultInitValue()) { - public String toString() { - return name + ":" + System.identityHashCode(this); - } - - public boolean isParameter() { - return false; - } - - public boolean isInternalName() { - return s.isInternalName(); - } - - public int valueNumber() { - throw new UnsupportedOperationException(); - } - }); - } - }; - } - - public interface WalkContext extends CAstVisitor.Context { - - ModuleEntry getModule(); - - String getName(); - - String file(); - - CAstSourcePositionMap getSourceMap(); - - CAstControlFlowMap getControlFlow(); - - Scope currentScope(); - - Set entityScopes(); - - IncipientCFG cfg(); - - UnwindState getUnwindState(); - - void setCatchType(int blockNumber, TypeReference catchType); - - void setCatchType(CAstNode catchNode, TypeReference catchType); - - TypeReference[][] getCatchTypes(); - - void addEntityName(CAstEntity e, String name); - - String getEntityName(CAstEntity e); - - boolean hasValue(CAstNode n); - - int setValue(CAstNode n, int v); - - int getValue(CAstNode n); - - Set, Integer>> exposeNameSet(CAstEntity entity, boolean writeSet); - - Set getAccesses(CAstEntity e); - - Scope getGlobalScope(); - - } - - private abstract class DelegatingContext implements WalkContext { - private final WalkContext parent; - - DelegatingContext(WalkContext parent) { - this.parent = parent; - } - - public Set getAccesses(CAstEntity e) { - return parent.getAccesses(e); - } - - public ModuleEntry getModule() { - return parent.getModule(); - } - - public String getName() { - return parent.getName(); - } - - public String file() { - return parent.file(); - } - - public CAstEntity top() { - return parent.top(); - } - - public CAstSourcePositionMap getSourceMap() { - return parent.getSourceMap(); - } - - public CAstControlFlowMap getControlFlow() { - return parent.getControlFlow(); - } - - public Scope currentScope() { - return parent.currentScope(); - } - - public Set entityScopes() { - return parent.entityScopes(); - } - - public IncipientCFG cfg() { - return parent.cfg(); - } - - public UnwindState getUnwindState() { - return parent.getUnwindState(); - } - - public void setCatchType(int blockNumber, TypeReference catchType) { - parent.setCatchType(blockNumber, catchType); - } - - public void setCatchType(CAstNode catchNode, TypeReference catchType) { - parent.setCatchType(catchNode, catchType); - } - - public TypeReference[][] getCatchTypes() { - return parent.getCatchTypes(); - } - - public void addEntityName(CAstEntity e, String name) { - parent.addEntityName(e, name); - } - - public String getEntityName(CAstEntity e) { - return parent.getEntityName(e); - } - - public boolean hasValue(CAstNode n) { - return parent.hasValue(n); - } - - public int setValue(CAstNode n, int v) { - return parent.setValue(n, v); - } - - public int getValue(CAstNode n) { - return parent.getValue(n); - } - - public Set, Integer>> exposeNameSet(CAstEntity entity, boolean writeSet) { - return parent.exposeNameSet(entity, writeSet); - } - - public Scope getGlobalScope() { - return parent.getGlobalScope(); - } - - } - - private class FileContext extends DelegatingContext { - private final String fUnitName; - - public FileContext(WalkContext parent, String unitName) { - super(parent); - fUnitName = unitName; - } - - public String getName() { - return fUnitName; - } - } - - private class UnwindContext extends DelegatingContext { - private final UnwindState state; - - UnwindContext(CAstNode unwindNode, WalkContext parent, CAstVisitor visitor) { - super(parent); - this.state = new UnwindState(unwindNode, parent, visitor); - } - - public UnwindState getUnwindState() { - return state; - } - } - - private abstract class EntityContext extends DelegatingContext { - protected final CAstEntity topNode; - - protected final String name; - - EntityContext(WalkContext parent, CAstEntity s) { - super(parent); - this.topNode = s; - this.name = composeEntityName(parent, s); - addEntityName(s, this.name); - } - - public String getName() { - return name; - } - - public CAstEntity top() { - return topNode; - } - - public CAstSourcePositionMap getSourceMap() { - return top().getSourceMap(); - } - - } - - private class CodeEntityContext extends EntityContext { - private final Scope topEntityScope; - - private final Set allEntityScopes; - - private final IncipientCFG cfg; - - private TypeReference[][] catchTypes = new TypeReference[0][]; - - Set, Integer>> exposedReads; - Set, Integer>> exposedWrites; - - Set accesses; - - /** - * maps nodes in the current function to the value number holding their value - * or, for constants, to their constant value. - */ - private final Map results = new LinkedHashMap(); - - CodeEntityContext(WalkContext parent, Scope entityScope, CAstEntity s) { - super(parent, s); - - this.topEntityScope = entityScope; - - this.allEntityScopes = HashSetFactory.make(); - this.allEntityScopes.add(entityScope); - - cfg = new IncipientCFG(); - } - - public Set getAccesses(CAstEntity e) { - if (e == topNode) { - if (accesses == null) { - accesses = HashSetFactory.make(); - } - return accesses; - } else { - return super.getAccesses(e); - } - } - - @Override - public Set, Integer>> exposeNameSet(CAstEntity entity, boolean writeSet) { - if (entity == topNode) { - if (writeSet) { - if (exposedWrites == null) { - exposedWrites = HashSetFactory.make(); - } - return exposedWrites; - } else { - if (exposedReads == null) { - exposedReads = HashSetFactory.make(); - } - return exposedReads; - } - } else { - return super.exposeNameSet(entity, writeSet); - } - } - - - public CAstControlFlowMap getControlFlow() { - return top().getControlFlow(); - } - - public IncipientCFG cfg() { - return cfg; - } - - public Scope currentScope() { - return topEntityScope; - } - - public Set entityScopes() { - return allEntityScopes; - } - - public UnwindState getUnwindState() { - return null; - } - - public void setCatchType(CAstNode catchNode, TypeReference catchType) { - setCatchType(cfg.getBlock(catchNode).getNumber(), catchType); - } - - public void setCatchType(int blockNumber, TypeReference catchType) { - if (catchTypes.length <= blockNumber) { - TypeReference[][] data = new TypeReference[blockNumber + 1][]; - System.arraycopy(catchTypes, 0, data, 0, catchTypes.length); - catchTypes = data; - } - - if (catchTypes[blockNumber] == null) { - catchTypes[blockNumber] = new TypeReference[] { catchType }; - } else { - TypeReference[] data = catchTypes[blockNumber]; - - for (int i = 0; i < data.length; i++) { - if (data[i] == catchType) { - return; - } - } - - TypeReference[] newData = new TypeReference[data.length + 1]; - System.arraycopy(data, 0, newData, 0, data.length); - newData[data.length] = catchType; - - catchTypes[blockNumber] = newData; - } - } - - public TypeReference[][] getCatchTypes() { - return catchTypes; - } - - public boolean hasValue(CAstNode n) { - return results.containsKey(n); - } - - public final int setValue(CAstNode n, int v) { - results.put(n, new Integer(v)); - return v; - } - - public final int getValue(CAstNode n) { - if (results.containsKey(n)) - return results.get(n).intValue(); - else { - if (DEBUG) { - System.err.println(("no value for " + n.getKind())); - } - return -1; - } - } - - } - - private final class TypeContext extends EntityContext { - - private TypeContext(WalkContext parent, CAstEntity n) { - super(parent, n); - } - - public CAstControlFlowMap getControlFlow() { - Assertions.UNREACHABLE("TypeContext.getControlFlow()"); - return null; - } - - public IncipientCFG cfg() { - Assertions.UNREACHABLE("TypeContext.cfg()"); - return null; - } - - public UnwindState getUnwindState() { - Assertions.UNREACHABLE("TypeContext.getUnwindState()"); - return null; - } - } - - private class LocalContext extends DelegatingContext { - private final Scope localScope; - - LocalContext(WalkContext parent, Scope localScope) { - super(parent); - this.localScope = localScope; - parent.entityScopes().add(localScope); - } - - public Scope currentScope() { - return localScope; - } - } - - /** - * lexical access information for some entity scope. used during call graph - * construction to handle lexical accesses. - */ - public static class AstLexicalInformation implements LexicalInformation { - /** - * the name of this function, as it appears in the definer portion of a - * lexical name - */ - private final String functionLexicalName; - - /** - * names possibly accessed in a nested lexical scope, represented as pairs - * (name,nameOfDefiningEntity) - */ - private final Pair[] exposedNames; - - /** - * map from instruction index and exposed name (via its index in - * {@link #exposedNames}) to the value number for the name at that - * instruction index. This can vary at different instructions due to SSA - * (and this information is updated during {@link SSAConversion}). - */ - private final int[][] instructionLexicalUses; - - /** - * maps each exposed name (via its index in {@link #exposedNames}) to its - * value number at method exit. - */ - private final int[] exitLexicalUses; - - /** - * the names of the enclosing methods declaring names that are lexically - * accessed by the entity - */ - private final String[] scopingParents; - - /** - * all value numbers appearing as entries in {@link #instructionLexicalUses} - * and {@link #exitLexicalUses}, computed lazily - */ - private MutableIntSet allExposedUses = null; - - /** - * names of exposed variables of this method that cannot be written outside - */ - private final Set readOnlyNames; - - @SuppressWarnings("unchecked") - public AstLexicalInformation(AstLexicalInformation original) { - this.functionLexicalName = original.functionLexicalName; - - if (original.exposedNames != null) { - exposedNames = new Pair[original.exposedNames.length]; - for (int i = 0; i < exposedNames.length; i++) { - exposedNames[i] = Pair.make(original.exposedNames[i].fst, original.exposedNames[i].snd); - } - } else { - exposedNames = null; - } - - instructionLexicalUses = new int[original.instructionLexicalUses.length][]; - for (int i = 0; i < instructionLexicalUses.length; i++) { - int[] x = original.instructionLexicalUses[i]; - if (x != null) { - instructionLexicalUses[i] = new int[x.length]; - for (int j = 0; j < x.length; j++) { - instructionLexicalUses[i][j] = x[j]; - } - } - } - - if (original.exitLexicalUses != null) { - exitLexicalUses = new int[original.exitLexicalUses.length]; - for (int i = 0; i < exitLexicalUses.length; i++) { - exitLexicalUses[i] = original.exitLexicalUses[i]; - } - } else { - exitLexicalUses = null; - } - - if (original.scopingParents != null) { - scopingParents = new String[original.scopingParents.length]; - for (int i = 0; i < scopingParents.length; i++) { - scopingParents[i] = original.scopingParents[i]; - } - } else { - scopingParents = null; - } - - readOnlyNames = original.readOnlyNames; - } - - private int[] buildLexicalUseArray(Pair, Integer>[] exposedNames, String entityName) { - if (exposedNames != null) { - int[] lexicalUses = new int[exposedNames.length]; - for (int j = 0; j < exposedNames.length; j++) { - if (entityName == null || entityName.equals(exposedNames[j].fst.snd)) { - lexicalUses[j] = exposedNames[j].snd; - } else { - lexicalUses[j] = -1; - } - } - - return lexicalUses; - } else { - return null; - } - } - - private Pair[] buildLexicalNamesArray(Pair, Integer>[] exposedNames) { - if (exposedNames != null) { - @SuppressWarnings("unchecked") - Pair[] lexicalNames = new Pair[exposedNames.length]; - for (int j = 0; j < exposedNames.length; j++) { - lexicalNames[j] = exposedNames[j].fst; - } - - return lexicalNames; - } else { - return null; - } - } - - @SuppressWarnings("unchecked") - AstLexicalInformation(String entityName, Scope scope, SSAInstruction[] instrs, - Set, Integer>> exposedNamesForReadSet, - Set, Integer>> exposedNamesForWriteSet, Set accesses) { - this.functionLexicalName = entityName; - - Pair, Integer>[] EN = null; - if (exposedNamesForReadSet != null || exposedNamesForWriteSet != null) { - Set, Integer>> exposedNamesSet = new HashSet, Integer>>(); - if (exposedNamesForReadSet != null) { - exposedNamesSet.addAll(exposedNamesForReadSet); - } - if (exposedNamesForWriteSet != null) { - exposedNamesSet.addAll(exposedNamesForWriteSet); - } - EN = exposedNamesSet.toArray(new Pair[exposedNamesSet.size()]); - } - - if (exposedNamesForReadSet != null) { - Set readOnlyNames = new HashSet(); - for (Pair, Integer> v : exposedNamesForReadSet) { - if (entityName != null && entityName.equals(v.fst.snd)) { - readOnlyNames.add(v.fst.fst); - } - } - if (exposedNamesForWriteSet != null) { - for (Pair, Integer> v : exposedNamesForWriteSet) { - if (entityName != null && entityName.equals(v.fst.snd)) { - readOnlyNames.remove(v.fst.fst); - } - } - } - this.readOnlyNames = readOnlyNames; - } else { - this.readOnlyNames = null; - } - - this.exposedNames = buildLexicalNamesArray(EN); - - // the value numbers stored in exitLexicalUses and instructionLexicalUses - // are identical at first; they will be updated - // as needed during the final SSA conversion - this.exitLexicalUses = buildLexicalUseArray(EN, entityName); - - this.instructionLexicalUses = new int[instrs.length][]; - for (int i = 0; i < instrs.length; i++) { - if (instrs[i] instanceof SSAAbstractInvokeInstruction) { - this.instructionLexicalUses[i] = buildLexicalUseArray(EN, null); - } - } - - if (accesses != null) { - Set parents = new LinkedHashSet(); - for (Iterator ACS = accesses.iterator(); ACS.hasNext();) { - Access AC = ACS.next(); - if (AC.variableDefiner != null) { - parents.add(AC.variableDefiner); - } - } - scopingParents = parents.toArray(new String[parents.size()]); - - if (DEBUG_LEXICAL) { - System.err.println(("scoping parents of " + scope.getEntity())); - System.err.println(parents.toString()); - } - - } else { - scopingParents = null; - } - - if (DEBUG_NAMES) { - System.err.println(("lexical uses of " + scope.getEntity())); - for (int i = 0; i < instructionLexicalUses.length; i++) { - if (instructionLexicalUses[i] != null) { - System.err.println((" lexical uses of " + instrs[i])); - for (int j = 0; j < instructionLexicalUses[i].length; j++) { - System.err.println((" " + this.exposedNames[j].fst + ": " + instructionLexicalUses[i][j])); - } - } - } - } - } - - public int[] getExitExposedUses() { - return exitLexicalUses; - } - - private static final int[] NONE = new int[0]; - - public int[] getExposedUses(int instructionOffset) { - return instructionLexicalUses[instructionOffset] == null ? NONE : instructionLexicalUses[instructionOffset]; - } - - public IntSet getAllExposedUses() { - if (allExposedUses == null) { - allExposedUses = IntSetUtil.make(); - if (exitLexicalUses != null) { - for (int i = 0; i < exitLexicalUses.length; i++) { - if (exitLexicalUses[i] > 0) { - allExposedUses.add(exitLexicalUses[i]); - } - } - } - if (instructionLexicalUses != null) { - for (int i = 0; i < instructionLexicalUses.length; i++) { - if (instructionLexicalUses[i] != null) { - for (int j = 0; j < instructionLexicalUses[i].length; j++) { - if (instructionLexicalUses[i][j] > 0) { - allExposedUses.add(instructionLexicalUses[i][j]); - } - } - } - } - } - } - - return allExposedUses; - } - - public Pair[] getExposedNames() { - return exposedNames; - } - - public String[] getScopingParents() { - return scopingParents; - } - - /** - * reset cached info about value numbers that may have changed - */ - public void handleAlteration() { - allExposedUses = null; - } - - public boolean isReadOnly(String name) { - return readOnlyNames != null && readOnlyNames.contains(name); - } - - public String getScopingName() { - return functionLexicalName; - } - }; - - /** - * record that in entity e, the access is performed. - * - * If {@link #useLocalValuesForLexicalVars()} is true, the access is performed - * using a local variable. in - * {@link #patchLexicalAccesses(SSAInstruction[], Set)}, this information is - * used to update an instruction that performs all the accesses at the - * beginning of the method and defines the locals. - */ - private void addAccess(WalkContext context, CAstEntity e, Access access) { - context.getAccesses(e).add(access); - } - - /** - * Record that a name assigned a value number in the scope of entity may be - * accessed by a lexically nested scope, i.e., the name may be - * exposed to lexically nested scopes. This information is needed - * during call graph construction to properly model the data flow due to the - * access in the nested scope. - * - * @param entity - * an entity in whose scope name is assigned a value number - * @param declaration - * the declaring entity for name (possibly an enclosing scope of - * entity, in the case where entity - * {@link #useLocalValuesForLexicalVars() accesses the name via a - * local}) - * @param name - * the accessed name - * @param valueNumber - * the name's value number in the scope of entity - */ - private void addExposedName(CAstEntity entity, CAstEntity declaration, String name, int valueNumber, boolean isWrite, WalkContext context) { - Pair, Integer> newVal = Pair.make(Pair.make(name, context.getEntityName(declaration)), valueNumber); - context.exposeNameSet(entity, isWrite).add(newVal); - } - - private void setDefaultValue(SymbolTable symtab, int vn, Object value) { - if (value == CAstSymbol.NULL_DEFAULT_VALUE) { - symtab.setDefaultValue(vn, null); - } else { - symtab.setDefaultValue(vn, value); - } - } - - protected IUnaryOpInstruction.IOperator translateUnaryOpcode(CAstNode op) { - if (op == CAstOperator.OP_BITNOT) - return AstConstants.UnaryOp.BITNOT; - else if (op == CAstOperator.OP_NOT) - return IUnaryOpInstruction.Operator.NEG; - else if (op == CAstOperator.OP_SUB) - return AstConstants.UnaryOp.MINUS; - else if (op == CAstOperator.OP_ADD) - return AstConstants.UnaryOp.PLUS; - else - Assertions.UNREACHABLE("cannot translate " + CAstPrinter.print(op)); - return null; - - } - - protected IBinaryOpInstruction.IOperator translateBinaryOpcode(CAstNode op) { - if (op == CAstOperator.OP_ADD) - return BinaryOpInstruction.Operator.ADD; - else if (op == CAstOperator.OP_DIV) - return BinaryOpInstruction.Operator.DIV; - else if (op == CAstOperator.OP_LSH) - return ShiftInstruction.Operator.SHL; - else if (op == CAstOperator.OP_MOD) - return BinaryOpInstruction.Operator.REM; - else if (op == CAstOperator.OP_MUL) - return BinaryOpInstruction.Operator.MUL; - else if (op == CAstOperator.OP_RSH) - return ShiftInstruction.Operator.SHR; - else if (op == CAstOperator.OP_SUB) - return BinaryOpInstruction.Operator.SUB; - else if (op == CAstOperator.OP_URSH) - return ShiftInstruction.Operator.USHR; - else if (op == CAstOperator.OP_BIT_AND) - return BinaryOpInstruction.Operator.AND; - else if (op == CAstOperator.OP_BIT_OR) - return BinaryOpInstruction.Operator.OR; - else if (op == CAstOperator.OP_BIT_XOR) - return BinaryOpInstruction.Operator.XOR; - else if (op == CAstOperator.OP_CONCAT) - return AstConstants.BinaryOp.CONCAT; - else if (op == CAstOperator.OP_EQ) - return AstConstants.BinaryOp.EQ; - else if (op == CAstOperator.OP_STRICT_EQ) - return AstConstants.BinaryOp.STRICT_EQ; - else if (op == CAstOperator.OP_GE) - return AstConstants.BinaryOp.GE; - else if (op == CAstOperator.OP_GT) - return AstConstants.BinaryOp.GT; - else if (op == CAstOperator.OP_LE) - return AstConstants.BinaryOp.LE; - else if (op == CAstOperator.OP_LT) - return AstConstants.BinaryOp.LT; - else if (op == CAstOperator.OP_NE) - return AstConstants.BinaryOp.NE; - else if (op == CAstOperator.OP_STRICT_NE) - return AstConstants.BinaryOp.STRICT_NE; - else { - Assertions.UNREACHABLE("cannot translate " + CAstPrinter.print(op)); - return null; - } - } - - protected IConditionalBranchInstruction.IOperator translateConditionOpcode(CAstNode op) { - if (op == CAstOperator.OP_EQ) - return ConditionalBranchInstruction.Operator.EQ; - else if (op == CAstOperator.OP_GE) - return ConditionalBranchInstruction.Operator.GE; - else if (op == CAstOperator.OP_GT) - return ConditionalBranchInstruction.Operator.GT; - else if (op == CAstOperator.OP_LE) - return ConditionalBranchInstruction.Operator.LE; - else if (op == CAstOperator.OP_LT) - return ConditionalBranchInstruction.Operator.LT; - else if (op == CAstOperator.OP_NE) - return ConditionalBranchInstruction.Operator.NE; - - else { - Assertions.UNREACHABLE("cannot translate " + CAstPrinter.print(op)); - return null; - } - } - - private String[] makeNameMap(CAstEntity n, Set scopes) { - // all scopes share the same underlying symtab, which is what - // size really refers to. - String[] map = new String[scopes.iterator().next().size() + 1]; - - if (DEBUG_NAMES) { - System.err.println(("names array of size " + map.length)); - } - - for (Iterator S = scopes.iterator(); S.hasNext();) { - Scope scope = S.next(); - for (Iterator I = scope.getAllNames(); I.hasNext();) { - String nm = I.next(); - Symbol v = (Symbol) scope.lookup(nm); - - if (v.isInternalName()) { - continue; - } - - // constants can flow to multiple variables - if (scope.isConstant(v.valueNumber())) - continue; - - assert map[v.valueNumber()] == null || map[v.valueNumber()].equals(nm) : "value number " + v.valueNumber() - + " mapped to multiple names in " + n.getName() + ": " + nm + " and " + map[v.valueNumber()]; - - map[v.valueNumber()] = nm; - - if (DEBUG_NAMES) { - System.err.println(("mapping name " + nm + " to " + v.valueNumber())); - } - } - } - - return map; - } - - protected final CAstType getTypeForNode(WalkContext context, CAstNode node) { - if (context.top().getNodeTypeMap() != null) { - return context.top().getNodeTypeMap().getNodeType(node); - } else { - return null; - } - } - - /** - * find any AstLexicalAccess instructions in instrs with a zero access count, - * and change them to perform specified accesses. If accesses is empty, null - * out the pointers to the AstLexicalAccess instructions in the array. - * - * Presumably, such empty AstLexicalAccess instructions should only exist if - * {@link #useLocalValuesForLexicalVars()} returns true? - */ - private void patchLexicalAccesses(SSAInstruction[] instrs, Set accesses) { - Access[] AC = accesses == null || accesses.isEmpty() ? (Access[]) null : (Access[]) accesses.toArray(new Access[accesses.size()]); - for (int i = 0; i < instrs.length; i++) { - if (instrs[i] instanceof AstLexicalAccess && ((AstLexicalAccess) instrs[i]).getAccessCount() == 0) { - // should just be AstLexicalRead for now; may add support for - // AstLexicalWrite later - assert instrs[i] instanceof AstLexicalRead; - assert useLocalValuesForLexicalVars(); - if (AC != null) { - ((AstLexicalAccess) instrs[i]).setAccesses(AC); - } else { - instrs[i] = null; - } - } - } - } - - private Position getPosition(CAstSourcePositionMap map, CAstNode n) { - if (map.getPosition(n) != null) { - return map.getPosition(n); - } else { - for (int i = 0; i < n.getChildCount(); i++) { - Position p = getPosition(map, n.getChild(i)); - if (p != null) { - return p; - } - } - - return null; - } - } - - protected WalkContext makeFileContext(WalkContext c, CAstEntity n) { - return new FileContext((WalkContext) c, n.getName()); - } - - protected WalkContext makeTypeContext(WalkContext c, CAstEntity n) { - return new TypeContext((WalkContext) c, n); - } - - protected WalkContext makeCodeContext(WalkContext c, CAstEntity n) { - WalkContext context = (WalkContext) c; - AbstractScope scope; - if (n.getKind() == CAstEntity.SCRIPT_ENTITY) - scope = makeScriptScope(n, context.currentScope()); - else - scope = makeFunctionScope(n, context.currentScope()); - return new CodeEntityContext(context, scope, n); - } - - protected boolean enterEntity(final CAstEntity n, WalkContext context, CAstVisitor visitor) { - if (DEBUG_TOP) - System.err.println(("translating " + n.getName())); - return false; - } - - protected boolean visitFileEntity(CAstEntity n, WalkContext context, WalkContext fileContext, CAstVisitor visitor) { /* empty */ - return false; - } - - protected void leaveFileEntity(CAstEntity n, WalkContext context, WalkContext fileContext, CAstVisitor visitor) { /* empty */ - } - - protected boolean visitFieldEntity(CAstEntity n, WalkContext context, CAstVisitor visitor) { /* empty */ - return false; - } - - protected void leaveFieldEntity(CAstEntity n, WalkContext context, CAstVisitor visitor) { - // Define a new field in the enclosing type, if the language we're - // processing allows such. - CAstEntity topEntity = context.top(); // better be a type - assert topEntity.getKind() == CAstEntity.TYPE_ENTITY : "Parent of field entity is not a type???"; - defineField(topEntity, (WalkContext) context, n); - } - - protected boolean visitGlobalEntity(CAstEntity n, WalkContext context, CAstVisitor visitor) { /* empty */ - return false; - } - - protected void leaveGlobalEntity(CAstEntity n, WalkContext context, CAstVisitor visitor) { - // Define a new field in the enclosing type, if the language we're - // processing allows such. - context.getGlobalScope().declare(new CAstSymbolImpl(n.getName())); - } - - protected boolean visitTypeEntity(CAstEntity n, WalkContext context, WalkContext typeContext, CAstVisitor visitor) { - return !defineType(n, (WalkContext) context); - } - - protected void leaveTypeEntity(CAstEntity n, WalkContext context, WalkContext typeContext, CAstVisitor visitor) { /* empty */ - } - - protected boolean visitFunctionEntity(CAstEntity n, WalkContext context, WalkContext codeContext, CAstVisitor visitor) { - if (n.getAST() == null) // presumably abstract - declareFunction(n, (WalkContext) context); - else - initFunctionEntity(n, (WalkContext) context, (WalkContext) codeContext); - return false; - } - - protected void leaveFunctionEntity(CAstEntity n, WalkContext context, WalkContext codeContext, CAstVisitor visitor) { - if (n.getAST() != null) // non-abstract - closeFunctionEntity(n, (WalkContext) context, (WalkContext) codeContext); - } - - protected boolean visitMacroEntity(CAstEntity n, WalkContext context, WalkContext codeContext, CAstVisitor visitor) { - return true; - } - - protected boolean visitScriptEntity(CAstEntity n, WalkContext context, WalkContext codeContext, CAstVisitor visitor) { - declareFunction(n, (WalkContext) codeContext); - initFunctionEntity(n, (WalkContext) context, (WalkContext) codeContext); - return false; - } - - protected void leaveScriptEntity(CAstEntity n, WalkContext context, WalkContext codeContext, CAstVisitor visitor) { - closeFunctionEntity(n, (WalkContext) context, (WalkContext) codeContext); - } - - public void initFunctionEntity(final CAstEntity n, WalkContext parentContext, WalkContext functionContext) { - // entry block - functionContext.cfg().makeEntryBlock(functionContext.cfg().newBlock(false)); - // first real block - functionContext.cfg().newBlock(true); - // prologue code, if any - doPrologue(functionContext); - } - - public void closeFunctionEntity(final CAstEntity n, WalkContext parentContext, WalkContext functionContext) { - // exit block - functionContext.cfg().makeExitBlock(functionContext.cfg().newBlock(true)); - - // create code entry stuff for this entity - SymbolTable symtab = ((AbstractScope) functionContext.currentScope()).getUnderlyingSymtab(); - TypeReference[][] catchTypes = functionContext.getCatchTypes(); - AstCFG cfg = new AstCFG(n, functionContext.cfg(), symtab); - Position[] line = functionContext.cfg().getLinePositionMap(); - boolean katch = functionContext.cfg().hasCatchBlock(); - boolean monitor = functionContext.cfg().hasMonitorOp(); - String[] nms = makeNameMap(n, functionContext.entityScopes()); - - /* - * Set reachableBlocks = DFS.getReachableNodes(cfg, - * Collections.singleton(cfg.entry())); - * Assertions._assert(reachableBlocks.size() == cfg.getNumberOfNodes(), - * cfg.toString()); - */ - - // (put here to allow subclasses to handle stuff in scoped entities) - // assemble lexical information - patchLexicalAccesses(cfg.getInstructions(), functionContext.getAccesses(n)); - AstLexicalInformation LI = new AstLexicalInformation(functionContext.getEntityName(n), (AbstractScope) functionContext.currentScope(), cfg.getInstructions(), - functionContext.exposeNameSet(n, false), - functionContext.exposeNameSet(n, true), - functionContext.getAccesses(n)); - - DebuggingInformation DBG = new AstDebuggingInformation(n.getPosition(), line, nms); - - // actually make code body - defineFunction(n, parentContext, cfg, symtab, katch, catchTypes, monitor, LI, DBG); - } - - protected WalkContext makeLocalContext(WalkContext context, CAstNode n) { - return new LocalContext((WalkContext) context, makeLocalScope(n, ((WalkContext) context).currentScope())); - } - - protected WalkContext makeUnwindContext(WalkContext context, CAstNode n, CAstVisitor visitor) { - // here, n represents the "finally" block of the unwind - return new UnwindContext(n, (WalkContext) context, visitor); - } - - private Map> entity2ExposedNames; - protected int processFunctionExpr(CAstNode n, WalkContext context) { - CAstEntity fn = (CAstEntity) n.getChild(0).getValue(); - declareFunction(fn, context); - int result = context.currentScope().allocateTempValue(); - int ex = context.currentScope().allocateTempValue(); - doMaterializeFunction(n, context, result, ex, fn); - return result; - } - - protected boolean visitFunctionExpr(CAstNode n, WalkContext c, CAstVisitor visitor) { /* empty */ - return false; - } - - protected void leaveFunctionExpr(CAstNode n, WalkContext c, CAstVisitor visitor) { - int result = processFunctionExpr(n, c); - c.setValue(n, result); - } - - protected boolean visitFunctionStmt(CAstNode n, WalkContext c, CAstVisitor visitor) { /* empty */ - return false; - } - - protected void leaveFunctionStmt(CAstNode n, WalkContext context, CAstVisitor visitor) { - int result = processFunctionExpr(n, context); - CAstEntity fn = (CAstEntity) n.getChild(0).getValue(); - // FIXME: handle redefinitions of functions - Scope cs = context.currentScope(); - if (cs.contains(fn.getName()) && !cs.isLexicallyScoped(cs.lookup(fn.getName())) && !cs.isGlobal(cs.lookup(fn.getName()))) { - // if we already have a local with the function's name, write the function - // value to that local - assignValue(n, context, cs.lookup(fn.getName()), fn.getName(), result); - } else if (topLevelFunctionsInGlobalScope() && context.top().getKind() == CAstEntity.SCRIPT_ENTITY) { - context.getGlobalScope().declare(new FinalCAstSymbol(fn.getName())); - assignValue(n, context, cs.lookup(fn.getName()), fn.getName(), result); - } else { - context.currentScope().declare(new FinalCAstSymbol(fn.getName()), result); - } - } - - protected boolean visitLocalScope(CAstNode n, WalkContext c, CAstVisitor visitor) { /* empty */ - return false; - } - - protected void leaveLocalScope(CAstNode n, WalkContext c, CAstVisitor visitor) { - c.setValue(n, c.getValue(n.getChild(0))); - } - - protected boolean visitBlockExpr(CAstNode n, WalkContext c, CAstVisitor visitor) { /* empty */ - return false; - } - - protected void leaveBlockExpr(CAstNode n, WalkContext c, CAstVisitor visitor) { - c.setValue(n, c.getValue(n.getChild(n.getChildCount() - 1))); - } - - protected boolean visitBlockStmt(CAstNode n, WalkContext c, CAstVisitor visitor) { /* empty */ - return false; - } - - protected void leaveBlockStmt(CAstNode n, WalkContext c, CAstVisitor visitor) { /* empty */ - } - - protected boolean visitLoop(CAstNode n, WalkContext c, CAstVisitor visitor) { - WalkContext context = (WalkContext) c; - // loop test block - context.cfg().newBlock(true); - PreBasicBlock headerB = context.cfg().getCurrentBlock(); - visitor.visit(n.getChild(0), context, visitor); - - assert c.getValue(n.getChild(0)) != -1 : "error in loop test " + CAstPrinter.print(n.getChild(0), context.top().getSourceMap()) - + " of loop " + CAstPrinter.print(n, context.top().getSourceMap()); - context.cfg().addInstruction( - insts.ConditionalBranchInstruction(translateConditionOpcode(CAstOperator.OP_EQ), null, c.getValue(n.getChild(0)), context - .currentScope().getConstantValue(new Integer(0)))); - PreBasicBlock branchB = context.cfg().getCurrentBlock(); - - // loop body - context.cfg().newBlock(true); - visitor.visit(n.getChild(1), context, visitor); - if (!context.cfg().isDeadBlock(context.cfg().getCurrentBlock())) { - context.cfg().addInstruction(insts.GotoInstruction()); - PreBasicBlock bodyB = context.cfg().getCurrentBlock(); - context.cfg().addEdge(bodyB, headerB); - - // next block - context.cfg().newBlock(false); - } - - PreBasicBlock nextB = context.cfg().getCurrentBlock(); - - // control flow mapping; - context.cfg().addEdge(branchB, nextB); - return true; - } - - // Make final to prevent overriding - protected final void leaveLoopHeader(CAstNode n, WalkContext c, CAstVisitor visitor) { /* empty */ - } - - protected final void leaveLoop(CAstNode n, WalkContext c, CAstVisitor visitor) { /* empty */ - } - - protected boolean visitGetCaughtException(CAstNode n, WalkContext c, CAstVisitor visitor) { /* empty */ - return false; - } - - protected void leaveGetCaughtException(CAstNode n, WalkContext c, CAstVisitor visitor) { - WalkContext context = (WalkContext) c; - String nm = (String) n.getChild(0).getValue(); - context.currentScope().declare(new FinalCAstSymbol(nm)); - context.cfg().addInstruction( - insts.GetCaughtExceptionInstruction(context.cfg().getCurrentBlock().getNumber(), context.currentScope().lookup(nm) - .valueNumber())); - } - - protected boolean visitThis(CAstNode n, WalkContext c, CAstVisitor visitor) { /* empty */ - return false; - } - - protected void leaveThis(CAstNode n, WalkContext c, CAstVisitor visitor) { - c.setValue(n, 1); - } - - protected boolean visitSuper(CAstNode n, WalkContext c, CAstVisitor visitor) { /* empty */ - return false; - } - - protected void leaveSuper(CAstNode n, WalkContext c, CAstVisitor visitor) { - c.setValue(n, 1); - } - - protected boolean visitCall(CAstNode n, WalkContext c, CAstVisitor visitor) { - WalkContext context = (WalkContext) c; - int result = context.currentScope().allocateTempValue(); - c.setValue(n, result); - return false; - } - - protected void leaveCall(CAstNode n, WalkContext c, CAstVisitor visitor) { - WalkContext context = (WalkContext) c; - int result = c.getValue(n); - int exp = context.currentScope().allocateTempValue(); - int fun = c.getValue(n.getChild(0)); - CAstNode functionName = n.getChild(1); - int[] args = new int[n.getChildCount() - 2]; - for (int i = 0; i < args.length; i++) { - args[i] = c.getValue(n.getChild(i + 2)); - } - doCall(context, n, result, exp, functionName, fun, args); - } - - protected boolean visitVar(CAstNode n, WalkContext c, CAstVisitor visitor) { /* empty */ - return false; - } - - protected void leaveVar(CAstNode n, WalkContext c, CAstVisitor visitor) { - WalkContext context = (WalkContext) c; - String nm = (String) n.getChild(0).getValue(); - assert nm != null : "cannot find var for " + CAstPrinter.print(n, context.getSourceMap()); - Symbol s = context.currentScope().lookup(nm); - assert s != null : "cannot find symbol for " + nm + " at " + CAstPrinter.print(n, context.getSourceMap()); - if (context.currentScope().isGlobal(s)) { - c.setValue(n, doGlobalRead(n, context, nm)); - } else if (context.currentScope().isLexicallyScoped(s)) { - c.setValue(n, doLexicallyScopedRead(n, context, nm)); - } else { - c.setValue(n, doLocalRead(context, nm)); - } - } - - protected boolean visitConstant(CAstNode n, WalkContext c, CAstVisitor visitor) { /* empty */ - return false; - } - - protected void leaveConstant(CAstNode n, WalkContext c, CAstVisitor visitor) { - WalkContext context = (WalkContext) c; - c.setValue(n, context.currentScope().getConstantValue(n.getValue())); - } - - protected boolean visitBinaryExpr(CAstNode n, WalkContext c, CAstVisitor visitor) { - WalkContext context = (WalkContext) c; - int result = context.currentScope().allocateTempValue(); - c.setValue(n, result); - return false; - } - - private boolean handleBinaryOpThrow(CAstNode n, CAstNode op, WalkContext context) { - // currently, only integer / and % throw exceptions - boolean mayBeInteger = false; - Collection labels = context.getControlFlow().getTargetLabels(n); - if (!labels.isEmpty()) { - context.cfg().addPreNode(n, context.getUnwindState()); - - mayBeInteger = true; - assert op == CAstOperator.OP_DIV || op == CAstOperator.OP_MOD : CAstPrinter.print(n); - for (Iterator iter = labels.iterator(); iter.hasNext();) { - Object label = iter.next(); - CAstNode target = context.getControlFlow().getTarget(n, label); - if (target == CAstControlFlowMap.EXCEPTION_TO_EXIT) - context.cfg().addPreEdgeToExit(n, true); - else - context.cfg().addPreEdge(n, target, true); - } - } - - return mayBeInteger; - } - - protected void leaveBinaryExpr(CAstNode n, WalkContext c, CAstVisitor visitor) { - WalkContext context = (WalkContext) c; - int result = c.getValue(n); - CAstNode l = n.getChild(1); - CAstNode r = n.getChild(2); - assert c.getValue(r) != -1 : CAstPrinter.print(n); - assert c.getValue(l) != -1 : CAstPrinter.print(n); - - boolean mayBeInteger = handleBinaryOpThrow(n, n.getChild(0), context); - - context.cfg().addInstruction( - insts.BinaryOpInstruction(translateBinaryOpcode(n.getChild(0)), false, false, result, c.getValue(l), c.getValue(r), - mayBeInteger)); - - if (mayBeInteger) { - context.cfg().newBlock(true); - } - } - - protected boolean visitUnaryExpr(CAstNode n, WalkContext c, CAstVisitor visitor) { - WalkContext context = (WalkContext) c; - int result = context.currentScope().allocateTempValue(); - c.setValue(n, result); - return false; - } - - protected void leaveUnaryExpr(CAstNode n, WalkContext c, CAstVisitor visitor) { - WalkContext context = (WalkContext) c; - int result = c.getValue(n); - CAstNode v = n.getChild(1); - context.cfg().addInstruction(insts.UnaryOpInstruction(translateUnaryOpcode(n.getChild(0)), result, c.getValue(v))); - } - - protected boolean visitArrayLength(CAstNode n, WalkContext c, CAstVisitor visitor) { - WalkContext context = (WalkContext) c; - int result = context.currentScope().allocateTempValue(); - c.setValue(n, result); - return false; - } - - protected void leaveArrayLength(CAstNode n, WalkContext c, CAstVisitor visitor) { - WalkContext context = (WalkContext) c; - int result = c.getValue(n); - int arrayValue = c.getValue(n.getChild(0)); - context.cfg().addInstruction(insts.ArrayLengthInstruction(result, arrayValue)); - } - - protected boolean visitArrayRef(CAstNode n, WalkContext c, CAstVisitor visitor) { /* empty */ - return false; - } - - protected void leaveArrayRef(CAstNode n, WalkContext c, CAstVisitor visitor) { - WalkContext context = (WalkContext) c; - int arrayValue = c.getValue(n.getChild(0)); - int result = context.currentScope().allocateTempValue(); - c.setValue(n, result); - arrayOpHandler.doArrayRead(context, result, arrayValue, n, gatherArrayDims(c, n)); - } - - protected boolean visitDeclStmt(CAstNode n, WalkContext c, CAstVisitor visitor) { /* empty */ - return false; - } - - // TODO: should we handle exploded declaration nodes here instead? - protected void leaveDeclStmt(CAstNode n, WalkContext c, CAstVisitor visitor) { - CAstSymbol s = (CAstSymbol) n.getChild(0).getValue(); - String nm = s.name(); - Scope scope = c.currentScope(); - if (n.getChildCount() == 2) { - CAstNode v = n.getChild(1); - if (scope.contains(nm) && scope.lookup(nm).getDefiningScope() == scope) { - assert !s.isFinal(); - doLocalWrite(c, nm, c.getValue(v)); - } else if (v.getKind() != CAstNode.CONSTANT && v.getKind() != CAstNode.VAR && v.getKind() != CAstNode.THIS) { - scope.declare(s, c.getValue(v)); - } else { - scope.declare(s); - doLocalWrite(c, nm, c.getValue(v)); - } - } else { - c.currentScope().declare(s); - } - } - - protected boolean visitReturn(CAstNode n, WalkContext c, CAstVisitor visitor) { /* empty */ - return false; - } - - protected void leaveReturn(CAstNode n, WalkContext c, CAstVisitor visitor) { - WalkContext context = (WalkContext) c; - if (n.getChildCount() > 0) { - context.cfg().addInstruction(insts.ReturnInstruction(c.getValue(n.getChild(0)), false)); - } else { - context.cfg().addInstruction(insts.ReturnInstruction()); - } - - context.cfg().addPreNode(n, context.getUnwindState()); - context.cfg().newBlock(false); - context.cfg().addPreEdgeToExit(n, false); - } - - protected boolean visitIfgoto(CAstNode n, WalkContext c, CAstVisitor visitor) { /* empty */ - return false; - } - - protected void leaveIfgoto(CAstNode n, WalkContext c, CAstVisitor visitor) { - WalkContext context = (WalkContext) c; - if (n.getChildCount() == 1) { - context.cfg().addInstruction( - insts.ConditionalBranchInstruction(translateConditionOpcode(CAstOperator.OP_NE), null, c.getValue(n.getChild(0)), context - .currentScope().getConstantValue(new Integer(0)))); - } else if (n.getChildCount() == 3) { - context.cfg().addInstruction( - insts.ConditionalBranchInstruction(translateConditionOpcode(n.getChild(0)), null, c.getValue(n.getChild(1)), - c.getValue(n.getChild(2)))); - } else { - Assertions.UNREACHABLE(); - } - - context.cfg().addPreNode(n, context.getUnwindState()); - context.cfg().newBlock(true); - context.cfg().addPreEdge(n, context.getControlFlow().getTarget(n, Boolean.TRUE), false); - } - - protected boolean visitGoto(CAstNode n, WalkContext c, CAstVisitor visitor) { /* empty */ - return false; - } - - protected void leaveGoto(CAstNode n, WalkContext c, CAstVisitor visitor) { - WalkContext context = (WalkContext) c; - if (!context.cfg().isDeadBlock(context.cfg().getCurrentBlock())) { - context.cfg().addPreNode(n, context.getUnwindState()); - context.cfg().addInstruction(insts.GotoInstruction()); - context.cfg().newBlock(false); - if (context.getControlFlow().getTarget(n, null) == null) { - assert context.getControlFlow().getTarget(n, null) != null : context.getControlFlow() + " does not map " + n + " (" - + context.getSourceMap().getPosition(n) + ")"; - } - context.cfg().addPreEdge(n, context.getControlFlow().getTarget(n, null), false); - } - } - - protected boolean visitLabelStmt(CAstNode n, WalkContext c, CAstVisitor visitor) { - WalkContext context = (WalkContext) c; - if (!context.getControlFlow().getSourceNodes(n).isEmpty()) { - context.cfg().newBlock(true); - context.cfg().addPreNode(n, context.getUnwindState()); - } - return false; - } - - protected void leaveLabelStmt(CAstNode n, WalkContext c, CAstVisitor visitor) { /* empty */ - } - - protected void processIf(CAstNode n, boolean isExpr, WalkContext c, CAstVisitor visitor) { - WalkContext context = (WalkContext) c; - PreBasicBlock trueB = null, falseB = null; - // conditional - CAstNode l = n.getChild(0); - visitor.visit(l, context, visitor); - context.cfg().addInstruction( - insts.ConditionalBranchInstruction(translateConditionOpcode(CAstOperator.OP_EQ), null, c.getValue(l), context.currentScope() - .getConstantValue(new Integer(0)))); - PreBasicBlock srcB = context.cfg().getCurrentBlock(); - // true clause - context.cfg().newBlock(true); - CAstNode r = n.getChild(1); - visitor.visit(r, context, visitor); - if (isExpr) - context.cfg().addInstruction(new AssignInstruction(c.getValue(n), c.getValue(r))); - if (n.getChildCount() == 3) { - if (!context.cfg().isDeadBlock(context.cfg().getCurrentBlock())) { - context.cfg().addInstruction(insts.GotoInstruction()); - trueB = context.cfg().getCurrentBlock(); - - // false clause - context.cfg().newBlock(false); - } - - falseB = context.cfg().getCurrentBlock(); - CAstNode f = n.getChild(2); - visitor.visit(f, context, visitor); - if (isExpr) - context.cfg().addInstruction(new AssignInstruction(c.getValue(n), c.getValue(f))); - } - - // end - context.cfg().newBlock(true); - if (n.getChildCount() == 3) { - if (trueB != null) - context.cfg().addEdge(trueB, context.cfg().getCurrentBlock()); - context.cfg().addEdge(srcB, falseB); - } else { - context.cfg().addEdge(srcB, context.cfg().getCurrentBlock()); - } - } - - // Make final to prevent overriding - protected final void leaveIfStmtCondition(CAstNode n, WalkContext c, CAstVisitor visitor) { /* empty */ - } - - protected final void leaveIfStmtTrueClause(CAstNode n, WalkContext c, CAstVisitor visitor) { /* empty */ - } - - protected final void leaveIfStmt(CAstNode n, WalkContext c, CAstVisitor visitor) { /* empty */ - } - - protected final void leaveIfExprCondition(CAstNode n, WalkContext c, CAstVisitor visitor) { /* empty */ - } - - protected final void leaveIfExprTrueClause(CAstNode n, WalkContext c, CAstVisitor visitor) { /* empty */ - } - - protected final void leaveIfExpr(CAstNode n, WalkContext c, CAstVisitor visitor) { /* empty */ - } - - protected boolean visitIfStmt(CAstNode n, WalkContext c, CAstVisitor visitor) { - processIf(n, false, c, visitor); - return true; - } - - protected boolean visitIfExpr(CAstNode n, WalkContext c, CAstVisitor visitor) { - WalkContext context = (WalkContext) c; - int result = context.currentScope().allocateTempValue(); - c.setValue(n, result); - processIf(n, true, c, visitor); - return true; - } - - protected boolean visitNew(CAstNode n, WalkContext c, CAstVisitor visitor) { /* empty */ - return false; - } - - protected void leaveNew(CAstNode n, WalkContext c, CAstVisitor visitor) { - WalkContext context = (WalkContext) c; - - int result = context.currentScope().allocateTempValue(); - c.setValue(n, result); - - int[] arguments; - if (n.getChildCount() <= 1) { - arguments = null; - } else { - arguments = new int[n.getChildCount() - 1]; - for (int i = 1; i < n.getChildCount(); i++) { - arguments[i - 1] = c.getValue(n.getChild(i)); - } - } - doNewObject(context, n, result, n.getChild(0).getValue(), arguments); - } - - protected boolean visitObjectLiteral(CAstNode n, WalkContext c, CAstVisitor visitor) { /* empty */ - return false; - } - - protected void leaveObjectLiteralFieldInit(CAstNode n, int i, WalkContext c, CAstVisitor visitor) { - WalkContext context = (WalkContext) c; - if (n.getChild(i).getKind() == CAstNode.EMPTY) { - handleUnspecifiedLiteralKey(context, n, i, visitor); - } - doFieldWrite(context, c.getValue(n.getChild(0)), n.getChild(i), n, c.getValue(n.getChild(i + 1))); - } - - protected void leaveObjectLiteral(CAstNode n, WalkContext c, CAstVisitor visitor) { - c.setValue(n, c.getValue(n.getChild(0))); - } - - protected boolean visitArrayLiteral(CAstNode n, WalkContext c, CAstVisitor visitor) { /* empty */ - return false; - } - - protected void leaveArrayLiteralObject(CAstNode n, WalkContext c, CAstVisitor visitor) { - c.setValue(n, c.getValue(n.getChild(0))); - } - - protected void leaveArrayLiteralInitElement(CAstNode n, int i, WalkContext c, CAstVisitor visitor) { - WalkContext context = (WalkContext) c; - arrayOpHandler.doArrayWrite(context, c.getValue(n.getChild(0)), n, - new int[] { context.currentScope().getConstantValue(new Integer(i - 1)) }, c.getValue(n.getChild(i))); - } - - protected void leaveArrayLiteral(CAstNode n, WalkContext c, CAstVisitor visitor) { /* empty */ - } - - protected boolean visitObjectRef(CAstNode n, WalkContext c, CAstVisitor visitor) { - WalkContext context = (WalkContext) c; - int result = context.currentScope().allocateTempValue(); - c.setValue(n, result); - return false; - } - - protected void leaveObjectRef(CAstNode n, WalkContext c, CAstVisitor visitor) { - WalkContext context = (WalkContext) c; - int result = c.getValue(n); - CAstNode elt = n.getChild(1); - doFieldRead(context, result, c.getValue(n.getChild(0)), elt, n); - } - - public boolean visitAssign(CAstNode n, WalkContext c, CAstVisitor visitor) { /* empty */ - return false; - } - - public void leaveAssign(CAstNode n, WalkContext c, CAstVisitor visitor) { - if (n.getKind() == CAstNode.ASSIGN) { - c.setValue(n, c.getValue(n.getChild(1))); - } else { - c.setValue(n, c.getValue(n.getChild(0))); - } - } - - private int[] gatherArrayDims(WalkContext c, CAstNode n) { - int numDims = n.getChildCount() - 2; - int[] dims = new int[numDims]; - for (int i = 0; i < numDims; i++) - dims[i] = c.getValue(n.getChild(i + 2)); - return dims; - } - - /* Prereq: a.getKind() == ASSIGN_PRE_OP || a.getKind() == ASSIGN_POST_OP */ - protected int processAssignOp(CAstNode n, CAstNode v, CAstNode a, int temp, boolean post, WalkContext c) { - WalkContext context = (WalkContext) c; - int rval = c.getValue(v); - CAstNode op = a.getChild(2); - int temp2 = context.currentScope().allocateTempValue(); - - boolean mayBeInteger = handleBinaryOpThrow(a, op, context); - - context.cfg().addInstruction( - insts.BinaryOpInstruction(translateBinaryOpcode(op), false, false, temp2, temp, rval, mayBeInteger)); - - if (mayBeInteger) { - context.cfg().newBlock(true); - } - - return temp2; - } - - protected boolean visitArrayRefAssign(CAstNode n, CAstNode v, CAstNode a, WalkContext c, CAstVisitor visitor) { /* empty */ - return false; - } - - protected void leaveArrayRefAssign(CAstNode n, CAstNode v, CAstNode a, WalkContext c, CAstVisitor visitor) { - WalkContext context = (WalkContext) c; - int rval = c.getValue(v); - c.setValue(n, rval); - arrayOpHandler.doArrayWrite(context, c.getValue(n.getChild(0)), n, gatherArrayDims(c, n), rval); - } - - protected boolean visitArrayRefAssignOp(CAstNode n, CAstNode v, CAstNode a, boolean pre, WalkContext c, CAstVisitor visitor) { /* empty */ - return false; - } - - protected void leaveArrayRefAssignOp(CAstNode n, CAstNode v, CAstNode a, boolean pre, WalkContext c, CAstVisitor visitor) { - WalkContext context = (WalkContext) c; - int temp = context.currentScope().allocateTempValue(); - int[] dims = gatherArrayDims(c, n); - arrayOpHandler.doArrayRead(context, temp, c.getValue(n.getChild(0)), n, dims); - int rval = processAssignOp(n, v, a, temp, !pre, c); - c.setValue(n, pre ? rval : temp); - arrayOpHandler.doArrayWrite(context, c.getValue(n.getChild(0)), n, dims, rval); - } - - protected boolean visitObjectRefAssign(CAstNode n, CAstNode v, CAstNode a, WalkContext c, CAstVisitor visitor) { /* empty */ - return false; - } - - protected void leaveObjectRefAssign(CAstNode n, CAstNode v, CAstNode a, WalkContext c, CAstVisitor visitor) { - WalkContext context = (WalkContext) c; - int rval = c.getValue(v); - c.setValue(n, rval); - doFieldWrite(context, c.getValue(n.getChild(0)), n.getChild(1), n, rval); - } - - protected void processObjectRefAssignOp(CAstNode n, CAstNode v, CAstNode a, WalkContext c) { - } - - protected boolean visitObjectRefAssignOp(CAstNode n, CAstNode v, CAstNode a, boolean pre, WalkContext c, CAstVisitor visitor) { /* empty */ - return false; - } - - protected void leaveObjectRefAssignOp(CAstNode n, CAstNode v, CAstNode a, boolean pre, WalkContext c, CAstVisitor visitor) { - WalkContext context = (WalkContext) c; - int temp = context.currentScope().allocateTempValue(); - doFieldRead(context, temp, c.getValue(n.getChild(0)), n.getChild(1), n); - int rval = processAssignOp(n, v, a, temp, !pre, c); - c.setValue(n, pre ? rval : temp); - doFieldWrite(context, c.getValue(n.getChild(0)), n.getChild(1), n, rval); - } - - protected boolean visitBlockExprAssign(CAstNode n, CAstNode v, CAstNode a, WalkContext c, CAstVisitor visitor) { /* empty */ - return false; - } - - protected void leaveBlockExprAssign(CAstNode n, CAstNode v, CAstNode a, WalkContext c, CAstVisitor visitor) { - c.setValue(n, c.getValue(n.getChild(n.getChildCount() - 1))); - } - - protected boolean visitBlockExprAssignOp(CAstNode n, CAstNode v, CAstNode a, boolean pre, WalkContext c, CAstVisitor visitor) { /* empty */ - return false; - } - - protected void leaveBlockExprAssignOp(CAstNode n, CAstNode v, CAstNode a, boolean pre, WalkContext c, CAstVisitor visitor) { /* empty */ - c.setValue(n, c.getValue(n.getChild(n.getChildCount() - 1))); - } - - protected boolean visitVarAssign(CAstNode n, CAstNode v, CAstNode a, WalkContext c, CAstVisitor visitor) { /* empty */ - return false; - } - - /** - * assign rval to nm as appropriate, depending on the scope of ls - */ - protected void assignValue(CAstNode n, WalkContext context, Symbol ls, String nm, int rval) { - if (context.currentScope().isGlobal(ls)) - doGlobalWrite(context, nm, rval); - else if (context.currentScope().isLexicallyScoped(ls)) { - doLexicallyScopedWrite(context, nm, rval); - } else { - assert rval != -1 : CAstPrinter.print(n, context.top().getSourceMap()); - doLocalWrite(context, nm, rval); - } - } - - protected void leaveVarAssign(CAstNode n, CAstNode v, CAstNode a, WalkContext c, CAstVisitor visitor) { - WalkContext context = (WalkContext) c; - int rval = c.getValue(v); - String nm = (String) n.getChild(0).getValue(); - Symbol ls = context.currentScope().lookup(nm); - c.setValue(n, rval); - assignValue(n, context, ls, nm, rval); - } - - protected boolean visitVarAssignOp(CAstNode n, CAstNode v, CAstNode a, boolean pre, WalkContext c, CAstVisitor visitor) { /* empty */ - return false; - } - - protected void leaveVarAssignOp(CAstNode n, CAstNode v, CAstNode a, boolean pre, WalkContext c, CAstVisitor visitor) { - WalkContext context = (WalkContext) c; - String nm = (String) n.getChild(0).getValue(); - Symbol ls = context.currentScope().lookup(nm); - int temp; - - if (context.currentScope().isGlobal(ls)) - temp = doGlobalRead(n, context, nm); - else if (context.currentScope().isLexicallyScoped(ls)) { - temp = doLexicallyScopedRead(n, context, nm); - } else { - temp = doLocalRead(context, nm); - } - - if (!pre) { - int ret = context.currentScope().allocateTempValue(); - context.cfg().addInstruction(new AssignInstruction(ret, temp)); - c.setValue(n, ret); - } - - int rval = processAssignOp(n, v, a, temp, !pre, c); - - if (pre) { - c.setValue(n, rval); - } - - if (context.currentScope().isGlobal(ls)) { - doGlobalWrite(context, nm, rval); - } else if (context.currentScope().isLexicallyScoped(ls)) { - doLexicallyScopedWrite(context, nm, rval); - } else { - doLocalWrite(context, nm, rval); - } - } - - private boolean isSimpleSwitch(CAstNode n, WalkContext context, CAstVisitor visitor) { - CAstControlFlowMap ctrl = context.getControlFlow(); - Collection caseLabels = ctrl.getTargetLabels(n); - for (Iterator kases = caseLabels.iterator(); kases.hasNext();) { - Object x = kases.next(); - - if (x == CAstControlFlowMap.SWITCH_DEFAULT) - continue; - - CAstNode xn = (CAstNode) x; - if (xn.getKind() == CAstNode.CONSTANT) { - visitor.visit(xn, context, visitor); - if (context.getValue(xn) != -1) { - if (context.currentScope().isConstant(context.getValue(xn))) { - Object val = context.currentScope().getConstantObject(context.getValue(xn)); - if (val instanceof Number) { - Number num = (Number) val; - if ((double) num.intValue() == num.doubleValue()) { - continue; - } - } - } - } - } - - return false; - } - - return true; - } - - private void doSimpleSwitch(CAstNode n, WalkContext context, CAstVisitor visitor) { - PreBasicBlock defaultHackBlock = null; - CAstControlFlowMap ctrl = context.getControlFlow(); - - CAstNode switchValue = n.getChild(0); - visitor.visit(switchValue, context, visitor); - int v = context.getValue(switchValue); - - boolean hasExplicitDefault = ctrl.getTarget(n, CAstControlFlowMap.SWITCH_DEFAULT) != null; - - Collection caseLabels = ctrl.getTargetLabels(n); - int cases = caseLabels.size(); - if (hasExplicitDefault) - cases--; - int[] casesAndLabels = new int[cases * 2]; - - int defaultBlock = context.cfg().getCurrentBlock().getGraphNodeId() + 1; - - context.cfg().addInstruction(insts.SwitchInstruction(v, defaultBlock, casesAndLabels)); - context.cfg().addPreNode(n, context.getUnwindState()); - // PreBasicBlock switchB = context.cfg().getCurrentBlock(); - context.cfg().newBlock(true); - - context.cfg().addInstruction(insts.GotoInstruction()); - defaultHackBlock = context.cfg().getCurrentBlock(); - context.cfg().newBlock(false); - - CAstNode switchBody = n.getChild(1); - visitor.visit(switchBody, context, visitor); - context.cfg().newBlock(true); - - if (!hasExplicitDefault) { - context.cfg().addEdge(defaultHackBlock, context.cfg().getCurrentBlock()); - } - - int cn = 0; - for (Iterator kases = caseLabels.iterator(); kases.hasNext();) { - Object x = kases.next(); - CAstNode target = ctrl.getTarget(n, x); - if (x == CAstControlFlowMap.SWITCH_DEFAULT) { - context.cfg().addEdge(defaultHackBlock, context.cfg().getBlock(target)); - } else { - Number caseLabel = (Number) context.currentScope().getConstantObject(context.getValue((CAstNode) x)); - casesAndLabels[2 * cn] = caseLabel.intValue(); - casesAndLabels[2 * cn + 1] = context.cfg().getBlock(target).getGraphNodeId(); - cn++; - - context.cfg().addPreEdge(n, target, false); - } - } - } - - private void doIfConvertSwitch(CAstNode n, WalkContext context, CAstVisitor visitor) { - CAstControlFlowMap ctrl = context.getControlFlow(); - context.cfg().addPreNode(n, context.getUnwindState()); - - CAstNode switchValue = n.getChild(0); - visitor.visit(switchValue, context, visitor); - int v = context.getValue(switchValue); - - Collection caseLabels = ctrl.getTargetLabels(n); - Map labelToBlock = new LinkedHashMap(); - for (Iterator kases = caseLabels.iterator(); kases.hasNext();) { - Object x = kases.next(); - if (x != CAstControlFlowMap.SWITCH_DEFAULT) { - visitor.visit((CAstNode) x, context, visitor); - context.cfg().addInstruction( - insts.ConditionalBranchInstruction(translateConditionOpcode(CAstOperator.OP_EQ), null, v, context.getValue((CAstNode) x))); - labelToBlock.put(x, context.cfg().getCurrentBlock()); - context.cfg().newBlock(true); - } - } - - PreBasicBlock defaultGotoBlock = context.cfg().getCurrentBlock(); - context.cfg().addInstruction(insts.GotoInstruction()); - context.cfg().newBlock(false); - - CAstNode switchBody = n.getChild(1); - visitor.visit(switchBody, context, visitor); - context.cfg().newBlock(true); - - for (Iterator kases = caseLabels.iterator(); kases.hasNext();) { - Object x = kases.next(); - if (x != CAstControlFlowMap.SWITCH_DEFAULT) { - CAstNode target = ctrl.getTarget(n, x); - context.cfg().addEdge(labelToBlock.get(x), context.cfg().getBlock(target)); - } - } - - if (ctrl.getTarget(n, CAstControlFlowMap.SWITCH_DEFAULT) == null) { - context.cfg().addEdge(defaultGotoBlock, context.cfg().getCurrentBlock()); - } else { - CAstNode target = ctrl.getTarget(n, CAstControlFlowMap.SWITCH_DEFAULT); - context.cfg().addEdge(defaultGotoBlock, context.cfg().getBlock(target)); - } - } - - protected boolean visitSwitch(CAstNode n, WalkContext c, CAstVisitor visitor) { - WalkContext context = (WalkContext) c; - if (isSimpleSwitch(n, context, visitor)) { - doSimpleSwitch(n, context, visitor); - } else { - doIfConvertSwitch(n, context, visitor); - } - return true; - } - - // Make final to prevent overriding - protected final void leaveSwitchValue(CAstNode n, WalkContext c, CAstVisitor visitor) { /* empty */ - } - - protected final void leaveSwitch(CAstNode n, WalkContext c, CAstVisitor visitor) { /* empty */ - } - - protected boolean visitThrow(CAstNode n, WalkContext c, CAstVisitor visitor) { /* empty */ - return false; - } - - protected void leaveThrow(CAstNode n, WalkContext c, CAstVisitor visitor) { - WalkContext context = (WalkContext) c; - doThrow(context, c.getValue(n.getChild(0))); - - context.cfg().addPreNode(n, context.getUnwindState()); - context.cfg().newBlock(false); - - Collection labels = context.getControlFlow().getTargetLabels(n); - for (Iterator iter = labels.iterator(); iter.hasNext();) { - Object label = iter.next(); - CAstNode target = context.getControlFlow().getTarget(n, label); - if (target == CAstControlFlowMap.EXCEPTION_TO_EXIT) - context.cfg().addPreEdgeToExit(n, true); - else - context.cfg().addPreEdge(n, target, true); - } - } - - protected boolean visitCatch(CAstNode n, WalkContext c, CAstVisitor visitor) { - WalkContext context = (WalkContext) c; - - // unreachable catch block - if (context.getControlFlow().getSourceNodes(n).isEmpty()) { - return true; - } - - String id = (String) n.getChild(0).getValue(); - context.cfg().setCurrentBlockAsHandler(); - if (!context.currentScope().contains(id)) { - context.currentScope().declare(new FinalCAstSymbol(id)); - } - context.cfg().addInstruction( - insts.GetCaughtExceptionInstruction(context.cfg().getCurrentBlock().getNumber(), context.currentScope().lookup(id) - .valueNumber())); - - context.cfg().addPreNode(n, context.getUnwindState()); - - CAstType caughtType = getTypeForNode(context, n); - if (caughtType != null) { - TypeReference caughtRef = makeType(caughtType); - context.setCatchType(n, caughtRef); - } else { - context.setCatchType(n, defaultCatchType()); - } - - return false; - } - - protected void leaveCatch(CAstNode n, WalkContext c, CAstVisitor visitor) { /* empty */ - } - - protected boolean visitUnwind(CAstNode n, WalkContext c, CAstVisitor visitor) { /* empty */ - return false; - } - - protected void leaveUnwind(CAstNode n, WalkContext c, CAstVisitor visitor) { /* empty */ - } - - private boolean hasIncomingEdges(CAstNode n, WalkContext context) { - if (context.cfg().hasDelayedEdges(n)) { - return true; - } else { - for (int i = 0; i < n.getChildCount(); i++) { - if (hasIncomingEdges(n.getChild(i), context)) { - return true; - } - } - - return false; - } - } - - protected boolean visitTry(final CAstNode n, WalkContext c, CAstVisitor visitor) { - final WalkContext context = (WalkContext) c; - boolean addSkipCatchGoto = false; - visitor.visit(n.getChild(0), context, visitor); - PreBasicBlock endOfTry = context.cfg().getCurrentBlock(); - - if (!hasIncomingEdges(n.getChild(1), context)) { - if (loader instanceof CAstAbstractLoader) { - ((CAstAbstractLoader) loader).addMessage(context.getModule(), new Warning(Warning.MILD) { - @Override - public String getMsg() { - return "Dead catch block at " + getPosition(context.getSourceMap(), n.getChild(1)); - } - }); - } - return true; - } - - if (!context.cfg().isDeadBlock(context.cfg().getCurrentBlock())) { - addSkipCatchGoto = true; - context.cfg().addInstruction(insts.GotoInstruction()); - context.cfg().newBlock(false); - } - - context.cfg().noteCatchBlock(); - visitor.visit(n.getChild(1), context, visitor); - - if (!context.cfg().isDeadBlock(context.cfg().getCurrentBlock())) { - context.cfg().newBlock(true); - } - - if (addSkipCatchGoto) { - PreBasicBlock afterBlock = context.cfg().getCurrentBlock(); - context.cfg().addEdge(endOfTry, afterBlock); - } - return true; - } - - // Make final to prevent overriding - protected final void leaveTryBlock(CAstNode n, WalkContext c, CAstVisitor visitor) { /* empty */ - } - - protected final void leaveTry(CAstNode n, WalkContext c, CAstVisitor visitor) { /* empty */ - } - - protected boolean visitEmpty(CAstNode n, WalkContext c, CAstVisitor visitor) { /* empty */ - return false; - } - - protected void leaveEmpty(CAstNode n, WalkContext c, CAstVisitor visitor) { - WalkContext context = (WalkContext) c; - c.setValue(n, context.currentScope().getConstantValue(null)); - } - - protected boolean visitPrimitive(CAstNode n, WalkContext c, CAstVisitor visitor) { /* empty */ - return false; - } - - protected void leavePrimitive(CAstNode n, WalkContext c, CAstVisitor visitor) { - WalkContext context = (WalkContext) c; - int result = context.currentScope().allocateTempValue(); - c.setValue(n, result); - - doPrimitive(result, context, n); - } - - protected boolean visitVoid(CAstNode n, WalkContext c, CAstVisitor visitor) { /* empty */ - return false; - } - - protected void leaveVoid(CAstNode n, WalkContext c, CAstVisitor visitor) { - c.setValue(n, -1); - } - - protected boolean visitAssert(CAstNode n, WalkContext c, CAstVisitor visitor) { /* empty */ - return false; - } - - protected void leaveAssert(CAstNode n, WalkContext c, CAstVisitor visitor) { - WalkContext context = (WalkContext) c; - boolean fromSpec = true; - int result = c.getValue(n.getChild(0)); - if (n.getChildCount() == 2) { - assert n.getChild(1).getKind() == CAstNode.CONSTANT; - assert n.getChild(1).getValue() instanceof Boolean; - fromSpec = n.getChild(1).getValue().equals(Boolean.TRUE); - } - context.cfg().addInstruction(new AstAssertInstruction(result, fromSpec)); - } - - protected boolean visitEachElementGet(CAstNode n, WalkContext c, CAstVisitor visitor) { - return false; - } - - protected void leaveEachElementGet(CAstNode n, WalkContext c, CAstVisitor visitor) { - int result = ((WalkContext) c).currentScope().allocateTempValue(); - c.setValue(n, result); - ((WalkContext) c).cfg().addInstruction(new EachElementGetInstruction(result, c.getValue(n.getChild(0)))); - } - - protected boolean visitEachElementHasNext(CAstNode n, WalkContext c, CAstVisitor visitor) { - return false; - } - - @Override - protected void leaveEachElementHasNext(CAstNode n, WalkContext c, CAstVisitor visitor) { - int result = ((WalkContext) c).currentScope().allocateTempValue(); - c.setValue(n, result); - ((WalkContext) c).cfg().addInstruction(new EachElementHasNextInstruction(result, c.getValue(n.getChild(0)))); - } - - protected boolean visitTypeLiteralExpr(CAstNode n, WalkContext c, CAstVisitor visitor) { - return false; - } - - protected void leaveTypeLiteralExpr(CAstNode n, WalkContext c, CAstVisitor visitor) { - WalkContext wc = (WalkContext) c; - assert n.getChild(0).getKind() == CAstNode.CONSTANT; - String typeNameStr = (String) n.getChild(0).getValue(); - TypeName typeName = TypeName.string2TypeName(typeNameStr); - TypeReference typeRef = TypeReference.findOrCreate(loader.getReference(), typeName); - - int result = wc.currentScope().allocateTempValue(); - c.setValue(n, result); - - wc.cfg().addInstruction(insts.LoadMetadataInstruction(result, loader.getLanguage().getConstantType(typeRef), typeRef)); - } - - protected boolean visitIsDefinedExpr(CAstNode n, WalkContext c, CAstVisitor visitor) { - return false; - } - - protected void leaveIsDefinedExpr(CAstNode n, WalkContext c, CAstVisitor visitor) { - WalkContext wc = (WalkContext) c; - int ref = c.getValue(n.getChild(0)); - int result = wc.currentScope().allocateTempValue(); - c.setValue(n, result); - if (n.getChildCount() == 1) { - wc.cfg().addInstruction(new AstIsDefinedInstruction(result, ref)); - } else { - doIsFieldDefined(wc, result, ref, n.getChild(1)); - } - } - - protected boolean visitEcho(CAstNode n, WalkContext c, CAstVisitor visitor) { - return false; - } - - protected void leaveEcho(CAstNode n, WalkContext c, CAstVisitor visitor) { - WalkContext wc = (WalkContext) c; - - int rvals[] = new int[n.getChildCount()]; - for (int i = 0; i < n.getChildCount(); i++) { - rvals[i] = c.getValue(n.getChild(i)); - } - - wc.cfg().addInstruction(new AstEchoInstruction(rvals)); - } - - public CAstEntity getIncludedEntity(CAstNode n) { - if (n.getChild(0).getKind() == CAstNode.NAMED_ENTITY_REF) { - assert namedEntityResolver != null; - return (CAstEntity) namedEntityResolver.get(n.getChild(0).getChild(0).getValue()); - } else { - return (CAstEntity) n.getChild(0).getValue(); - } - } - - protected void leaveInclude(final CAstNode n, WalkContext c, CAstVisitor visitor) { - WalkContext wc = (WalkContext) c; - - CAstEntity included = getIncludedEntity(n); - - if (included == null) { - System.err.println(("cannot find include for " + CAstPrinter.print(n))); - System.err.println(("from:\n" + namedEntityResolver)); - } else { - final boolean isMacroExpansion = (included.getKind() == CAstEntity.MACRO_ENTITY); - - System.err.println("found " + included.getName() + " for " + CAstPrinter.print(n)); - - final CAstEntity copy = (new CAstCloner(new CAstImpl(), true) { - - private CAstNode copyIncludeExpr(CAstNode expr) { - if (expr.getValue() != null) { - return Ast.makeConstant(expr.getValue()); - } else if (expr instanceof CAstOperator) { - return expr; - } else { - CAstNode nc[] = new CAstNode[expr.getChildCount()]; - - for (int i = 0; i < expr.getChildCount(); i++) { - nc[i] = copyIncludeExpr(expr.getChild(i)); - } - - return Ast.makeNode(expr.getKind(), nc); - } - } - - protected CAstNode copyNodes(CAstNode root, final CAstControlFlowMap cfg, NonCopyingContext c, Map, CAstNode> nodeMap) { - if (isMacroExpansion && root.getKind() == CAstNode.MACRO_VAR) { - int arg = ((Number) root.getChild(0).getValue()).intValue(); - CAstNode expr = copyIncludeExpr(n.getChild(arg)); - nodeMap.put(Pair.make(root, c.key()), expr); - return expr; - } else { - return super.copyNodesHackForEclipse(root, cfg, c, nodeMap); - } - } - }).rewrite(included); - - if (copy.getAST() == null) { - System.err.println((copy.getName() + " has no AST")); - - } else { - visit(copy.getAST(), new DelegatingContext(wc) { - public CAstSourcePositionMap getSourceMap() { - return copy.getSourceMap(); - } - - public CAstControlFlowMap getControlFlow() { - return copy.getControlFlow(); - } - }, visitor); - - visitor.visitScopedEntities(copy, copy.getAllScopedEntities(), wc, visitor); - } - } - } - - protected final void walkEntities(CAstEntity N, WalkContext c) { - visitEntities(N, c, this); - } - - public final class RootContext implements WalkContext { - private final Scope globalScope; - - private final CAstEntity N; - - private final ModuleEntry module; - - private final Map entityNames = new LinkedHashMap(); - - public RootContext(CAstEntity N, ModuleEntry module) { - this.N = N; - this.module = module; - this.globalScope = makeGlobalScope(); - } - - public ModuleEntry getModule() { - return module; - } - - public String file() { - return module.getName(); - } - - public CAstEntity top() { - return N; - } - - public Scope currentScope() { - return globalScope; - } - - public Set entityScopes() { - return Collections.singleton(globalScope); - } - - public CAstSourcePositionMap getSourceMap() { - return N.getSourceMap(); - } - - public CAstControlFlowMap getControlFlow() { - return N.getControlFlow(); - } - - public IncipientCFG cfg() { - return null; - } - - public UnwindState getUnwindState() { - return null; - } - - public String getName() { - return null; - } - - public void setCatchType(int blockNumber, TypeReference catchType) { - } - - public void setCatchType(CAstNode castNode, TypeReference catchType) { - } - - public TypeReference[][] getCatchTypes() { - return null; - } - - public void addEntityName(CAstEntity e, String name) { - entityNames.put(e, name); - } - - public String getEntityName(CAstEntity e) { - if (e == null) { - return null; - } else { - assert entityNames.containsKey(e); - return "L" + entityNames.get(e); - } - } - - public boolean hasValue(CAstNode n) { - assert false; - return false; - } - - public int setValue(CAstNode n, int v) { - assert false; - return 0; - } - - public int getValue(CAstNode n) { - assert false; - return -1; - } - - public Set, Integer>> exposeNameSet(CAstEntity entity, boolean writeSet) { - assert false; - return null; - } - - public Set getAccesses(CAstEntity e) { - assert false; - return null; - } - - public Scope getGlobalScope(){ - return globalScope; - } - - }; - - /** - * translate module, represented by {@link CAstEntity} N - */ - public void translate(final CAstEntity N, final ModuleEntry module) { - if (DEBUG_TOP) - System.err.println(("translating " + module.getName())); - // this.inlinedSourceMap = inlinedSourceMap; - final ExposedNamesCollector exposedNamesCollector = new ExposedNamesCollector(); - exposedNamesCollector.run(N); - entity2ExposedNames = exposedNamesCollector.getEntity2ExposedNames(); - // CAstEntity rewrite = (new ExposedParamRenamer(new CAstImpl(), - // entity2ExposedNames)).rewrite(N); - walkEntities(N, new RootContext(N, module)); - } - - public void translate(final CAstEntity N, final WalkContext context) { - final ExposedNamesCollector exposedNamesCollector = new ExposedNamesCollector(); - exposedNamesCollector.run(N); - entity2ExposedNames = exposedNamesCollector.getEntity2ExposedNames(); - walkEntities(N, context); - } - -} +/****************************************************************************** + * Copyright (c) 2002 - 2006 IBM Corporation. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *****************************************************************************/ +package com.ibm.wala.cast.ir.translator; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.HashSet; +import java.util.Iterator; +import java.util.LinkedHashMap; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import com.ibm.wala.cast.ir.ssa.AssignInstruction; +import com.ibm.wala.cast.ir.ssa.AstAssertInstruction; +import com.ibm.wala.cast.ir.ssa.AstConstants; +import com.ibm.wala.cast.ir.ssa.AstEchoInstruction; +import com.ibm.wala.cast.ir.ssa.AstGlobalRead; +import com.ibm.wala.cast.ir.ssa.AstGlobalWrite; +import com.ibm.wala.cast.ir.ssa.AstIsDefinedInstruction; +import com.ibm.wala.cast.ir.ssa.AstLexicalAccess; +import com.ibm.wala.cast.ir.ssa.AstLexicalAccess.Access; +import com.ibm.wala.cast.ir.ssa.AstLexicalRead; +import com.ibm.wala.cast.ir.ssa.AstLexicalWrite; +import com.ibm.wala.cast.ir.ssa.EachElementGetInstruction; +import com.ibm.wala.cast.ir.ssa.EachElementHasNextInstruction; +import com.ibm.wala.cast.ir.ssa.SSAConversion; +import com.ibm.wala.cast.loader.AstMethod.DebuggingInformation; +import com.ibm.wala.cast.loader.AstMethod.LexicalInformation; +import com.ibm.wala.cast.loader.CAstAbstractLoader; +import com.ibm.wala.cast.tree.CAstControlFlowMap; +import com.ibm.wala.cast.tree.CAstEntity; +import com.ibm.wala.cast.tree.CAstNode; +import com.ibm.wala.cast.tree.CAstSourcePositionMap; +import com.ibm.wala.cast.tree.CAstSourcePositionMap.Position; +import com.ibm.wala.cast.tree.CAstSymbol; +import com.ibm.wala.cast.tree.CAstType; +import com.ibm.wala.cast.tree.impl.CAstCloner; +import com.ibm.wala.cast.tree.impl.CAstImpl; +import com.ibm.wala.cast.tree.impl.CAstOperator; +import com.ibm.wala.cast.tree.impl.CAstRewriter; +import com.ibm.wala.cast.tree.impl.CAstSymbolImpl; +import com.ibm.wala.cast.tree.impl.CAstSymbolImplBase; +import com.ibm.wala.cast.tree.visit.CAstVisitor; +import com.ibm.wala.cast.types.AstTypeReference; +import com.ibm.wala.cast.util.CAstPrinter; +import com.ibm.wala.cfg.AbstractCFG; +import com.ibm.wala.cfg.IBasicBlock; +import com.ibm.wala.classLoader.IClassLoader; +import com.ibm.wala.classLoader.IMethod; +import com.ibm.wala.classLoader.ModuleEntry; +import com.ibm.wala.shrikeBT.BinaryOpInstruction; +import com.ibm.wala.shrikeBT.ConditionalBranchInstruction; +import com.ibm.wala.shrikeBT.IBinaryOpInstruction; +import com.ibm.wala.shrikeBT.IConditionalBranchInstruction; +import com.ibm.wala.shrikeBT.IUnaryOpInstruction; +import com.ibm.wala.shrikeBT.ShiftInstruction; +import com.ibm.wala.ssa.SSAAbstractInvokeInstruction; +import com.ibm.wala.ssa.SSAGetCaughtExceptionInstruction; +import com.ibm.wala.ssa.SSAInstruction; +import com.ibm.wala.ssa.SSAInstructionFactory; +import com.ibm.wala.ssa.SSAMonitorInstruction; +import com.ibm.wala.ssa.SymbolTable; +import com.ibm.wala.types.FieldReference; +import com.ibm.wala.types.TypeName; +import com.ibm.wala.types.TypeReference; +import com.ibm.wala.util.collections.HashSetFactory; +import com.ibm.wala.util.collections.MapUtil; +import com.ibm.wala.util.collections.Pair; +import com.ibm.wala.util.debug.Assertions; +import com.ibm.wala.util.graph.INodeWithNumber; +import com.ibm.wala.util.graph.impl.SparseNumberedGraph; +import com.ibm.wala.util.intset.IntSet; +import com.ibm.wala.util.intset.IntSetUtil; +import com.ibm.wala.util.intset.MutableIntSet; +import com.ibm.wala.util.strings.Atom; +import com.ibm.wala.util.warnings.Warning; + +/** + * Common code to translate CAst to IR. Must be specialized by each language to + * handle semantics appropriately. + */ +public abstract class AstTranslator extends CAstVisitor implements ArrayOpHandler, TranslatorToIR { + + /** + * set to true to use new handling of lexical scoping + */ + public static final boolean NEW_LEXICAL = true; + + + /** + * does the language care about using type-appropriate default values? For + * Java, the answer is yes (ints should get a default value of 0, null for + * pointers, etc.). For JavaScript, the answer is no, as any variable can hold + * the value 'undefined'. + */ + protected abstract boolean useDefaultInitValues(); + + /** + * can lexical reads / writes access globals? + */ + protected abstract boolean treatGlobalsAsLexicallyScoped(); + + /** + * given accesses in a method to variables defined in an enclosing lexical + * scope, is it legal to read the variable into a local l once at the + * beginning of the method, operate on l through the method body (rather than + * performing separate lexical read / write operations), and write back the + * value in l (if necessary) at the end of the method? + */ + protected abstract boolean useLocalValuesForLexicalVars(); + + protected boolean topLevelFunctionsInGlobalScope() { + return true; + } + + /** + * for a block that catches all exceptions, what is the root exception type + * that it can catch? E.g., for Java, java.lang.Throwable + */ + protected abstract TypeReference defaultCatchType(); + + protected abstract TypeReference makeType(CAstType type); + + /** + * define a new (presumably nested) type. return true if type was successfully + * defined, false otherwise + */ + protected abstract boolean defineType(CAstEntity type, WalkContext wc); + + /** + * declare a new function, represented by N + */ + protected abstract void declareFunction(CAstEntity N, WalkContext context); + + /** + * fully define a function. invoked after all the code of the function has + * been processed + */ + protected abstract void defineFunction(CAstEntity N, WalkContext definingContext, AbstractCFG cfg, SymbolTable symtab, + boolean hasCatchBlock, TypeReference[][] caughtTypes, boolean hasMonitorOp, AstLexicalInformation lexicalInfo, + DebuggingInformation debugInfo); + + /** + * define a new field fieldEntity within topEntity + */ + protected abstract void defineField(CAstEntity topEntity, WalkContext context, CAstEntity fieldEntity); + + /** + * create the language-appropriate name for f + */ + protected abstract String composeEntityName(WalkContext parent, CAstEntity f); + + /** + * generate IR for a CAst throw expression, updating context.cfg() + */ + protected abstract void doThrow(WalkContext context, int exception); + + /** + * generate IR for a CAst array read, updating context.cfg() + */ + public abstract void doArrayRead(WalkContext context, int result, int arrayValue, CAstNode arrayRef, int[] dimValues); + + /** + * generate IR for a CAst array write, updating context.cfg() + */ + public abstract void doArrayWrite(WalkContext context, int arrayValue, CAstNode arrayRef, int[] dimValues, int rval); + + /** + * generate IR for a CAst field read, updating context.cfg() + */ + protected abstract void doFieldRead(WalkContext context, int result, int receiver, CAstNode elt, CAstNode parent); + + /** + * generate IR for a CAst field write, updating context.cfg() + */ + protected abstract void doFieldWrite(WalkContext context, int receiver, CAstNode elt, CAstNode parent, int rval); + + /** + * generate IR for a CAst function expression, updating context.cfg() + */ + protected abstract void doMaterializeFunction(CAstNode node, WalkContext context, int result, int exception, CAstEntity fn); + + /** + * generate IR for a CAst new expression, updating context.cfg() + */ + protected abstract void doNewObject(WalkContext context, CAstNode newNode, int result, Object type, int[] arguments); + + /** + * generate IR for a CAst method call expression, updating context.cfg() + */ + protected abstract void doCall(WalkContext context, CAstNode call, int result, int exception, CAstNode name, int receiver, + int[] arguments); + + /** + * used to generate instructions for array operations; defaults to this + */ + private ArrayOpHandler arrayOpHandler; + + protected boolean isExceptionLabel(Object label) { + if (label == null) + return false; + if (label instanceof Boolean) + return false; + if (label instanceof Number) + return false; + if (label == CAstControlFlowMap.SWITCH_DEFAULT) + return false; + return true; + } + + /** + * If this returns true, new global declarations get created for any attempt + * to access a non-existent variable (believe it or not, JavaScript actually + * does this!) + */ + protected boolean hasImplicitGlobals() { + return false; + } + + /** + * If this returns true, then attempts to lookup non-existent names return + * `null' rather than tripping an assertion. This can be used when special + * handling is needed for built-in names. (PHP does this) + */ + protected boolean hasSpecialUndeclaredVariables() { + return false; + } + + /** + * some languages let you omit initialization of certain fields when writing + * an object literal (e.g., PHP). This method should be overridden to handle + * such cases. + */ + protected void handleUnspecifiedLiteralKey(WalkContext context, CAstNode objectLiteralNode, int unspecifiedLiteralIndex, + CAstVisitor visitor) { + Assertions.UNREACHABLE(); + } + + /** + * generate prologue code for each function body + */ + protected void doPrologue(WalkContext context) { + // if we are SSA converting lexical accesses, add a placeholder instruction + // eventually (via mutation of its Access array) reads all relevant lexical + // variables at the beginning of the method. + if (useLocalValuesForLexicalVars()) { + context.cfg().addInstruction(new AstLexicalRead(new Access[0])); + } else { + // perform a lexical write to copy the value stored in the local + // associated with each parameter to the lexical name + final CAstEntity entity = context.top(); + Set exposedNames = entity2ExposedNames.get(entity); + if (exposedNames != null) { + for (String arg : entity.getArgumentNames()) { + if (exposedNames.contains(arg)) { + final Scope currentScope = context.currentScope(); + Symbol symbol = currentScope.lookup(arg); + assert symbol.getDefiningScope() == currentScope; + int argVN = symbol.valueNumber(); + Access A = new Access(arg, context.getEntityName(entity), argVN); + context.cfg().addInstruction(new AstLexicalWrite(A)); + } + } + } + } + } + + /** + * generate IR for call modeling creation of primitive value, updating + * context.cfg() + */ + protected abstract void doPrimitive(int resultVal, WalkContext context, CAstNode primitiveCall); + + /** + * get the value number for a name defined locally (i.e., within the current + * method) by looking up the name in context.currentScope(). Note that the + * caller is responsible for ensuring that name is defined in the local scope. + */ + protected int doLocalRead(WalkContext context, String name) { + if (!useLocalValuesForLexicalVars()) { + CAstEntity entity = context.top(); + Set exposed = entity2ExposedNames.get(entity); + if (exposed != null && exposed.contains(name)) { + return doLexReadHelper(context, name); + } + } + return context.currentScope().lookup(name).valueNumber(); + } + + /** + * add an {@link AssignInstruction} to context.cfg() that copies rval to the + * value number of local nm. Note that the caller is responsible for ensuring + * that nm is defined in the local scope. + */ + protected void doLocalWrite(WalkContext context, String nm, int rval) { + if (!useLocalValuesForLexicalVars()) { + CAstEntity entity = context.top(); + Set exposed = entity2ExposedNames.get(entity); + if (exposed != null && exposed.contains(nm)) { + // use a lexical write + doLexicallyScopedWrite(context, nm, rval); + return; + } + } + int lval = context.currentScope().lookup(nm).valueNumber(); + if (lval != rval) { + context.cfg().addInstruction(new AssignInstruction(lval, rval)); + } + } + + /** + * Note that the caller is responsible for ensuring that name is defined in a + * lexical scope. + * + * @param node + * the AST node representing the read + * @param context + * @param name + * @return + */ + protected int doLexicallyScopedRead(CAstNode node, WalkContext context, final String name) { + return doLexReadHelper(context, name); + } + + /** + * we only have this method to avoid having to pass a node parameter at other + * call sites, as would be required for + * {@link #doLexicallyScopedRead(CAstNode, WalkContext, String)} + */ + private int doLexReadHelper(WalkContext context, final String name) { + Symbol S = context.currentScope().lookup(name); + Scope definingScope = S.getDefiningScope(); + CAstEntity E = definingScope.getEntity(); + // record in declaring scope that the name is exposed to a nested scope +//<<<<<<< .mine +// Symbol S = context.currentScope().lookup(name); +// CAstEntity E = S.getDefiningScope().getEntity(); +// addExposedName(E, E, name, S.getDefiningScope().lookup(name).valueNumber(), false, context); +//======= + addExposedName(E, E, name, definingScope.lookup(name).valueNumber(), false, context); +//>>>>>>> .r4421 + + final String entityName = context.getEntityName(E); + if (useLocalValuesForLexicalVars()) { + // lexically-scoped variables can be given a single vn in a method +//<<<<<<< .mine +// Access A = new Access(name, context.getEntityName(E), vn); +//======= +//>>>>>>> .r4421 + +//<<<<<<< .mine + // (context.top() is current entity) + // record the name as exposed for the current entity, since if the name is + // updated via a call to a nested function, SSA for the current entity may + // need to be updated with the new definition +// addExposedName(context.top(), E, name, vn, false, context); +//======= + markExposedInEnclosingEntities(context, name, definingScope, E, entityName, false); +//>>>>>>> .r4421 + +//<<<<<<< .mine + // record the access; later, the Accesses in the instruction + // defining vn will be adjusted based on this information; see + // patchLexicalAccesses() +// addAccess(context, context.top(), A); +//======= + return S.valueNumber(); +//>>>>>>> .r4421 + + } else { + // lexically-scoped variables should be read from their scope each time + int result = context.currentScope().allocateTempValue(); +//<<<<<<< .mine +// Access A = new Access(name, context.getEntityName(E), result); +//======= + Access A = new Access(name, entityName, result); +//>>>>>>> .r4421 + context.cfg().addInstruction(new AstLexicalRead(A)); + markExposedInEnclosingEntities(context, name, definingScope, E, entityName, false); + return result; + } + } + + /** + * record name as exposed for the current entity and for all enclosing + * entities up to that of the defining scope, since if the name is updated via + * a call to a nested function, SSA for these entities may need to be updated + * with the new definition + * + * @param context + * @param name + * @param definingScope + * @param E + * @param entityName + * @param isWrite + */ + private void markExposedInEnclosingEntities(WalkContext context, final String name, Scope definingScope, CAstEntity E, + final String entityName, boolean isWrite) { + Scope curScope = context.currentScope(); + while (!curScope.equals(definingScope)) { + final Symbol curSymbol = curScope.lookup(name); + final int vn = curSymbol.valueNumber(); + final Access A = new Access(name, entityName, vn); + final CAstEntity entity = curScope.getEntity(); + if (entity != definingScope.getEntity()) { + addExposedName(entity, E, name, vn, isWrite, context); + // record the access; later, the Accesses in the instruction + // defining vn will be adjusted based on this information; see + // patchLexicalAccesses() + addAccess(context, entity, A); + } + curScope = curScope.getParent(); + } + } + + /** + * Note that the caller is responsible for ensuring that name is defined in a + * lexical scope. + * + */ + protected void doLexicallyScopedWrite(WalkContext context, String name, int rval) { + Symbol S = context.currentScope().lookup(name); + Scope definingScope = S.getDefiningScope(); + CAstEntity E = definingScope.getEntity(); + // record in declaring scope that the name is exposed to a nested scope + addExposedName(E, E, name, definingScope.lookup(name).valueNumber(), true, context); + + if (useLocalValuesForLexicalVars()) { + // lexically-scoped variables can be given a single vn in a method + + markExposedInEnclosingEntities(context, name, definingScope, E, context.getEntityName(E), true); + + context.cfg().addInstruction(new AssignInstruction(S.valueNumber(), rval)); + // we add write instructions at every access for now + // eventually, we may restructure the method to do a single combined write + // before exit + Access A = new Access(name, context.getEntityName(E), rval); + context.cfg().addInstruction(new AstLexicalWrite(A)); + + } else { + // lexically-scoped variables must be written in their scope each time + Access A = new Access(name, context.getEntityName(E), rval); + context.cfg().addInstruction(new AstLexicalWrite(A)); + markExposedInEnclosingEntities(context, name, definingScope, E, context.getEntityName(E), true); + } + } + + /** + * generate instructions for a read of a global + */ + protected int doGlobalRead(CAstNode node, WalkContext context, String name) { + Symbol S = context.currentScope().lookup(name); + + // Global variables can be treated as lexicals defined in the CG root, or + if (treatGlobalsAsLexicallyScoped()) { + + // lexically-scoped variables can be given a single vn in a method, or + if (useLocalValuesForLexicalVars()) { + int vn = S.valueNumber(); + Access A = new Access(name, null, vn); + + addExposedName(context.top(), null, name, vn, false, context); + addAccess(context, context.top(), A); + + return vn; + + // lexically-scoped variables can be read from their scope each time + } else { + int result = context.currentScope().allocateTempValue(); + Access A = new Access(name, null, result); + context.cfg().addInstruction(new AstLexicalRead(A)); + addAccess(context, context.top(), A); + return result; + } + + // globals can be treated as a single static location + } else { + int result = context.currentScope().allocateTempValue(); + FieldReference global = makeGlobalRef(name); + context.cfg().addInstruction(new AstGlobalRead(result, global)); + return result; + } + } + + /** + * generate instructions for a write of a global + */ + protected void doGlobalWrite(WalkContext context, String name, int rval) { + Symbol S = context.currentScope().lookup(name); + + // Global variables can be treated as lexicals defined in the CG root, or + if (treatGlobalsAsLexicallyScoped()) { + + // lexically-scoped variables can be given a single vn in a method, or + if (useLocalValuesForLexicalVars()) { + int vn = S.valueNumber(); + Access A = new Access(name, null, vn); + + addExposedName(context.top(), null, name, vn, true, context); + addAccess(context, context.top(), A); + + context.cfg().addInstruction(new AssignInstruction(vn, rval)); + context.cfg().addInstruction(new AstLexicalWrite(A)); + + // lexically-scoped variables can be read from their scope each time + } else { + Access A = new Access(name, null, rval); + context.cfg().addInstruction(new AstLexicalWrite(A)); + addAccess(context, context.top(), A); + } + + // globals can be treated as a single static location + } else { + FieldReference global = makeGlobalRef(name); + context.cfg().addInstruction(new AstGlobalWrite(global, rval)); + } + } + + /** + * generate instructions to check if ref has field, storing answer in result + */ + protected void doIsFieldDefined(WalkContext context, int result, int ref, CAstNode field) { + Assertions.UNREACHABLE(); + } + + /** + * creates a reference to a global named globalName. the declaring type and + * type of the global are both the root type. + */ + protected FieldReference makeGlobalRef(String globalName) { + TypeReference rootTypeRef = TypeReference.findOrCreate(loader.getReference(), AstTypeReference.rootTypeName); + return FieldReference.findOrCreate(rootTypeRef, Atom.findOrCreateUnicodeAtom("global " + globalName), rootTypeRef); + } + + protected final IClassLoader loader; + + /** + * for handling languages that let you include other source files named + * statically (e.g., ABAP) + */ + protected final Map namedEntityResolver; + + protected final SSAInstructionFactory insts; + + protected AstTranslator(IClassLoader loader, Map namedEntityResolver, ArrayOpHandler arrayOpHandler) { + this.loader = loader; + this.namedEntityResolver = namedEntityResolver; + this.arrayOpHandler = arrayOpHandler!=null? arrayOpHandler: this; + this.insts = loader.getInstructionFactory(); + } + + protected AstTranslator(IClassLoader loader, Map namedEntityResolver) { + this(loader, namedEntityResolver, null); + } + + protected AstTranslator(IClassLoader loader) { + this(loader, null); + } + + /** + * for keeping position information for the generated SSAInstructions and SSA + * locals + */ + private static class AstDebuggingInformation implements DebuggingInformation { + private Position codeBodyPosition; + + private String[][] valueNumberNames; + + private Position[] instructionPositions; + + AstDebuggingInformation(Position codeBodyPosition, Position[] instructionPositions, String[] names) { + this.codeBodyPosition = codeBodyPosition; + + this.instructionPositions = instructionPositions; + + valueNumberNames = new String[names.length][]; + for (int i = 0; i < names.length; i++) { + if (names[i] != null) { + valueNumberNames[i] = new String[] { names[i] }; + } else { + valueNumberNames[i] = new String[0]; + } + } + } + + public Position getCodeBodyPosition() { + return codeBodyPosition; + } + + public Position getInstructionPosition(int instructionOffset) { + return instructionPositions[instructionOffset]; + } + + public String[][] getSourceNamesForValues() { + return valueNumberNames; + } + } + + public static final boolean DEBUG_ALL = false; + + public static final boolean DEBUG_TOP = DEBUG_ALL || false; + + public static final boolean DEBUG_CFG = DEBUG_ALL || false; + + public static final boolean DEBUG_NAMES = DEBUG_ALL || false; + + public static final boolean DEBUG_LEXICAL = DEBUG_ALL || false; + + /** + * basic block implementation used in the CFGs constructed during the + * IR-generating AST traversal + */ + protected final static class PreBasicBlock implements INodeWithNumber, IBasicBlock { + private static final int NORMAL = 0; + + private static final int HANDLER = 1; + + private static final int ENTRY = 2; + + private static final int EXIT = 3; + + private int kind = NORMAL; + + private int number = -1; + + private int firstIndex = -1; + + private int lastIndex = -2; + + private final List instructions = new ArrayList(); + + public int getNumber() { + return getGraphNodeId(); + } + + public int getGraphNodeId() { + return number; + } + + public void setGraphNodeId(int number) { + this.number = number; + } + + public int getFirstInstructionIndex() { + return firstIndex; + } + + void setFirstIndex(int firstIndex) { + this.firstIndex = firstIndex; + } + + public int getLastInstructionIndex() { + return lastIndex; + } + + void setLastIndex(int lastIndex) { + this.lastIndex = lastIndex; + } + + void makeExitBlock() { + kind = EXIT; + } + + void makeEntryBlock() { + kind = ENTRY; + } + + void makeHandlerBlock() { + kind = HANDLER; + } + + public boolean isEntryBlock() { + return kind == ENTRY; + } + + public boolean isExitBlock() { + return kind == EXIT; + } + + public boolean isHandlerBlock() { + return kind == HANDLER; + } + + public String toString() { + return "PreBB" + number + ":" + firstIndex + ".." + lastIndex; + } + + List instructions() { + return instructions; + } + + public boolean isCatchBlock() { + return (lastIndex > -1) && (instructions.get(0) instanceof SSAGetCaughtExceptionInstruction); + } + + public IMethod getMethod() { + return null; + } + + public Iterator iterator() { + return instructions.iterator(); + } + } + + protected final class UnwindState { + final CAstNode unwindAst; + + final WalkContext astContext; + + final CAstVisitor astVisitor; + + UnwindState(CAstNode unwindAst, WalkContext astContext, CAstVisitor astVisitor) { + this.unwindAst = unwindAst; + this.astContext = astContext; + this.astVisitor = astVisitor; + } + + public UnwindState getParent() { + return astContext.getUnwindState(); + } + + public int hashCode() { + return astContext.hashCode() * unwindAst.hashCode() * astVisitor.hashCode(); + } + + public boolean equals(Object o) { + if (o instanceof UnwindState) { + if (((UnwindState) o).unwindAst != unwindAst) + return false; + if (((UnwindState) o).astVisitor != astVisitor) + return false; + if (getParent() == null) { + return ((UnwindState) o).getParent() == null; + } else { + return getParent().equals(((UnwindState) o).getParent()); + } + } + + return false; + } + + boolean covers(UnwindState other) { + if (equals(other)) + return true; + if (getParent() != null) + return getParent().covers(other); + return false; + } + } + + /** + * holds the control-flow graph as it is being constructed. When construction + * is complete, information is stored in an {@link AstCFG} + */ + public final class IncipientCFG extends SparseNumberedGraph { + + protected class Unwind { + private final Map unwindData = new LinkedHashMap(); + + /** + * a cache of generated blocks + */ + private final Map>, PreBasicBlock> code = new LinkedHashMap>, PreBasicBlock>(); + + void setUnwindState(PreBasicBlock block, UnwindState context) { + unwindData.put(block, context); + } + + void setUnwindState(CAstNode node, UnwindState context) { + unwindData.put(nodeToBlock.get(node), context); + } + + /** + * When adding an edge from source to target, it is possible that certain + * exception-handling code needs to be executed before the control is + * actually transfered to target. This method determines if this is the + * case, and if so, it generates the exception handler blocks and adds an + * appropriate edge to the target. It returns the basic block that should + * be the target of the edge from source (target itself if there is no + * exception-handling code, the initial catch block otherwise) + */ + public PreBasicBlock findOrCreateCode(PreBasicBlock source, PreBasicBlock target, final boolean exception) { + UnwindState sourceContext = unwindData.get(source); + final CAstNode dummy = exception ? (new CAstImpl()).makeNode(CAstNode.EMPTY) : null; + + // no unwinding is needed, so jump to target block directly + if (sourceContext == null) + return target; + + WalkContext astContext = sourceContext.astContext; + UnwindState targetContext = null; + if (target != null) + targetContext = unwindData.get(target); + + // in unwind context, but catch in same (or inner) unwind context + if (targetContext != null && targetContext.covers(sourceContext)) + return target; + + Pair> key = Pair.make(sourceContext, Pair.make(target, exception)); + + if (code.containsKey(key)) { + return code.get(key); + + } else { + int e = -1; + PreBasicBlock currentBlock = getCurrentBlock(); + if (!isDeadBlock(currentBlock)) { + addInstruction(insts.GotoInstruction()); + newBlock(false); + } + PreBasicBlock startBlock = getCurrentBlock(); + if (exception) { + setCurrentBlockAsHandler(); + e = sourceContext.astContext.currentScope().allocateTempValue(); + addInstruction(insts.GetCaughtExceptionInstruction(startBlock.getNumber(), e)); + sourceContext.astContext.setCatchType(startBlock.getNumber(), defaultCatchType()); + } + + while (sourceContext != null && (targetContext == null || !targetContext.covers(sourceContext))) { + final CAstRewriter.Rewrite ast = (new CAstCloner(new CAstImpl()) { + protected CAstNode flowOutTo(Map, CAstNode> nodeMap, CAstNode oldSource, Object label, + CAstNode oldTarget, CAstControlFlowMap orig, CAstSourcePositionMap src) { + if (exception && !isExceptionLabel(label)) { + return dummy; + } else { + return oldTarget; + } + } + }).copy(sourceContext.unwindAst, sourceContext.astContext.getControlFlow(), sourceContext.astContext.getSourceMap(), + sourceContext.astContext.top().getNodeTypeMap(), sourceContext.astContext.top().getAllScopedEntities()); + sourceContext.astVisitor.visit(ast.newRoot(), new DelegatingContext(sourceContext.astContext) { + public CAstSourcePositionMap getSourceMap() { + return ast.newPos(); + } + + public CAstControlFlowMap getControlFlow() { + return ast.newCfg(); + } + }, sourceContext.astVisitor); + + sourceContext = sourceContext.getParent(); + } + + PreBasicBlock endBlock = getCurrentBlock(); + if (exception) { + addPreNode(dummy); + doThrow(astContext, e); + } else { + addInstruction(insts.GotoInstruction()); + } + newBlock(false); + + addEdge(currentBlock, getCurrentBlock()); + if (target != null) { + addEdge(endBlock, target); + + // `null' target is idiom for branch/throw to exit + } else { + addDelayedEdge(endBlock, exitMarker, exception); + } + + code.put(key, startBlock); + return startBlock; + } + } + } + + private Unwind unwind = null; + + private final List blocks = new ArrayList(); + + private final Map nodeToBlock = new LinkedHashMap(); + + private final Map>> delayedEdges = new LinkedHashMap>>(); + + private final Object exitMarker = new Object(); + + private final Set deadBlocks = new LinkedHashSet(); + + private final Set normalToExit = new LinkedHashSet(); + + private final Set exceptionalToExit = new LinkedHashSet(); + + private Position[] linePositions = new Position[10]; + + private boolean hasCatchBlock = false; + + /** + * does the method have any monitor operations? + */ + private boolean hasMonitorOp = false; + + private int currentInstruction = 0; + + private PreBasicBlock currentBlock; + + public int getCurrentInstruction() { + return currentInstruction; + } + + public PreBasicBlock getCurrentBlock() { + return currentBlock; + } + + boolean hasCatchBlock() { + return hasCatchBlock; + } + + boolean hasMonitorOp() { + return hasMonitorOp; + } + + void noteCatchBlock() { + hasCatchBlock = true; + } + + Position[] getLinePositionMap() { + return linePositions; + } + + /** + * create a new basic block, and set it as the current block. + * + * @param fallThruFromPrior + * should a fall-through edge be added from the previous block + * (value of currentBlock at entry)? if false, the newly created + * block is marked as a dead block, as it has no incoming edges. + * @return the new block + */ + public PreBasicBlock newBlock(boolean fallThruFromPrior) { + // optimization: if we have a fall-through from an empty block, just + // return the empty block + if (fallThruFromPrior && !currentBlock.isEntryBlock() && currentBlock.instructions().size() == 0) { + return currentBlock; + } + + PreBasicBlock previous = currentBlock; + currentBlock = new PreBasicBlock(); + addNode(currentBlock); + blocks.add(currentBlock); + + if (DEBUG_CFG) + System.err.println(("adding new block (node) " + currentBlock)); + if (fallThruFromPrior) { + if (DEBUG_CFG) + System.err.println(("adding fall-thru edge " + previous + " --> " + currentBlock)); + addEdge(previous, currentBlock); + } else { + deadBlocks.add(currentBlock); + } + + return currentBlock; + } + + /** + * record a delayed edge addition from src to dst. Edge will be added when + * appropriate; see {@link #checkForRealizedEdges(CAstNode)} and + * {@link #checkForRealizedExitEdges(PreBasicBlock)} + */ + private void addDelayedEdge(PreBasicBlock src, Object dst, boolean exception) { + MapUtil.findOrCreateSet(delayedEdges, dst).add(Pair.make(src, exception)); + } + + void makeEntryBlock(PreBasicBlock bb) { + bb.makeEntryBlock(); + } + + void makeExitBlock(PreBasicBlock bb) { + bb.makeExitBlock(); + + for (Iterator ps = getPredNodes(bb); ps.hasNext();) + normalToExit.add(ps.next()); + + // now that we have created the exit block, add the delayed edges to the + // exit + checkForRealizedExitEdges(bb); + } + + void setCurrentBlockAsHandler() { + currentBlock.makeHandlerBlock(); + } + + boolean hasDelayedEdges(CAstNode n) { + return delayedEdges.containsKey(n); + } + + /** + * given some n which is now mapped by nodeToBlock, add any delayed edges to + * n's block + */ + private void checkForRealizedEdges(CAstNode n) { + if (delayedEdges.containsKey(n)) { + for (Iterator> ss = delayedEdges.get(n).iterator(); ss.hasNext();) { + Pair s = ss.next(); + PreBasicBlock src = s.fst; + boolean exception = s.snd; + if (unwind == null) { + addEdge(src, nodeToBlock.get(n)); + } else { + PreBasicBlock target = nodeToBlock.get(n); + addEdge(src, unwind.findOrCreateCode(src, target, exception)); + } + } + + delayedEdges.remove(n); + } + } + + /** + * add any delayed edges to the exit block + */ + private void checkForRealizedExitEdges(PreBasicBlock exitBlock) { + if (delayedEdges.containsKey(exitMarker)) { + for (Iterator> ss = delayedEdges.get(exitMarker).iterator(); ss.hasNext();) { + Pair s = ss.next(); + PreBasicBlock src = s.fst; + boolean exception = s.snd; + addEdge(src, exitBlock); + if (exception) + exceptionalToExit.add(src); + else + normalToExit.add(src); + } + + delayedEdges.remove(exitMarker); + } + } + + private void setUnwindState(CAstNode node, UnwindState context) { + if (unwind == null) + unwind = new Unwind(); + unwind.setUnwindState(node, context); + } + + public void addPreNode(CAstNode n) { + addPreNode(n, null); + } + + /** + * associate n with the current block, and update the current unwind state + */ + public void addPreNode(CAstNode n, UnwindState context) { + if (DEBUG_CFG) + System.err.println(("adding pre-node " + n)); + nodeToBlock.put(n, currentBlock); + deadBlocks.remove(currentBlock); + if (context != null) + setUnwindState(n, context); + // now that we've associated n with a block, add associated delayed edges + checkForRealizedEdges(n); + } + + public void addPreEdge(CAstNode src, CAstNode dst, boolean exception) { + assert nodeToBlock.containsKey(src); + addPreEdge(nodeToBlock.get(src), dst, exception); + } + + /** + * if dst is associated with a basic block b, add an edge from src to b. + * otherwise, record the edge addition as delayed. + */ + public void addPreEdge(PreBasicBlock src, CAstNode dst, boolean exception) { + if (dst == CAstControlFlowMap.EXCEPTION_TO_EXIT) { + assert exception; + addPreEdgeToExit(src, exception); + } else if (nodeToBlock.containsKey(dst)) { + PreBasicBlock target = nodeToBlock.get(dst); + if (DEBUG_CFG) + System.err.println(("adding pre-edge " + src + " --> " + dst)); + if (unwind == null) { + addEdge(src, target); + } else { + addEdge(src, unwind.findOrCreateCode(src, target, exception)); + } + } else { + if (DEBUG_CFG) + System.err.println(("adding delayed pre-edge " + src + " --> " + dst)); + addDelayedEdge(src, dst, exception); + } + } + + public void addPreEdgeToExit(CAstNode src, boolean exception) { + assert nodeToBlock.containsKey(src); + addPreEdgeToExit(nodeToBlock.get(src), exception); + } + + public void addPreEdgeToExit(PreBasicBlock src, boolean exception) { + if (unwind != null) { + PreBasicBlock handlers = unwind.findOrCreateCode(src, null, exception); + if (handlers != null) { + addEdge(src, handlers); + return; + } + } + + addDelayedEdge(src, exitMarker, exception); + } + + public void addEdge(PreBasicBlock src, PreBasicBlock dst) { + super.addEdge(src, dst); + deadBlocks.remove(dst); + } + + boolean isDeadBlock(PreBasicBlock block) { + return deadBlocks.contains(block); + } + + public PreBasicBlock getBlock(CAstNode n) { + return nodeToBlock.get(n); + } + + /** + * mark the current position as the position for the instruction + */ + private void noteLinePosition(int instruction) { + if (linePositions.length < (instruction + 1)) { + Position[] newData = new Position[instruction * 2 + 1]; + System.arraycopy(linePositions, 0, newData, 0, linePositions.length); + linePositions = newData; + } + + linePositions[instruction] = getCurrentPosition(); + } + + public void addInstruction(SSAInstruction n) { + deadBlocks.remove(currentBlock); + + int inst = currentInstruction++; + + noteLinePosition(inst); + + if (currentBlock.instructions().size() == 0) { + currentBlock.setFirstIndex(inst); + } else { + assert !(n instanceof SSAGetCaughtExceptionInstruction); + } + + if (DEBUG_CFG) { + System.err.println(("adding " + n + " at " + inst + " to " + currentBlock)); + } + + if (n instanceof SSAMonitorInstruction) { + hasMonitorOp = true; + } + + currentBlock.instructions().add(n); + + currentBlock.setLastIndex(inst); + } + } + + /** + * data structure for the final CFG for a method, based on the information in + * an {@link IncipientCFG} + */ + protected final static class AstCFG extends AbstractCFG { + private final SSAInstruction[] instructions; + + private final int[] instructionToBlockMap; + + private final String functionName; + + private final SymbolTable symtab; + + AstCFG(CAstEntity n, IncipientCFG icfg, SymbolTable symtab) { + super(null); + List blocks = icfg.blocks; + + this.symtab = symtab; + functionName = n.getName(); + instructionToBlockMap = new int[blocks.size()]; + + for (int i = 0; i < blocks.size(); i++) + instructionToBlockMap[i] = blocks.get(i).getLastInstructionIndex(); + + for (int i = 0; i < blocks.size(); i++) { + PreBasicBlock block = blocks.get(i); + this.addNode(block); + if (block.isCatchBlock()) { + setCatchBlock(i); + } + + if (DEBUG_CFG) + System.err.println(("added " + blocks.get(i) + " to final CFG as " + getNumber(blocks.get(i)))); + } + if (DEBUG_CFG) + System.err.println((getMaxNumber() + " blocks total")); + + init(); + + for (int i = 0; i < blocks.size(); i++) { + PreBasicBlock src = blocks.get(i); + for (Iterator j = icfg.getSuccNodes(src); j.hasNext();) { + PreBasicBlock dst = (PreBasicBlock) j.next(); + if (isCatchBlock(dst.getNumber()) || (dst.isExitBlock() && icfg.exceptionalToExit.contains(src))) { + if (DEBUG_CFG) + System.err.println(("exceptonal edge " + src + " -> " + dst)); + addExceptionalEdge(src, dst); + } + + if (dst.isExitBlock() ? icfg.normalToExit.contains(src) : !isCatchBlock(dst.getNumber())) { + if (DEBUG_CFG) + System.err.println(("normal edge " + src + " -> " + dst)); + addNormalEdge(src, dst); + } + } + } + + int x = 0; + instructions = new SSAInstruction[icfg.currentInstruction]; + for (int i = 0; i < blocks.size(); i++) { + List bi = blocks.get(i).instructions(); + for (int j = 0; j < bi.size(); j++) { + instructions[x++] = bi.get(j); + } + } + } + + public int hashCode() { + return functionName.hashCode(); + } + + public boolean equals(Object o) { + return (o instanceof AstCFG) && functionName.equals(((AstCFG) o).functionName); + } + + public PreBasicBlock getBlockForInstruction(int index) { + for (int i = 1; i < getNumberOfNodes() - 1; i++) + if (index <= instructionToBlockMap[i]) + return getNode(i); + + return null; + } + + public SSAInstruction[] getInstructions() { + return instructions; + } + + public int getProgramCounter(int index) { + return index; + } + + public String toString() { + SSAInstruction[] insts = (SSAInstruction[]) getInstructions(); + StringBuffer s = new StringBuffer("CAst CFG of " + functionName); + int params[] = symtab.getParameterValueNumbers(); + for (int i = 0; i < params.length; i++) + s.append(" ").append(params[i]); + s.append("\n"); + + for (int i = 0; i < getNumberOfNodes(); i++) { + PreBasicBlock bb = (PreBasicBlock) getNode(i); + s.append(bb).append("\n"); + + for (Iterator ss = getSuccNodes(bb); ss.hasNext();) + s.append(" -->" + ss.next() + "\n"); + + for (int j = bb.getFirstInstructionIndex(); j <= bb.getLastInstructionIndex(); j++) + if (insts[j] != null) + s.append(" " + insts[j].toString(symtab) + "\n"); + } + + s.append("-- END --"); + return s.toString(); + } + } + + public static enum ScopeType { + LOCAL, GLOBAL, SCRIPT, FUNCTION, TYPE + }; + + private static final boolean DEBUG = false; + + protected class FinalCAstSymbol implements CAstSymbol { + private final String _name; + + private FinalCAstSymbol(String _name) { + this._name = _name; + } + + public String name() { + return _name; + } + + public boolean isFinal() { + return true; + } + + public boolean isCaseInsensitive() { + return false; + } + + public boolean isInternalName() { + return false; + } + + public Object defaultInitValue() { + return null; + } + } + + public static class InternalCAstSymbol extends CAstSymbolImplBase { + public InternalCAstSymbol(String _name) { + super(_name, false, false, null); + } + + public InternalCAstSymbol(String _name, boolean _isFinal) { + super(_name, _isFinal, false, null); + } + + public InternalCAstSymbol(String _name, boolean _isFinal, boolean _isCaseInsensitive) { + super(_name, _isFinal, _isCaseInsensitive, null); + } + + public InternalCAstSymbol(String _name, boolean _isFinal, boolean _isCaseInsensitive, Object _defaultInitValue) { + super(_name, _isFinal, _isCaseInsensitive, _defaultInitValue); + } + + public boolean isInternalName() { + return true; + } + } + + /** + * interface for name information stored in a symbol table. + * + * @see Scope + */ + protected interface Symbol { + int valueNumber(); + + Scope getDefiningScope(); + + boolean isParameter(); + + Object constant(); + + void setConstant(Object s); + + boolean isFinal(); + + boolean isInternalName(); + + Object defaultInitValue(); + } + + /** + * a scope in the symbol table built during AST traversal + */ + public interface Scope { + + ScopeType type(); + + int allocateTempValue(); + + int getConstantValue(Object c); + + boolean isConstant(int valueNumber); + + Object getConstantObject(int valueNumber); + + void declare(CAstSymbol s); + + void declare(CAstSymbol s, int valueNumber); + + boolean isCaseInsensitive(String name); + + boolean contains(String name); + + Symbol lookup(String name); + + Iterator getAllNames(); + + int size(); + + boolean isGlobal(Symbol s); + + boolean isLexicallyScoped(Symbol s); + + CAstEntity getEntity(); + + Scope getParent(); + } + + private static abstract class AbstractSymbol implements Symbol { + private Object constantValue; + + private boolean isFinalValue; + + private final Scope definingScope; + + private Object defaultValue; + + AbstractSymbol(Scope definingScope, boolean isFinalValue, Object defaultValue) { + this.definingScope = definingScope; + this.isFinalValue = isFinalValue; + this.defaultValue = defaultValue; + } + + public boolean isFinal() { + return isFinalValue; + } + + public Object defaultInitValue() { + return defaultValue; + } + + public Object constant() { + return constantValue; + } + + public void setConstant(Object cv) { + constantValue = cv; + } + + public Scope getDefiningScope() { + return definingScope; + } + }; + + private abstract class AbstractScope implements Scope { + private final Scope parent; + + private final Map values = new LinkedHashMap(); + + private final Map caseInsensitiveNames = new LinkedHashMap(); + + protected abstract SymbolTable getUnderlyingSymtab(); + + public Scope getParent() { + return parent; + } + + public int size() { + return getUnderlyingSymtab().getMaxValueNumber() + 1; + } + + public Iterator getAllNames() { + return values.keySet().iterator(); + } + + public int allocateTempValue() { + return getUnderlyingSymtab().newSymbol(); + } + + public int getConstantValue(Object o) { + if (o instanceof Integer) { + return getUnderlyingSymtab().getConstant(((Integer) o).intValue()); + } else if (o instanceof Float) { + return getUnderlyingSymtab().getConstant(((Float) o).floatValue()); + } else if (o instanceof Double) { + return getUnderlyingSymtab().getConstant(((Double) o).doubleValue()); + } else if (o instanceof Long) { + return getUnderlyingSymtab().getConstant(((Long) o).longValue()); + } else if (o instanceof String) { + return getUnderlyingSymtab().getConstant((String) o); + } else if (o instanceof Boolean) { + return getUnderlyingSymtab().getConstant((Boolean) o); + } else if (o instanceof Character) { + return getUnderlyingSymtab().getConstant(((Character) o).charValue()); + } else if (o instanceof Byte) { + return getUnderlyingSymtab().getConstant(((Byte) o).byteValue()); + } else if (o instanceof Short) { + return getUnderlyingSymtab().getConstant(((Short) o).shortValue()); + } else if (o == null) { + return getUnderlyingSymtab().getNullConstant(); + } else if (o == CAstControlFlowMap.SWITCH_DEFAULT) { + return getUnderlyingSymtab().getConstant("__default label"); + } else { + System.err.println(("cannot handle constant " + o)); + Assertions.UNREACHABLE(); + return -1; + } + } + + public boolean isConstant(int valueNumber) { + return getUnderlyingSymtab().isConstant(valueNumber); + } + + public Object getConstantObject(int valueNumber) { + return getUnderlyingSymtab().getConstantValue(valueNumber); + } + + public void declare(CAstSymbol s, int vn) { + String nm = s.name(); + assert !contains(nm) : nm; + if (s.isCaseInsensitive()) + caseInsensitiveNames.put(nm.toLowerCase(), nm); + values.put(nm, makeSymbol(s, vn)); + } + + public void declare(CAstSymbol s) { + String nm = s.name(); + if (!contains(nm) || lookup(nm).getDefiningScope() != this) { + if (s.isCaseInsensitive()) + caseInsensitiveNames.put(nm.toLowerCase(), nm); + values.put(nm, makeSymbol(s)); + } else { + assert !s.isFinal() : "trying to redeclare " + nm; + } + } + + AbstractScope(Scope parent) { + this.parent = parent; + } + + private final String mapName(String nm) { + String mappedName = caseInsensitiveNames.get(nm.toLowerCase()); + return (mappedName == null) ? nm : mappedName; + } + + protected Symbol makeSymbol(CAstSymbol s) { + return makeSymbol(s.name(), s.isFinal(), s.isInternalName(), s.defaultInitValue(), -1, this); + } + + protected Symbol makeSymbol(CAstSymbol s, int vn) { + return makeSymbol(s.name(), s.isFinal(), s.isInternalName(), s.defaultInitValue(), vn, this); + } + + abstract protected Symbol makeSymbol(String nm, boolean isFinal, boolean isInternalName, Object defaultInitValue, int vn, + Scope parent); + + public boolean isCaseInsensitive(String nm) { + return caseInsensitiveNames.containsKey(nm.toLowerCase()); + } + + public Symbol lookup(String nm) { + if (contains(nm)) { + return values.get(mapName(nm)); + } else { + Symbol scoped = parent.lookup(nm); + if (scoped != null && getEntityScope() == this && (isGlobal(scoped) || isLexicallyScoped(scoped))) { + values.put(nm, + makeSymbol(nm, scoped.isFinal(), scoped.isInternalName(), scoped.defaultInitValue(), -1, scoped.getDefiningScope())); + if (scoped.getDefiningScope().isCaseInsensitive(nm)) { + caseInsensitiveNames.put(nm.toLowerCase(), nm); + } + return values.get(nm); + } else { + return scoped; + } + } + } + + public boolean contains(String nm) { + String mappedName = caseInsensitiveNames.get(nm.toLowerCase()); + return values.containsKey(mappedName == null ? nm : mappedName); + } + + public boolean isGlobal(Symbol s) { + return s.getDefiningScope().type() == ScopeType.GLOBAL; + } + + public abstract boolean isLexicallyScoped(Symbol s); + + protected abstract AbstractScope getEntityScope(); + + public abstract CAstEntity getEntity(); + }; + + private AbstractScope makeScriptScope(final CAstEntity s, Scope parent) { + return new AbstractScope(parent) { + SymbolTable scriptGlobalSymtab = new SymbolTable(s.getArgumentCount()); + + public SymbolTable getUnderlyingSymtab() { + return scriptGlobalSymtab; + } + + protected AbstractScope getEntityScope() { + return this; + } + + public boolean isLexicallyScoped(Symbol s) { + if (isGlobal(s)) + return false; + else + return ((AbstractScope) s.getDefiningScope()).getEntity() != getEntity(); + } + + public CAstEntity getEntity() { + return s; + } + + public ScopeType type() { + return ScopeType.SCRIPT; + } + + protected Symbol makeSymbol(final String nm, final boolean isFinal, final boolean isInternalName, + final Object defaultInitValue, int vn, Scope definer) { + final int v = vn == -1 ? getUnderlyingSymtab().newSymbol() : vn; + if (useDefaultInitValues() && defaultInitValue != null) { + if (getUnderlyingSymtab().getValue(v) == null) { + setDefaultValue(getUnderlyingSymtab(), v, defaultInitValue); + } + } + return new AbstractSymbol(definer, isFinal, defaultInitValue) { + public String toString() { + return nm + ":" + System.identityHashCode(this); + } + + public int valueNumber() { + return v; + } + + public boolean isInternalName() { + return isInternalName; + } + + public boolean isParameter() { + return false; + } + }; + } + }; + } + + protected int getArgumentCount(CAstEntity f) { + return f.getArgumentCount(); + } + + protected String[] getArgumentNames(CAstEntity f) { + return f.getArgumentNames(); + } + + private AbstractScope makeFunctionScope(final CAstEntity f, Scope parent) { + return new AbstractScope(parent) { + private final String[] params = getArgumentNames(f); + + private final SymbolTable functionSymtab = new SymbolTable(getArgumentCount(f)); + + // ctor for scope object + { + for (int i = 0; i < getArgumentCount(f); i++) { + final int yuck = i; + declare(new CAstSymbol() { + public String name() { + return params[yuck]; + } + + public boolean isFinal() { + return false; + } + + public boolean isCaseInsensitive() { + return false; + } + + public boolean isInternalName() { + return false; + } + + public Object defaultInitValue() { + return null; + } + + }); + } + } + + public SymbolTable getUnderlyingSymtab() { + return functionSymtab; + } + + protected AbstractScope getEntityScope() { + return this; + } + + public boolean isLexicallyScoped(Symbol s) { + if (isGlobal(s)) + return false; + else + return ((AbstractScope) s.getDefiningScope()).getEntity() != getEntity(); + } + + public CAstEntity getEntity() { + return f; + } + + public ScopeType type() { + return ScopeType.FUNCTION; + } + + private int find(String n) { + for (int i = 0; i < params.length; i++) { + if (n.equals(params[i])) { + return i + 1; + } + } + + return -1; + } + + protected Symbol makeSymbol(final String nm, final boolean isFinal, final boolean isInternalName, + final Object defaultInitValue, final int valueNumber, Scope definer) { + return new AbstractSymbol(definer, isFinal, defaultInitValue) { + final int vn; + + { + int x = find(nm); + if (x != -1) { + assert valueNumber == -1; + vn = x; + } else if (valueNumber != -1) { + vn = valueNumber; + } else { + vn = getUnderlyingSymtab().newSymbol(); + } + if (useDefaultInitValues() && defaultInitValue != null) { + if (getUnderlyingSymtab().getValue(vn) == null) { + setDefaultValue(getUnderlyingSymtab(), vn, defaultInitValue); + } + } + } + + public String toString() { + return nm + ":" + System.identityHashCode(this); + } + + public int valueNumber() { + return vn; + } + + public boolean isInternalName() { + return isInternalName; + } + + public boolean isParameter() { + return vn <= params.length; + } + }; + } + }; + } + + private Scope makeLocalScope(CAstNode s, final Scope parent) { + return new AbstractScope(parent) { + public ScopeType type() { + return ScopeType.LOCAL; + } + + public SymbolTable getUnderlyingSymtab() { + return ((AbstractScope) parent).getUnderlyingSymtab(); + } + + protected AbstractScope getEntityScope() { + return ((AbstractScope) parent).getEntityScope(); + } + + public boolean isLexicallyScoped(Symbol s) { + return ((AbstractScope) getEntityScope()).isLexicallyScoped(s); + } + + public CAstEntity getEntity() { + return ((AbstractScope) getEntityScope()).getEntity(); + } + + protected Symbol makeSymbol(final String nm, boolean isFinal, final boolean isInternalName, final Object defaultInitValue, + int vn, Scope definer) { + final int v = vn == -1 ? getUnderlyingSymtab().newSymbol() : vn; + if (useDefaultInitValues() && defaultInitValue != null) { + if (getUnderlyingSymtab().getValue(v) == null) { + setDefaultValue(getUnderlyingSymtab(), v, defaultInitValue); + } + } + return new AbstractSymbol(definer, isFinal, defaultInitValue) { + public String toString() { + return nm + ":" + System.identityHashCode(this); + } + + public int valueNumber() { + return v; + } + + public boolean isInternalName() { + return isInternalName; + } + + public boolean isParameter() { + return false; + } + }; + } + }; + } + + private Scope makeGlobalScope() { + final Map globalSymbols = new LinkedHashMap(); + final Map caseInsensitiveNames = new LinkedHashMap(); + return new Scope() { + private final String mapName(String nm) { + String mappedName = caseInsensitiveNames.get(nm.toLowerCase()); + return (mappedName == null) ? nm : mappedName; + } + + public Scope getParent() { + return null; + } + + public boolean isGlobal(Symbol s) { + return true; + } + + public boolean isLexicallyScoped(Symbol s) { + return false; + } + + public CAstEntity getEntity() { + return null; + } + + public int size() { + return globalSymbols.size(); + } + + public Iterator getAllNames() { + return globalSymbols.keySet().iterator(); + } + + public int allocateTempValue() { + throw new UnsupportedOperationException(); + } + + public int getConstantValue(Object c) { + throw new UnsupportedOperationException(); + } + + public boolean isConstant(int valueNumber) { + throw new UnsupportedOperationException(); + } + + public Object getConstantObject(int valueNumber) { + throw new UnsupportedOperationException(); + } + + public ScopeType type() { + return ScopeType.GLOBAL; + } + + public boolean contains(String name) { + return hasImplicitGlobals() || globalSymbols.containsKey(mapName(name)); + } + + public boolean isCaseInsensitive(String name) { + return caseInsensitiveNames.containsKey(name.toLowerCase()); + } + + public Symbol lookup(final String name) { + if (!globalSymbols.containsKey(mapName(name))) { + if (hasImplicitGlobals()) { + declare(new CAstSymbol() { + public String name() { + return name; + } + + public boolean isFinal() { + return false; + } + + public boolean isCaseInsensitive() { + return false; + } + + public boolean isInternalName() { + return false; + } + + public Object defaultInitValue() { + return null; + } + }); + } else if (hasSpecialUndeclaredVariables()) { + return null; + } else { + throw new Error("cannot find " + name); + } + } + + return globalSymbols.get(mapName(name)); + } + + public void declare(CAstSymbol s, int vn) { + assert vn == -1; + declare(s); + } + + public void declare(final CAstSymbol s) { + final String name = s.name(); + if (s.isCaseInsensitive()) { + caseInsensitiveNames.put(name.toLowerCase(), name); + } + globalSymbols.put(name, new AbstractSymbol(this, s.isFinal(), s.defaultInitValue()) { + public String toString() { + return name + ":" + System.identityHashCode(this); + } + + public boolean isParameter() { + return false; + } + + public boolean isInternalName() { + return s.isInternalName(); + } + + public int valueNumber() { + throw new UnsupportedOperationException(); + } + }); + } + }; + } + + protected Scope makeTypeScope(final CAstEntity type, final Scope parent) { + final Map typeSymbols = new LinkedHashMap(); + final Map caseInsensitiveNames = new LinkedHashMap(); + return new Scope() { + private final String mapName(String nm) { + String mappedName = caseInsensitiveNames.get(nm.toLowerCase()); + return (mappedName == null) ? nm : mappedName; + } + + public Scope getParent() { + return parent; + } + + public boolean isGlobal(Symbol s) { + return false; + } + + public boolean isLexicallyScoped(Symbol s) { + return false; + } + + public CAstEntity getEntity() { + return type; + } + + public int size() { + return typeSymbols.size(); + } + + public Iterator getAllNames() { + return typeSymbols.keySet().iterator(); + } + + public int allocateTempValue() { + throw new UnsupportedOperationException(); + } + + public int getConstantValue(Object c) { + throw new UnsupportedOperationException(); + } + + public boolean isConstant(int valueNumber) { + throw new UnsupportedOperationException(); + } + + public Object getConstantObject(int valueNumber) { + throw new UnsupportedOperationException(); + } + + public ScopeType type() { + return ScopeType.TYPE; + } + + public boolean contains(String name) { + return typeSymbols.containsKey(mapName(name)); + } + + public boolean isCaseInsensitive(String name) { + return caseInsensitiveNames.containsKey(name.toLowerCase()); + } + + public Symbol lookup(String nm) { + if (typeSymbols.containsKey(mapName(nm))) + return typeSymbols.get(mapName(nm)); + else { + return parent.lookup(nm); + } + } + + public void declare(CAstSymbol s, int vn) { + assert vn == -1; + declare(s); + } + + public void declare(final CAstSymbol s) { + final String name = s.name(); + assert !s.isFinal(); + if (s.isCaseInsensitive()) + caseInsensitiveNames.put(name.toLowerCase(), name); + typeSymbols.put(name, new AbstractSymbol(this, s.isFinal(), s.defaultInitValue()) { + public String toString() { + return name + ":" + System.identityHashCode(this); + } + + public boolean isParameter() { + return false; + } + + public boolean isInternalName() { + return s.isInternalName(); + } + + public int valueNumber() { + throw new UnsupportedOperationException(); + } + }); + } + }; + } + + public interface WalkContext extends CAstVisitor.Context { + + ModuleEntry getModule(); + + String getName(); + + String file(); + + CAstSourcePositionMap getSourceMap(); + + CAstControlFlowMap getControlFlow(); + + Scope currentScope(); + + Set entityScopes(); + + IncipientCFG cfg(); + + UnwindState getUnwindState(); + + void setCatchType(int blockNumber, TypeReference catchType); + + void setCatchType(CAstNode catchNode, TypeReference catchType); + + TypeReference[][] getCatchTypes(); + + void addEntityName(CAstEntity e, String name); + + String getEntityName(CAstEntity e); + + boolean hasValue(CAstNode n); + + int setValue(CAstNode n, int v); + + int getValue(CAstNode n); + + Set, Integer>> exposeNameSet(CAstEntity entity, boolean writeSet); + + Set getAccesses(CAstEntity e); + + Scope getGlobalScope(); + + } + + private abstract class DelegatingContext implements WalkContext { + private final WalkContext parent; + + DelegatingContext(WalkContext parent) { + this.parent = parent; + } + + public Set getAccesses(CAstEntity e) { + return parent.getAccesses(e); + } + + public ModuleEntry getModule() { + return parent.getModule(); + } + + public String getName() { + return parent.getName(); + } + + public String file() { + return parent.file(); + } + + public CAstEntity top() { + return parent.top(); + } + + public CAstSourcePositionMap getSourceMap() { + return parent.getSourceMap(); + } + + public CAstControlFlowMap getControlFlow() { + return parent.getControlFlow(); + } + + public Scope currentScope() { + return parent.currentScope(); + } + + public Set entityScopes() { + return parent.entityScopes(); + } + + public IncipientCFG cfg() { + return parent.cfg(); + } + + public UnwindState getUnwindState() { + return parent.getUnwindState(); + } + + public void setCatchType(int blockNumber, TypeReference catchType) { + parent.setCatchType(blockNumber, catchType); + } + + public void setCatchType(CAstNode catchNode, TypeReference catchType) { + parent.setCatchType(catchNode, catchType); + } + + public TypeReference[][] getCatchTypes() { + return parent.getCatchTypes(); + } + + public void addEntityName(CAstEntity e, String name) { + parent.addEntityName(e, name); + } + + public String getEntityName(CAstEntity e) { + return parent.getEntityName(e); + } + + public boolean hasValue(CAstNode n) { + return parent.hasValue(n); + } + + public int setValue(CAstNode n, int v) { + return parent.setValue(n, v); + } + + public int getValue(CAstNode n) { + return parent.getValue(n); + } + + public Set, Integer>> exposeNameSet(CAstEntity entity, boolean writeSet) { + return parent.exposeNameSet(entity, writeSet); + } + + public Scope getGlobalScope() { + return parent.getGlobalScope(); + } + + } + + private class FileContext extends DelegatingContext { + private final String fUnitName; + + public FileContext(WalkContext parent, String unitName) { + super(parent); + fUnitName = unitName; + } + + public String getName() { + return fUnitName; + } + } + + private class UnwindContext extends DelegatingContext { + private final UnwindState state; + + UnwindContext(CAstNode unwindNode, WalkContext parent, CAstVisitor visitor) { + super(parent); + this.state = new UnwindState(unwindNode, parent, visitor); + } + + public UnwindState getUnwindState() { + return state; + } + } + + private abstract class EntityContext extends DelegatingContext { + protected final CAstEntity topNode; + + protected final String name; + + EntityContext(WalkContext parent, CAstEntity s) { + super(parent); + this.topNode = s; + this.name = composeEntityName(parent, s); + addEntityName(s, this.name); + } + + public String getName() { + return name; + } + + public CAstEntity top() { + return topNode; + } + + public CAstSourcePositionMap getSourceMap() { + return top().getSourceMap(); + } + + } + + private class CodeEntityContext extends EntityContext { + private final Scope topEntityScope; + + private final Set allEntityScopes; + + private final IncipientCFG cfg; + + private TypeReference[][] catchTypes = new TypeReference[0][]; + + Set, Integer>> exposedReads; + Set, Integer>> exposedWrites; + + Set accesses; + + /** + * maps nodes in the current function to the value number holding their value + * or, for constants, to their constant value. + */ + private final Map results = new LinkedHashMap(); + + CodeEntityContext(WalkContext parent, Scope entityScope, CAstEntity s) { + super(parent, s); + + this.topEntityScope = entityScope; + + this.allEntityScopes = HashSetFactory.make(); + this.allEntityScopes.add(entityScope); + + cfg = new IncipientCFG(); + } + + public Set getAccesses(CAstEntity e) { + if (e == topNode) { + if (accesses == null) { + accesses = HashSetFactory.make(); + } + return accesses; + } else { + return super.getAccesses(e); + } + } + + @Override + public Set, Integer>> exposeNameSet(CAstEntity entity, boolean writeSet) { + if (entity == topNode) { + if (writeSet) { + if (exposedWrites == null) { + exposedWrites = HashSetFactory.make(); + } + return exposedWrites; + } else { + if (exposedReads == null) { + exposedReads = HashSetFactory.make(); + } + return exposedReads; + } + } else { + return super.exposeNameSet(entity, writeSet); + } + } + + + public CAstControlFlowMap getControlFlow() { + return top().getControlFlow(); + } + + public IncipientCFG cfg() { + return cfg; + } + + public Scope currentScope() { + return topEntityScope; + } + + public Set entityScopes() { + return allEntityScopes; + } + + public UnwindState getUnwindState() { + return null; + } + + public void setCatchType(CAstNode catchNode, TypeReference catchType) { + setCatchType(cfg.getBlock(catchNode).getNumber(), catchType); + } + + public void setCatchType(int blockNumber, TypeReference catchType) { + if (catchTypes.length <= blockNumber) { + TypeReference[][] data = new TypeReference[blockNumber + 1][]; + System.arraycopy(catchTypes, 0, data, 0, catchTypes.length); + catchTypes = data; + } + + if (catchTypes[blockNumber] == null) { + catchTypes[blockNumber] = new TypeReference[] { catchType }; + } else { + TypeReference[] data = catchTypes[blockNumber]; + + for (int i = 0; i < data.length; i++) { + if (data[i] == catchType) { + return; + } + } + + TypeReference[] newData = new TypeReference[data.length + 1]; + System.arraycopy(data, 0, newData, 0, data.length); + newData[data.length] = catchType; + + catchTypes[blockNumber] = newData; + } + } + + public TypeReference[][] getCatchTypes() { + return catchTypes; + } + + public boolean hasValue(CAstNode n) { + return results.containsKey(n); + } + + public final int setValue(CAstNode n, int v) { + results.put(n, new Integer(v)); + return v; + } + + public final int getValue(CAstNode n) { + if (results.containsKey(n)) + return results.get(n).intValue(); + else { + if (DEBUG) { + System.err.println(("no value for " + n.getKind())); + } + return -1; + } + } + + } + + private final class TypeContext extends EntityContext { + + private TypeContext(WalkContext parent, CAstEntity n) { + super(parent, n); + } + + public CAstControlFlowMap getControlFlow() { + Assertions.UNREACHABLE("TypeContext.getControlFlow()"); + return null; + } + + public IncipientCFG cfg() { + Assertions.UNREACHABLE("TypeContext.cfg()"); + return null; + } + + public UnwindState getUnwindState() { + Assertions.UNREACHABLE("TypeContext.getUnwindState()"); + return null; + } + } + + private class LocalContext extends DelegatingContext { + private final Scope localScope; + + LocalContext(WalkContext parent, Scope localScope) { + super(parent); + this.localScope = localScope; + parent.entityScopes().add(localScope); + } + + public Scope currentScope() { + return localScope; + } + } + + /** + * lexical access information for some entity scope. used during call graph + * construction to handle lexical accesses. + */ + public static class AstLexicalInformation implements LexicalInformation { + /** + * the name of this function, as it appears in the definer portion of a + * lexical name + */ + private final String functionLexicalName; + + /** + * names possibly accessed in a nested lexical scope, represented as pairs + * (name,nameOfDefiningEntity) + */ + private final Pair[] exposedNames; + + /** + * map from instruction index and exposed name (via its index in + * {@link #exposedNames}) to the value number for the name at that + * instruction index. This can vary at different instructions due to SSA + * (and this information is updated during {@link SSAConversion}). + */ + private final int[][] instructionLexicalUses; + + /** + * maps each exposed name (via its index in {@link #exposedNames}) to its + * value number at method exit. + */ + private final int[] exitLexicalUses; + + /** + * the names of the enclosing methods declaring names that are lexically + * accessed by the entity + */ + private final String[] scopingParents; + + /** + * all value numbers appearing as entries in {@link #instructionLexicalUses} + * and {@link #exitLexicalUses}, computed lazily + */ + private MutableIntSet allExposedUses = null; + + /** + * names of exposed variables of this method that cannot be written outside + */ + private final Set readOnlyNames; + + @SuppressWarnings("unchecked") + public AstLexicalInformation(AstLexicalInformation original) { + this.functionLexicalName = original.functionLexicalName; + + if (original.exposedNames != null) { + exposedNames = new Pair[original.exposedNames.length]; + for (int i = 0; i < exposedNames.length; i++) { + exposedNames[i] = Pair.make(original.exposedNames[i].fst, original.exposedNames[i].snd); + } + } else { + exposedNames = null; + } + + instructionLexicalUses = new int[original.instructionLexicalUses.length][]; + for (int i = 0; i < instructionLexicalUses.length; i++) { + int[] x = original.instructionLexicalUses[i]; + if (x != null) { + instructionLexicalUses[i] = new int[x.length]; + for (int j = 0; j < x.length; j++) { + instructionLexicalUses[i][j] = x[j]; + } + } + } + + if (original.exitLexicalUses != null) { + exitLexicalUses = new int[original.exitLexicalUses.length]; + for (int i = 0; i < exitLexicalUses.length; i++) { + exitLexicalUses[i] = original.exitLexicalUses[i]; + } + } else { + exitLexicalUses = null; + } + + if (original.scopingParents != null) { + scopingParents = new String[original.scopingParents.length]; + for (int i = 0; i < scopingParents.length; i++) { + scopingParents[i] = original.scopingParents[i]; + } + } else { + scopingParents = null; + } + + readOnlyNames = original.readOnlyNames; + } + + private int[] buildLexicalUseArray(Pair, Integer>[] exposedNames, String entityName) { + if (exposedNames != null) { + int[] lexicalUses = new int[exposedNames.length]; + for (int j = 0; j < exposedNames.length; j++) { + if (entityName == null || entityName.equals(exposedNames[j].fst.snd)) { + lexicalUses[j] = exposedNames[j].snd; + } else { + lexicalUses[j] = -1; + } + } + + return lexicalUses; + } else { + return null; + } + } + + private Pair[] buildLexicalNamesArray(Pair, Integer>[] exposedNames) { + if (exposedNames != null) { + @SuppressWarnings("unchecked") + Pair[] lexicalNames = new Pair[exposedNames.length]; + for (int j = 0; j < exposedNames.length; j++) { + lexicalNames[j] = exposedNames[j].fst; + } + + return lexicalNames; + } else { + return null; + } + } + + @SuppressWarnings("unchecked") + AstLexicalInformation(String entityName, Scope scope, SSAInstruction[] instrs, + Set, Integer>> exposedNamesForReadSet, + Set, Integer>> exposedNamesForWriteSet, Set accesses) { + this.functionLexicalName = entityName; + + Pair, Integer>[] EN = null; + if (exposedNamesForReadSet != null || exposedNamesForWriteSet != null) { + Set, Integer>> exposedNamesSet = new HashSet, Integer>>(); + if (exposedNamesForReadSet != null) { + exposedNamesSet.addAll(exposedNamesForReadSet); + } + if (exposedNamesForWriteSet != null) { + exposedNamesSet.addAll(exposedNamesForWriteSet); + } + EN = exposedNamesSet.toArray(new Pair[exposedNamesSet.size()]); + } + + if (exposedNamesForReadSet != null) { + Set readOnlyNames = new HashSet(); + for (Pair, Integer> v : exposedNamesForReadSet) { + if (entityName != null && entityName.equals(v.fst.snd)) { + readOnlyNames.add(v.fst.fst); + } + } + if (exposedNamesForWriteSet != null) { + for (Pair, Integer> v : exposedNamesForWriteSet) { + if (entityName != null && entityName.equals(v.fst.snd)) { + readOnlyNames.remove(v.fst.fst); + } + } + } + this.readOnlyNames = readOnlyNames; + } else { + this.readOnlyNames = null; + } + + this.exposedNames = buildLexicalNamesArray(EN); + + // the value numbers stored in exitLexicalUses and instructionLexicalUses + // are identical at first; they will be updated + // as needed during the final SSA conversion + this.exitLexicalUses = buildLexicalUseArray(EN, entityName); + + this.instructionLexicalUses = new int[instrs.length][]; + for (int i = 0; i < instrs.length; i++) { + if (instrs[i] instanceof SSAAbstractInvokeInstruction) { + this.instructionLexicalUses[i] = buildLexicalUseArray(EN, null); + } + } + + if (accesses != null) { + Set parents = new LinkedHashSet(); + for (Iterator ACS = accesses.iterator(); ACS.hasNext();) { + Access AC = ACS.next(); + if (AC.variableDefiner != null) { + parents.add(AC.variableDefiner); + } + } + scopingParents = parents.toArray(new String[parents.size()]); + + if (DEBUG_LEXICAL) { + System.err.println(("scoping parents of " + scope.getEntity())); + System.err.println(parents.toString()); + } + + } else { + scopingParents = null; + } + + if (DEBUG_NAMES) { + System.err.println(("lexical uses of " + scope.getEntity())); + for (int i = 0; i < instructionLexicalUses.length; i++) { + if (instructionLexicalUses[i] != null) { + System.err.println((" lexical uses of " + instrs[i])); + for (int j = 0; j < instructionLexicalUses[i].length; j++) { + System.err.println((" " + this.exposedNames[j].fst + ": " + instructionLexicalUses[i][j])); + } + } + } + } + } + + public int[] getExitExposedUses() { + return exitLexicalUses; + } + + private static final int[] NONE = new int[0]; + + public int[] getExposedUses(int instructionOffset) { + return instructionLexicalUses[instructionOffset] == null ? NONE : instructionLexicalUses[instructionOffset]; + } + + public IntSet getAllExposedUses() { + if (allExposedUses == null) { + allExposedUses = IntSetUtil.make(); + if (exitLexicalUses != null) { + for (int i = 0; i < exitLexicalUses.length; i++) { + if (exitLexicalUses[i] > 0) { + allExposedUses.add(exitLexicalUses[i]); + } + } + } + if (instructionLexicalUses != null) { + for (int i = 0; i < instructionLexicalUses.length; i++) { + if (instructionLexicalUses[i] != null) { + for (int j = 0; j < instructionLexicalUses[i].length; j++) { + if (instructionLexicalUses[i][j] > 0) { + allExposedUses.add(instructionLexicalUses[i][j]); + } + } + } + } + } + } + + return allExposedUses; + } + + public Pair[] getExposedNames() { + return exposedNames; + } + + public String[] getScopingParents() { + return scopingParents; + } + + /** + * reset cached info about value numbers that may have changed + */ + public void handleAlteration() { + allExposedUses = null; + } + + public boolean isReadOnly(String name) { + return readOnlyNames != null && readOnlyNames.contains(name); + } + + public String getScopingName() { + return functionLexicalName; + } + }; + + /** + * record that in entity e, the access is performed. + * + * If {@link #useLocalValuesForLexicalVars()} is true, the access is performed + * using a local variable. in + * {@link #patchLexicalAccesses(SSAInstruction[], Set)}, this information is + * used to update an instruction that performs all the accesses at the + * beginning of the method and defines the locals. + */ + private void addAccess(WalkContext context, CAstEntity e, Access access) { + context.getAccesses(e).add(access); + } + + /** + * Record that a name assigned a value number in the scope of entity may be + * accessed by a lexically nested scope, i.e., the name may be + * exposed to lexically nested scopes. This information is needed + * during call graph construction to properly model the data flow due to the + * access in the nested scope. + * + * @param entity + * an entity in whose scope name is assigned a value number + * @param declaration + * the declaring entity for name (possibly an enclosing scope of + * entity, in the case where entity + * {@link #useLocalValuesForLexicalVars() accesses the name via a + * local}) + * @param name + * the accessed name + * @param valueNumber + * the name's value number in the scope of entity + */ + private void addExposedName(CAstEntity entity, CAstEntity declaration, String name, int valueNumber, boolean isWrite, WalkContext context) { + Pair, Integer> newVal = Pair.make(Pair.make(name, context.getEntityName(declaration)), valueNumber); + context.exposeNameSet(entity, isWrite).add(newVal); + } + + private void setDefaultValue(SymbolTable symtab, int vn, Object value) { + if (value == CAstSymbol.NULL_DEFAULT_VALUE) { + symtab.setDefaultValue(vn, null); + } else { + symtab.setDefaultValue(vn, value); + } + } + + protected IUnaryOpInstruction.IOperator translateUnaryOpcode(CAstNode op) { + if (op == CAstOperator.OP_BITNOT) + return AstConstants.UnaryOp.BITNOT; + else if (op == CAstOperator.OP_NOT) + return IUnaryOpInstruction.Operator.NEG; + else if (op == CAstOperator.OP_SUB) + return AstConstants.UnaryOp.MINUS; + else if (op == CAstOperator.OP_ADD) + return AstConstants.UnaryOp.PLUS; + else + Assertions.UNREACHABLE("cannot translate " + CAstPrinter.print(op)); + return null; + + } + + protected IBinaryOpInstruction.IOperator translateBinaryOpcode(CAstNode op) { + if (op == CAstOperator.OP_ADD) + return BinaryOpInstruction.Operator.ADD; + else if (op == CAstOperator.OP_DIV) + return BinaryOpInstruction.Operator.DIV; + else if (op == CAstOperator.OP_LSH) + return ShiftInstruction.Operator.SHL; + else if (op == CAstOperator.OP_MOD) + return BinaryOpInstruction.Operator.REM; + else if (op == CAstOperator.OP_MUL) + return BinaryOpInstruction.Operator.MUL; + else if (op == CAstOperator.OP_RSH) + return ShiftInstruction.Operator.SHR; + else if (op == CAstOperator.OP_SUB) + return BinaryOpInstruction.Operator.SUB; + else if (op == CAstOperator.OP_URSH) + return ShiftInstruction.Operator.USHR; + else if (op == CAstOperator.OP_BIT_AND) + return BinaryOpInstruction.Operator.AND; + else if (op == CAstOperator.OP_BIT_OR) + return BinaryOpInstruction.Operator.OR; + else if (op == CAstOperator.OP_BIT_XOR) + return BinaryOpInstruction.Operator.XOR; + else if (op == CAstOperator.OP_CONCAT) + return AstConstants.BinaryOp.CONCAT; + else if (op == CAstOperator.OP_EQ) + return AstConstants.BinaryOp.EQ; + else if (op == CAstOperator.OP_STRICT_EQ) + return AstConstants.BinaryOp.STRICT_EQ; + else if (op == CAstOperator.OP_GE) + return AstConstants.BinaryOp.GE; + else if (op == CAstOperator.OP_GT) + return AstConstants.BinaryOp.GT; + else if (op == CAstOperator.OP_LE) + return AstConstants.BinaryOp.LE; + else if (op == CAstOperator.OP_LT) + return AstConstants.BinaryOp.LT; + else if (op == CAstOperator.OP_NE) + return AstConstants.BinaryOp.NE; + else if (op == CAstOperator.OP_STRICT_NE) + return AstConstants.BinaryOp.STRICT_NE; + else { + Assertions.UNREACHABLE("cannot translate " + CAstPrinter.print(op)); + return null; + } + } + + protected IConditionalBranchInstruction.IOperator translateConditionOpcode(CAstNode op) { + if (op == CAstOperator.OP_EQ) + return ConditionalBranchInstruction.Operator.EQ; + else if (op == CAstOperator.OP_GE) + return ConditionalBranchInstruction.Operator.GE; + else if (op == CAstOperator.OP_GT) + return ConditionalBranchInstruction.Operator.GT; + else if (op == CAstOperator.OP_LE) + return ConditionalBranchInstruction.Operator.LE; + else if (op == CAstOperator.OP_LT) + return ConditionalBranchInstruction.Operator.LT; + else if (op == CAstOperator.OP_NE) + return ConditionalBranchInstruction.Operator.NE; + + else { + Assertions.UNREACHABLE("cannot translate " + CAstPrinter.print(op)); + return null; + } + } + + private String[] makeNameMap(CAstEntity n, Set scopes) { + // all scopes share the same underlying symtab, which is what + // size really refers to. + String[] map = new String[scopes.iterator().next().size() + 1]; + + if (DEBUG_NAMES) { + System.err.println(("names array of size " + map.length)); + } + + for (Iterator S = scopes.iterator(); S.hasNext();) { + Scope scope = S.next(); + for (Iterator I = scope.getAllNames(); I.hasNext();) { + String nm = I.next(); + Symbol v = (Symbol) scope.lookup(nm); + + if (v.isInternalName()) { + continue; + } + + // constants can flow to multiple variables + if (scope.isConstant(v.valueNumber())) + continue; + + assert map[v.valueNumber()] == null || map[v.valueNumber()].equals(nm) : "value number " + v.valueNumber() + + " mapped to multiple names in " + n.getName() + ": " + nm + " and " + map[v.valueNumber()]; + + map[v.valueNumber()] = nm; + + if (DEBUG_NAMES) { + System.err.println(("mapping name " + nm + " to " + v.valueNumber())); + } + } + } + + return map; + } + + protected final CAstType getTypeForNode(WalkContext context, CAstNode node) { + if (context.top().getNodeTypeMap() != null) { + return context.top().getNodeTypeMap().getNodeType(node); + } else { + return null; + } + } + + /** + * find any AstLexicalAccess instructions in instrs with a zero access count, + * and change them to perform specified accesses. If accesses is empty, null + * out the pointers to the AstLexicalAccess instructions in the array. + * + * Presumably, such empty AstLexicalAccess instructions should only exist if + * {@link #useLocalValuesForLexicalVars()} returns true? + */ + private void patchLexicalAccesses(SSAInstruction[] instrs, Set accesses) { + Access[] AC = accesses == null || accesses.isEmpty() ? (Access[]) null : (Access[]) accesses.toArray(new Access[accesses.size()]); + for (int i = 0; i < instrs.length; i++) { + if (instrs[i] instanceof AstLexicalAccess && ((AstLexicalAccess) instrs[i]).getAccessCount() == 0) { + // should just be AstLexicalRead for now; may add support for + // AstLexicalWrite later + assert instrs[i] instanceof AstLexicalRead; + assert useLocalValuesForLexicalVars(); + if (AC != null) { + ((AstLexicalAccess) instrs[i]).setAccesses(AC); + } else { + instrs[i] = null; + } + } + } + } + + private Position getPosition(CAstSourcePositionMap map, CAstNode n) { + if (map.getPosition(n) != null) { + return map.getPosition(n); + } else { + for (int i = 0; i < n.getChildCount(); i++) { + Position p = getPosition(map, n.getChild(i)); + if (p != null) { + return p; + } + } + + return null; + } + } + + protected WalkContext makeFileContext(WalkContext c, CAstEntity n) { + return new FileContext((WalkContext) c, n.getName()); + } + + protected WalkContext makeTypeContext(WalkContext c, CAstEntity n) { + return new TypeContext((WalkContext) c, n); + } + + protected WalkContext makeCodeContext(WalkContext c, CAstEntity n) { + WalkContext context = (WalkContext) c; + AbstractScope scope; + if (n.getKind() == CAstEntity.SCRIPT_ENTITY) + scope = makeScriptScope(n, context.currentScope()); + else + scope = makeFunctionScope(n, context.currentScope()); + return new CodeEntityContext(context, scope, n); + } + + protected boolean enterEntity(final CAstEntity n, WalkContext context, CAstVisitor visitor) { + if (DEBUG_TOP) + System.err.println(("translating " + n.getName())); + return false; + } + + protected boolean visitFileEntity(CAstEntity n, WalkContext context, WalkContext fileContext, CAstVisitor visitor) { /* empty */ + return false; + } + + protected void leaveFileEntity(CAstEntity n, WalkContext context, WalkContext fileContext, CAstVisitor visitor) { /* empty */ + } + + protected boolean visitFieldEntity(CAstEntity n, WalkContext context, CAstVisitor visitor) { /* empty */ + return false; + } + + protected void leaveFieldEntity(CAstEntity n, WalkContext context, CAstVisitor visitor) { + // Define a new field in the enclosing type, if the language we're + // processing allows such. + CAstEntity topEntity = context.top(); // better be a type + assert topEntity.getKind() == CAstEntity.TYPE_ENTITY : "Parent of field entity is not a type???"; + defineField(topEntity, (WalkContext) context, n); + } + + protected boolean visitGlobalEntity(CAstEntity n, WalkContext context, CAstVisitor visitor) { /* empty */ + return false; + } + + protected void leaveGlobalEntity(CAstEntity n, WalkContext context, CAstVisitor visitor) { + // Define a new field in the enclosing type, if the language we're + // processing allows such. + context.getGlobalScope().declare(new CAstSymbolImpl(n.getName())); + } + + protected boolean visitTypeEntity(CAstEntity n, WalkContext context, WalkContext typeContext, CAstVisitor visitor) { + return !defineType(n, (WalkContext) context); + } + + protected void leaveTypeEntity(CAstEntity n, WalkContext context, WalkContext typeContext, CAstVisitor visitor) { /* empty */ + } + + protected boolean visitFunctionEntity(CAstEntity n, WalkContext context, WalkContext codeContext, CAstVisitor visitor) { + if (n.getAST() == null) // presumably abstract + declareFunction(n, (WalkContext) context); + else + initFunctionEntity(n, (WalkContext) context, (WalkContext) codeContext); + return false; + } + + protected void leaveFunctionEntity(CAstEntity n, WalkContext context, WalkContext codeContext, CAstVisitor visitor) { + if (n.getAST() != null) // non-abstract + closeFunctionEntity(n, (WalkContext) context, (WalkContext) codeContext); + } + + protected boolean visitMacroEntity(CAstEntity n, WalkContext context, WalkContext codeContext, CAstVisitor visitor) { + return true; + } + + protected boolean visitScriptEntity(CAstEntity n, WalkContext context, WalkContext codeContext, CAstVisitor visitor) { + declareFunction(n, (WalkContext) codeContext); + initFunctionEntity(n, (WalkContext) context, (WalkContext) codeContext); + return false; + } + + protected void leaveScriptEntity(CAstEntity n, WalkContext context, WalkContext codeContext, CAstVisitor visitor) { + closeFunctionEntity(n, (WalkContext) context, (WalkContext) codeContext); + } + + public void initFunctionEntity(final CAstEntity n, WalkContext parentContext, WalkContext functionContext) { + // entry block + functionContext.cfg().makeEntryBlock(functionContext.cfg().newBlock(false)); + // first real block + functionContext.cfg().newBlock(true); + // prologue code, if any + doPrologue(functionContext); + } + + public void closeFunctionEntity(final CAstEntity n, WalkContext parentContext, WalkContext functionContext) { + // exit block + functionContext.cfg().makeExitBlock(functionContext.cfg().newBlock(true)); + + // create code entry stuff for this entity + SymbolTable symtab = ((AbstractScope) functionContext.currentScope()).getUnderlyingSymtab(); + TypeReference[][] catchTypes = functionContext.getCatchTypes(); + AstCFG cfg = new AstCFG(n, functionContext.cfg(), symtab); + Position[] line = functionContext.cfg().getLinePositionMap(); + boolean katch = functionContext.cfg().hasCatchBlock(); + boolean monitor = functionContext.cfg().hasMonitorOp(); + String[] nms = makeNameMap(n, functionContext.entityScopes()); + + /* + * Set reachableBlocks = DFS.getReachableNodes(cfg, + * Collections.singleton(cfg.entry())); + * Assertions._assert(reachableBlocks.size() == cfg.getNumberOfNodes(), + * cfg.toString()); + */ + + // (put here to allow subclasses to handle stuff in scoped entities) + // assemble lexical information + patchLexicalAccesses(cfg.getInstructions(), functionContext.getAccesses(n)); + AstLexicalInformation LI = new AstLexicalInformation(functionContext.getEntityName(n), (AbstractScope) functionContext.currentScope(), cfg.getInstructions(), + functionContext.exposeNameSet(n, false), + functionContext.exposeNameSet(n, true), + functionContext.getAccesses(n)); + + DebuggingInformation DBG = new AstDebuggingInformation(n.getPosition(), line, nms); + + // actually make code body + defineFunction(n, parentContext, cfg, symtab, katch, catchTypes, monitor, LI, DBG); + } + + protected WalkContext makeLocalContext(WalkContext context, CAstNode n) { + return new LocalContext((WalkContext) context, makeLocalScope(n, ((WalkContext) context).currentScope())); + } + + protected WalkContext makeUnwindContext(WalkContext context, CAstNode n, CAstVisitor visitor) { + // here, n represents the "finally" block of the unwind + return new UnwindContext(n, (WalkContext) context, visitor); + } + + private Map> entity2ExposedNames; + protected int processFunctionExpr(CAstNode n, WalkContext context) { + CAstEntity fn = (CAstEntity) n.getChild(0).getValue(); + declareFunction(fn, context); + int result = context.currentScope().allocateTempValue(); + int ex = context.currentScope().allocateTempValue(); + doMaterializeFunction(n, context, result, ex, fn); + return result; + } + + protected boolean visitFunctionExpr(CAstNode n, WalkContext c, CAstVisitor visitor) { /* empty */ + return false; + } + + protected void leaveFunctionExpr(CAstNode n, WalkContext c, CAstVisitor visitor) { + int result = processFunctionExpr(n, c); + c.setValue(n, result); + } + + protected boolean visitFunctionStmt(CAstNode n, WalkContext c, CAstVisitor visitor) { /* empty */ + return false; + } + + protected void leaveFunctionStmt(CAstNode n, WalkContext context, CAstVisitor visitor) { + int result = processFunctionExpr(n, context); + CAstEntity fn = (CAstEntity) n.getChild(0).getValue(); + // FIXME: handle redefinitions of functions + Scope cs = context.currentScope(); + if (cs.contains(fn.getName()) && !cs.isLexicallyScoped(cs.lookup(fn.getName())) && !cs.isGlobal(cs.lookup(fn.getName()))) { + // if we already have a local with the function's name, write the function + // value to that local + assignValue(n, context, cs.lookup(fn.getName()), fn.getName(), result); + } else if (topLevelFunctionsInGlobalScope() && context.top().getKind() == CAstEntity.SCRIPT_ENTITY) { + context.getGlobalScope().declare(new FinalCAstSymbol(fn.getName())); + assignValue(n, context, cs.lookup(fn.getName()), fn.getName(), result); + } else { + context.currentScope().declare(new FinalCAstSymbol(fn.getName()), result); + } + } + + protected boolean visitLocalScope(CAstNode n, WalkContext c, CAstVisitor visitor) { /* empty */ + return false; + } + + protected void leaveLocalScope(CAstNode n, WalkContext c, CAstVisitor visitor) { + c.setValue(n, c.getValue(n.getChild(0))); + } + + protected boolean visitBlockExpr(CAstNode n, WalkContext c, CAstVisitor visitor) { /* empty */ + return false; + } + + protected void leaveBlockExpr(CAstNode n, WalkContext c, CAstVisitor visitor) { + c.setValue(n, c.getValue(n.getChild(n.getChildCount() - 1))); + } + + protected boolean visitBlockStmt(CAstNode n, WalkContext c, CAstVisitor visitor) { /* empty */ + return false; + } + + protected void leaveBlockStmt(CAstNode n, WalkContext c, CAstVisitor visitor) { /* empty */ + } + + protected boolean visitLoop(CAstNode n, WalkContext c, CAstVisitor visitor) { + WalkContext context = (WalkContext) c; + // loop test block + context.cfg().newBlock(true); + PreBasicBlock headerB = context.cfg().getCurrentBlock(); + visitor.visit(n.getChild(0), context, visitor); + + assert c.getValue(n.getChild(0)) != -1 : "error in loop test " + CAstPrinter.print(n.getChild(0), context.top().getSourceMap()) + + " of loop " + CAstPrinter.print(n, context.top().getSourceMap()); + context.cfg().addInstruction( + insts.ConditionalBranchInstruction(translateConditionOpcode(CAstOperator.OP_EQ), null, c.getValue(n.getChild(0)), context + .currentScope().getConstantValue(new Integer(0)))); + PreBasicBlock branchB = context.cfg().getCurrentBlock(); + + // loop body + context.cfg().newBlock(true); + visitor.visit(n.getChild(1), context, visitor); + if (!context.cfg().isDeadBlock(context.cfg().getCurrentBlock())) { + context.cfg().addInstruction(insts.GotoInstruction()); + PreBasicBlock bodyB = context.cfg().getCurrentBlock(); + context.cfg().addEdge(bodyB, headerB); + + // next block + context.cfg().newBlock(false); + } + + PreBasicBlock nextB = context.cfg().getCurrentBlock(); + + // control flow mapping; + context.cfg().addEdge(branchB, nextB); + return true; + } + + // Make final to prevent overriding + protected final void leaveLoopHeader(CAstNode n, WalkContext c, CAstVisitor visitor) { /* empty */ + } + + protected final void leaveLoop(CAstNode n, WalkContext c, CAstVisitor visitor) { /* empty */ + } + + protected boolean visitGetCaughtException(CAstNode n, WalkContext c, CAstVisitor visitor) { /* empty */ + return false; + } + + protected void leaveGetCaughtException(CAstNode n, WalkContext c, CAstVisitor visitor) { + WalkContext context = (WalkContext) c; + String nm = (String) n.getChild(0).getValue(); + context.currentScope().declare(new FinalCAstSymbol(nm)); + context.cfg().addInstruction( + insts.GetCaughtExceptionInstruction(context.cfg().getCurrentBlock().getNumber(), context.currentScope().lookup(nm) + .valueNumber())); + } + + protected boolean visitThis(CAstNode n, WalkContext c, CAstVisitor visitor) { /* empty */ + return false; + } + + protected void leaveThis(CAstNode n, WalkContext c, CAstVisitor visitor) { + c.setValue(n, 1); + } + + protected boolean visitSuper(CAstNode n, WalkContext c, CAstVisitor visitor) { /* empty */ + return false; + } + + protected void leaveSuper(CAstNode n, WalkContext c, CAstVisitor visitor) { + c.setValue(n, 1); + } + + protected boolean visitCall(CAstNode n, WalkContext c, CAstVisitor visitor) { + WalkContext context = (WalkContext) c; + int result = context.currentScope().allocateTempValue(); + c.setValue(n, result); + return false; + } + + protected void leaveCall(CAstNode n, WalkContext c, CAstVisitor visitor) { + WalkContext context = (WalkContext) c; + int result = c.getValue(n); + int exp = context.currentScope().allocateTempValue(); + int fun = c.getValue(n.getChild(0)); + CAstNode functionName = n.getChild(1); + int[] args = new int[n.getChildCount() - 2]; + for (int i = 0; i < args.length; i++) { + args[i] = c.getValue(n.getChild(i + 2)); + } + doCall(context, n, result, exp, functionName, fun, args); + } + + protected boolean visitVar(CAstNode n, WalkContext c, CAstVisitor visitor) { /* empty */ + return false; + } + + protected void leaveVar(CAstNode n, WalkContext c, CAstVisitor visitor) { + WalkContext context = (WalkContext) c; + String nm = (String) n.getChild(0).getValue(); + assert nm != null : "cannot find var for " + CAstPrinter.print(n, context.getSourceMap()); + Symbol s = context.currentScope().lookup(nm); + assert s != null : "cannot find symbol for " + nm + " at " + CAstPrinter.print(n, context.getSourceMap()); + if (context.currentScope().isGlobal(s)) { + c.setValue(n, doGlobalRead(n, context, nm)); + } else if (context.currentScope().isLexicallyScoped(s)) { + c.setValue(n, doLexicallyScopedRead(n, context, nm)); + } else { + c.setValue(n, doLocalRead(context, nm)); + } + } + + protected boolean visitConstant(CAstNode n, WalkContext c, CAstVisitor visitor) { /* empty */ + return false; + } + + protected void leaveConstant(CAstNode n, WalkContext c, CAstVisitor visitor) { + WalkContext context = (WalkContext) c; + c.setValue(n, context.currentScope().getConstantValue(n.getValue())); + } + + protected boolean visitBinaryExpr(CAstNode n, WalkContext c, CAstVisitor visitor) { + WalkContext context = (WalkContext) c; + int result = context.currentScope().allocateTempValue(); + c.setValue(n, result); + return false; + } + + private boolean handleBinaryOpThrow(CAstNode n, CAstNode op, WalkContext context) { + // currently, only integer / and % throw exceptions + boolean mayBeInteger = false; + Collection labels = context.getControlFlow().getTargetLabels(n); + if (!labels.isEmpty()) { + context.cfg().addPreNode(n, context.getUnwindState()); + + mayBeInteger = true; + assert op == CAstOperator.OP_DIV || op == CAstOperator.OP_MOD : CAstPrinter.print(n); + for (Iterator iter = labels.iterator(); iter.hasNext();) { + Object label = iter.next(); + CAstNode target = context.getControlFlow().getTarget(n, label); + if (target == CAstControlFlowMap.EXCEPTION_TO_EXIT) + context.cfg().addPreEdgeToExit(n, true); + else + context.cfg().addPreEdge(n, target, true); + } + } + + return mayBeInteger; + } + + protected void leaveBinaryExpr(CAstNode n, WalkContext c, CAstVisitor visitor) { + WalkContext context = (WalkContext) c; + int result = c.getValue(n); + CAstNode l = n.getChild(1); + CAstNode r = n.getChild(2); + assert c.getValue(r) != -1 : CAstPrinter.print(n); + assert c.getValue(l) != -1 : CAstPrinter.print(n); + + boolean mayBeInteger = handleBinaryOpThrow(n, n.getChild(0), context); + + context.cfg().addInstruction( + insts.BinaryOpInstruction(translateBinaryOpcode(n.getChild(0)), false, false, result, c.getValue(l), c.getValue(r), + mayBeInteger)); + + if (mayBeInteger) { + context.cfg().newBlock(true); + } + } + + protected boolean visitUnaryExpr(CAstNode n, WalkContext c, CAstVisitor visitor) { + WalkContext context = (WalkContext) c; + int result = context.currentScope().allocateTempValue(); + c.setValue(n, result); + return false; + } + + protected void leaveUnaryExpr(CAstNode n, WalkContext c, CAstVisitor visitor) { + WalkContext context = (WalkContext) c; + int result = c.getValue(n); + CAstNode v = n.getChild(1); + context.cfg().addInstruction(insts.UnaryOpInstruction(translateUnaryOpcode(n.getChild(0)), result, c.getValue(v))); + } + + protected boolean visitArrayLength(CAstNode n, WalkContext c, CAstVisitor visitor) { + WalkContext context = (WalkContext) c; + int result = context.currentScope().allocateTempValue(); + c.setValue(n, result); + return false; + } + + protected void leaveArrayLength(CAstNode n, WalkContext c, CAstVisitor visitor) { + WalkContext context = (WalkContext) c; + int result = c.getValue(n); + int arrayValue = c.getValue(n.getChild(0)); + context.cfg().addInstruction(insts.ArrayLengthInstruction(result, arrayValue)); + } + + protected boolean visitArrayRef(CAstNode n, WalkContext c, CAstVisitor visitor) { /* empty */ + return false; + } + + protected void leaveArrayRef(CAstNode n, WalkContext c, CAstVisitor visitor) { + WalkContext context = (WalkContext) c; + int arrayValue = c.getValue(n.getChild(0)); + int result = context.currentScope().allocateTempValue(); + c.setValue(n, result); + arrayOpHandler.doArrayRead(context, result, arrayValue, n, gatherArrayDims(c, n)); + } + + protected boolean visitDeclStmt(CAstNode n, WalkContext c, CAstVisitor visitor) { /* empty */ + return false; + } + + // TODO: should we handle exploded declaration nodes here instead? + protected void leaveDeclStmt(CAstNode n, WalkContext c, CAstVisitor visitor) { + CAstSymbol s = (CAstSymbol) n.getChild(0).getValue(); + String nm = s.name(); + Scope scope = c.currentScope(); + if (n.getChildCount() == 2) { + CAstNode v = n.getChild(1); + if (scope.contains(nm) && scope.lookup(nm).getDefiningScope() == scope) { + assert !s.isFinal(); + doLocalWrite(c, nm, c.getValue(v)); + } else if (v.getKind() != CAstNode.CONSTANT && v.getKind() != CAstNode.VAR && v.getKind() != CAstNode.THIS) { + scope.declare(s, c.getValue(v)); + } else { + scope.declare(s); + doLocalWrite(c, nm, c.getValue(v)); + } + } else { + c.currentScope().declare(s); + } + } + + protected boolean visitReturn(CAstNode n, WalkContext c, CAstVisitor visitor) { /* empty */ + return false; + } + + protected void leaveReturn(CAstNode n, WalkContext c, CAstVisitor visitor) { + WalkContext context = (WalkContext) c; + if (n.getChildCount() > 0) { + context.cfg().addInstruction(insts.ReturnInstruction(c.getValue(n.getChild(0)), false)); + } else { + context.cfg().addInstruction(insts.ReturnInstruction()); + } + + context.cfg().addPreNode(n, context.getUnwindState()); + context.cfg().newBlock(false); + context.cfg().addPreEdgeToExit(n, false); + } + + protected boolean visitIfgoto(CAstNode n, WalkContext c, CAstVisitor visitor) { /* empty */ + return false; + } + + protected void leaveIfgoto(CAstNode n, WalkContext c, CAstVisitor visitor) { + WalkContext context = (WalkContext) c; + if (n.getChildCount() == 1) { + context.cfg().addInstruction( + insts.ConditionalBranchInstruction(translateConditionOpcode(CAstOperator.OP_NE), null, c.getValue(n.getChild(0)), context + .currentScope().getConstantValue(new Integer(0)))); + } else if (n.getChildCount() == 3) { + context.cfg().addInstruction( + insts.ConditionalBranchInstruction(translateConditionOpcode(n.getChild(0)), null, c.getValue(n.getChild(1)), + c.getValue(n.getChild(2)))); + } else { + Assertions.UNREACHABLE(); + } + + context.cfg().addPreNode(n, context.getUnwindState()); + context.cfg().newBlock(true); + context.cfg().addPreEdge(n, context.getControlFlow().getTarget(n, Boolean.TRUE), false); + } + + protected boolean visitGoto(CAstNode n, WalkContext c, CAstVisitor visitor) { /* empty */ + return false; + } + + protected void leaveGoto(CAstNode n, WalkContext c, CAstVisitor visitor) { + WalkContext context = (WalkContext) c; + if (!context.cfg().isDeadBlock(context.cfg().getCurrentBlock())) { + context.cfg().addPreNode(n, context.getUnwindState()); + context.cfg().addInstruction(insts.GotoInstruction()); + context.cfg().newBlock(false); + if (context.getControlFlow().getTarget(n, null) == null) { + assert context.getControlFlow().getTarget(n, null) != null : context.getControlFlow() + " does not map " + n + " (" + + context.getSourceMap().getPosition(n) + ")"; + } + context.cfg().addPreEdge(n, context.getControlFlow().getTarget(n, null), false); + } + } + + protected boolean visitLabelStmt(CAstNode n, WalkContext c, CAstVisitor visitor) { + WalkContext context = (WalkContext) c; + if (!context.getControlFlow().getSourceNodes(n).isEmpty()) { + context.cfg().newBlock(true); + context.cfg().addPreNode(n, context.getUnwindState()); + } + return false; + } + + protected void leaveLabelStmt(CAstNode n, WalkContext c, CAstVisitor visitor) { /* empty */ + } + + protected void processIf(CAstNode n, boolean isExpr, WalkContext c, CAstVisitor visitor) { + WalkContext context = (WalkContext) c; + PreBasicBlock trueB = null, falseB = null; + // conditional + CAstNode l = n.getChild(0); + visitor.visit(l, context, visitor); + context.cfg().addInstruction( + insts.ConditionalBranchInstruction(translateConditionOpcode(CAstOperator.OP_EQ), null, c.getValue(l), context.currentScope() + .getConstantValue(new Integer(0)))); + PreBasicBlock srcB = context.cfg().getCurrentBlock(); + // true clause + context.cfg().newBlock(true); + CAstNode r = n.getChild(1); + visitor.visit(r, context, visitor); + if (isExpr) + context.cfg().addInstruction(new AssignInstruction(c.getValue(n), c.getValue(r))); + if (n.getChildCount() == 3) { + if (!context.cfg().isDeadBlock(context.cfg().getCurrentBlock())) { + context.cfg().addInstruction(insts.GotoInstruction()); + trueB = context.cfg().getCurrentBlock(); + + // false clause + context.cfg().newBlock(false); + } + + falseB = context.cfg().getCurrentBlock(); + CAstNode f = n.getChild(2); + visitor.visit(f, context, visitor); + if (isExpr) + context.cfg().addInstruction(new AssignInstruction(c.getValue(n), c.getValue(f))); + } + + // end + context.cfg().newBlock(true); + if (n.getChildCount() == 3) { + if (trueB != null) + context.cfg().addEdge(trueB, context.cfg().getCurrentBlock()); + context.cfg().addEdge(srcB, falseB); + } else { + context.cfg().addEdge(srcB, context.cfg().getCurrentBlock()); + } + } + + // Make final to prevent overriding + protected final void leaveIfStmtCondition(CAstNode n, WalkContext c, CAstVisitor visitor) { /* empty */ + } + + protected final void leaveIfStmtTrueClause(CAstNode n, WalkContext c, CAstVisitor visitor) { /* empty */ + } + + protected final void leaveIfStmt(CAstNode n, WalkContext c, CAstVisitor visitor) { /* empty */ + } + + protected final void leaveIfExprCondition(CAstNode n, WalkContext c, CAstVisitor visitor) { /* empty */ + } + + protected final void leaveIfExprTrueClause(CAstNode n, WalkContext c, CAstVisitor visitor) { /* empty */ + } + + protected final void leaveIfExpr(CAstNode n, WalkContext c, CAstVisitor visitor) { /* empty */ + } + + protected boolean visitIfStmt(CAstNode n, WalkContext c, CAstVisitor visitor) { + processIf(n, false, c, visitor); + return true; + } + + protected boolean visitIfExpr(CAstNode n, WalkContext c, CAstVisitor visitor) { + WalkContext context = (WalkContext) c; + int result = context.currentScope().allocateTempValue(); + c.setValue(n, result); + processIf(n, true, c, visitor); + return true; + } + + protected boolean visitNew(CAstNode n, WalkContext c, CAstVisitor visitor) { /* empty */ + return false; + } + + protected void leaveNew(CAstNode n, WalkContext c, CAstVisitor visitor) { + WalkContext context = (WalkContext) c; + + int result = context.currentScope().allocateTempValue(); + c.setValue(n, result); + + int[] arguments; + if (n.getChildCount() <= 1) { + arguments = null; + } else { + arguments = new int[n.getChildCount() - 1]; + for (int i = 1; i < n.getChildCount(); i++) { + arguments[i - 1] = c.getValue(n.getChild(i)); + } + } + doNewObject(context, n, result, n.getChild(0).getValue(), arguments); + } + + protected boolean visitObjectLiteral(CAstNode n, WalkContext c, CAstVisitor visitor) { /* empty */ + return false; + } + + protected void leaveObjectLiteralFieldInit(CAstNode n, int i, WalkContext c, CAstVisitor visitor) { + WalkContext context = (WalkContext) c; + if (n.getChild(i).getKind() == CAstNode.EMPTY) { + handleUnspecifiedLiteralKey(context, n, i, visitor); + } + doFieldWrite(context, c.getValue(n.getChild(0)), n.getChild(i), n, c.getValue(n.getChild(i + 1))); + } + + protected void leaveObjectLiteral(CAstNode n, WalkContext c, CAstVisitor visitor) { + c.setValue(n, c.getValue(n.getChild(0))); + } + + protected boolean visitArrayLiteral(CAstNode n, WalkContext c, CAstVisitor visitor) { /* empty */ + return false; + } + + protected void leaveArrayLiteralObject(CAstNode n, WalkContext c, CAstVisitor visitor) { + c.setValue(n, c.getValue(n.getChild(0))); + } + + protected void leaveArrayLiteralInitElement(CAstNode n, int i, WalkContext c, CAstVisitor visitor) { + WalkContext context = (WalkContext) c; + arrayOpHandler.doArrayWrite(context, c.getValue(n.getChild(0)), n, + new int[] { context.currentScope().getConstantValue(new Integer(i - 1)) }, c.getValue(n.getChild(i))); + } + + protected void leaveArrayLiteral(CAstNode n, WalkContext c, CAstVisitor visitor) { /* empty */ + } + + protected boolean visitObjectRef(CAstNode n, WalkContext c, CAstVisitor visitor) { + WalkContext context = (WalkContext) c; + int result = context.currentScope().allocateTempValue(); + c.setValue(n, result); + return false; + } + + protected void leaveObjectRef(CAstNode n, WalkContext c, CAstVisitor visitor) { + WalkContext context = (WalkContext) c; + int result = c.getValue(n); + CAstNode elt = n.getChild(1); + doFieldRead(context, result, c.getValue(n.getChild(0)), elt, n); + } + + public boolean visitAssign(CAstNode n, WalkContext c, CAstVisitor visitor) { /* empty */ + return false; + } + + public void leaveAssign(CAstNode n, WalkContext c, CAstVisitor visitor) { + if (n.getKind() == CAstNode.ASSIGN) { + c.setValue(n, c.getValue(n.getChild(1))); + } else { + c.setValue(n, c.getValue(n.getChild(0))); + } + } + + private int[] gatherArrayDims(WalkContext c, CAstNode n) { + int numDims = n.getChildCount() - 2; + int[] dims = new int[numDims]; + for (int i = 0; i < numDims; i++) + dims[i] = c.getValue(n.getChild(i + 2)); + return dims; + } + + /* Prereq: a.getKind() == ASSIGN_PRE_OP || a.getKind() == ASSIGN_POST_OP */ + protected int processAssignOp(CAstNode n, CAstNode v, CAstNode a, int temp, boolean post, WalkContext c) { + WalkContext context = (WalkContext) c; + int rval = c.getValue(v); + CAstNode op = a.getChild(2); + int temp2 = context.currentScope().allocateTempValue(); + + boolean mayBeInteger = handleBinaryOpThrow(a, op, context); + + context.cfg().addInstruction( + insts.BinaryOpInstruction(translateBinaryOpcode(op), false, false, temp2, temp, rval, mayBeInteger)); + + if (mayBeInteger) { + context.cfg().newBlock(true); + } + + return temp2; + } + + protected boolean visitArrayRefAssign(CAstNode n, CAstNode v, CAstNode a, WalkContext c, CAstVisitor visitor) { /* empty */ + return false; + } + + protected void leaveArrayRefAssign(CAstNode n, CAstNode v, CAstNode a, WalkContext c, CAstVisitor visitor) { + WalkContext context = (WalkContext) c; + int rval = c.getValue(v); + c.setValue(n, rval); + arrayOpHandler.doArrayWrite(context, c.getValue(n.getChild(0)), n, gatherArrayDims(c, n), rval); + } + + protected boolean visitArrayRefAssignOp(CAstNode n, CAstNode v, CAstNode a, boolean pre, WalkContext c, CAstVisitor visitor) { /* empty */ + return false; + } + + protected void leaveArrayRefAssignOp(CAstNode n, CAstNode v, CAstNode a, boolean pre, WalkContext c, CAstVisitor visitor) { + WalkContext context = (WalkContext) c; + int temp = context.currentScope().allocateTempValue(); + int[] dims = gatherArrayDims(c, n); + arrayOpHandler.doArrayRead(context, temp, c.getValue(n.getChild(0)), n, dims); + int rval = processAssignOp(n, v, a, temp, !pre, c); + c.setValue(n, pre ? rval : temp); + arrayOpHandler.doArrayWrite(context, c.getValue(n.getChild(0)), n, dims, rval); + } + + protected boolean visitObjectRefAssign(CAstNode n, CAstNode v, CAstNode a, WalkContext c, CAstVisitor visitor) { /* empty */ + return false; + } + + protected void leaveObjectRefAssign(CAstNode n, CAstNode v, CAstNode a, WalkContext c, CAstVisitor visitor) { + WalkContext context = (WalkContext) c; + int rval = c.getValue(v); + c.setValue(n, rval); + doFieldWrite(context, c.getValue(n.getChild(0)), n.getChild(1), n, rval); + } + + protected void processObjectRefAssignOp(CAstNode n, CAstNode v, CAstNode a, WalkContext c) { + } + + protected boolean visitObjectRefAssignOp(CAstNode n, CAstNode v, CAstNode a, boolean pre, WalkContext c, CAstVisitor visitor) { /* empty */ + return false; + } + + protected void leaveObjectRefAssignOp(CAstNode n, CAstNode v, CAstNode a, boolean pre, WalkContext c, CAstVisitor visitor) { + WalkContext context = (WalkContext) c; + int temp = context.currentScope().allocateTempValue(); + doFieldRead(context, temp, c.getValue(n.getChild(0)), n.getChild(1), n); + int rval = processAssignOp(n, v, a, temp, !pre, c); + c.setValue(n, pre ? rval : temp); + doFieldWrite(context, c.getValue(n.getChild(0)), n.getChild(1), n, rval); + } + + protected boolean visitBlockExprAssign(CAstNode n, CAstNode v, CAstNode a, WalkContext c, CAstVisitor visitor) { /* empty */ + return false; + } + + protected void leaveBlockExprAssign(CAstNode n, CAstNode v, CAstNode a, WalkContext c, CAstVisitor visitor) { + c.setValue(n, c.getValue(n.getChild(n.getChildCount() - 1))); + } + + protected boolean visitBlockExprAssignOp(CAstNode n, CAstNode v, CAstNode a, boolean pre, WalkContext c, CAstVisitor visitor) { /* empty */ + return false; + } + + protected void leaveBlockExprAssignOp(CAstNode n, CAstNode v, CAstNode a, boolean pre, WalkContext c, CAstVisitor visitor) { /* empty */ + c.setValue(n, c.getValue(n.getChild(n.getChildCount() - 1))); + } + + protected boolean visitVarAssign(CAstNode n, CAstNode v, CAstNode a, WalkContext c, CAstVisitor visitor) { /* empty */ + return false; + } + + /** + * assign rval to nm as appropriate, depending on the scope of ls + */ + protected void assignValue(CAstNode n, WalkContext context, Symbol ls, String nm, int rval) { + if (context.currentScope().isGlobal(ls)) + doGlobalWrite(context, nm, rval); + else if (context.currentScope().isLexicallyScoped(ls)) { + doLexicallyScopedWrite(context, nm, rval); + } else { + assert rval != -1 : CAstPrinter.print(n, context.top().getSourceMap()); + doLocalWrite(context, nm, rval); + } + } + + protected void leaveVarAssign(CAstNode n, CAstNode v, CAstNode a, WalkContext c, CAstVisitor visitor) { + WalkContext context = (WalkContext) c; + int rval = c.getValue(v); + String nm = (String) n.getChild(0).getValue(); + Symbol ls = context.currentScope().lookup(nm); + c.setValue(n, rval); + assignValue(n, context, ls, nm, rval); + } + + protected boolean visitVarAssignOp(CAstNode n, CAstNode v, CAstNode a, boolean pre, WalkContext c, CAstVisitor visitor) { /* empty */ + return false; + } + + protected void leaveVarAssignOp(CAstNode n, CAstNode v, CAstNode a, boolean pre, WalkContext c, CAstVisitor visitor) { + WalkContext context = (WalkContext) c; + String nm = (String) n.getChild(0).getValue(); + Symbol ls = context.currentScope().lookup(nm); + int temp; + + if (context.currentScope().isGlobal(ls)) + temp = doGlobalRead(n, context, nm); + else if (context.currentScope().isLexicallyScoped(ls)) { + temp = doLexicallyScopedRead(n, context, nm); + } else { + temp = doLocalRead(context, nm); + } + + if (!pre) { + int ret = context.currentScope().allocateTempValue(); + context.cfg().addInstruction(new AssignInstruction(ret, temp)); + c.setValue(n, ret); + } + + int rval = processAssignOp(n, v, a, temp, !pre, c); + + if (pre) { + c.setValue(n, rval); + } + + if (context.currentScope().isGlobal(ls)) { + doGlobalWrite(context, nm, rval); + } else if (context.currentScope().isLexicallyScoped(ls)) { + doLexicallyScopedWrite(context, nm, rval); + } else { + doLocalWrite(context, nm, rval); + } + } + + private boolean isSimpleSwitch(CAstNode n, WalkContext context, CAstVisitor visitor) { + CAstControlFlowMap ctrl = context.getControlFlow(); + Collection caseLabels = ctrl.getTargetLabels(n); + for (Iterator kases = caseLabels.iterator(); kases.hasNext();) { + Object x = kases.next(); + + if (x == CAstControlFlowMap.SWITCH_DEFAULT) + continue; + + CAstNode xn = (CAstNode) x; + if (xn.getKind() == CAstNode.CONSTANT) { + visitor.visit(xn, context, visitor); + if (context.getValue(xn) != -1) { + if (context.currentScope().isConstant(context.getValue(xn))) { + Object val = context.currentScope().getConstantObject(context.getValue(xn)); + if (val instanceof Number) { + Number num = (Number) val; + if ((double) num.intValue() == num.doubleValue()) { + continue; + } + } + } + } + } + + return false; + } + + return true; + } + + private void doSimpleSwitch(CAstNode n, WalkContext context, CAstVisitor visitor) { + PreBasicBlock defaultHackBlock = null; + CAstControlFlowMap ctrl = context.getControlFlow(); + + CAstNode switchValue = n.getChild(0); + visitor.visit(switchValue, context, visitor); + int v = context.getValue(switchValue); + + boolean hasExplicitDefault = ctrl.getTarget(n, CAstControlFlowMap.SWITCH_DEFAULT) != null; + + Collection caseLabels = ctrl.getTargetLabels(n); + int cases = caseLabels.size(); + if (hasExplicitDefault) + cases--; + int[] casesAndLabels = new int[cases * 2]; + + int defaultBlock = context.cfg().getCurrentBlock().getGraphNodeId() + 1; + + context.cfg().addInstruction(insts.SwitchInstruction(v, defaultBlock, casesAndLabels)); + context.cfg().addPreNode(n, context.getUnwindState()); + // PreBasicBlock switchB = context.cfg().getCurrentBlock(); + context.cfg().newBlock(true); + + context.cfg().addInstruction(insts.GotoInstruction()); + defaultHackBlock = context.cfg().getCurrentBlock(); + context.cfg().newBlock(false); + + CAstNode switchBody = n.getChild(1); + visitor.visit(switchBody, context, visitor); + context.cfg().newBlock(true); + + if (!hasExplicitDefault) { + context.cfg().addEdge(defaultHackBlock, context.cfg().getCurrentBlock()); + } + + int cn = 0; + for (Iterator kases = caseLabels.iterator(); kases.hasNext();) { + Object x = kases.next(); + CAstNode target = ctrl.getTarget(n, x); + if (x == CAstControlFlowMap.SWITCH_DEFAULT) { + context.cfg().addEdge(defaultHackBlock, context.cfg().getBlock(target)); + } else { + Number caseLabel = (Number) context.currentScope().getConstantObject(context.getValue((CAstNode) x)); + casesAndLabels[2 * cn] = caseLabel.intValue(); + casesAndLabels[2 * cn + 1] = context.cfg().getBlock(target).getGraphNodeId(); + cn++; + + context.cfg().addPreEdge(n, target, false); + } + } + } + + private void doIfConvertSwitch(CAstNode n, WalkContext context, CAstVisitor visitor) { + CAstControlFlowMap ctrl = context.getControlFlow(); + context.cfg().addPreNode(n, context.getUnwindState()); + + CAstNode switchValue = n.getChild(0); + visitor.visit(switchValue, context, visitor); + int v = context.getValue(switchValue); + + Collection caseLabels = ctrl.getTargetLabels(n); + Map labelToBlock = new LinkedHashMap(); + for (Iterator kases = caseLabels.iterator(); kases.hasNext();) { + Object x = kases.next(); + if (x != CAstControlFlowMap.SWITCH_DEFAULT) { + visitor.visit((CAstNode) x, context, visitor); + context.cfg().addInstruction( + insts.ConditionalBranchInstruction(translateConditionOpcode(CAstOperator.OP_EQ), null, v, context.getValue((CAstNode) x))); + labelToBlock.put(x, context.cfg().getCurrentBlock()); + context.cfg().newBlock(true); + } + } + + PreBasicBlock defaultGotoBlock = context.cfg().getCurrentBlock(); + context.cfg().addInstruction(insts.GotoInstruction()); + context.cfg().newBlock(false); + + CAstNode switchBody = n.getChild(1); + visitor.visit(switchBody, context, visitor); + context.cfg().newBlock(true); + + for (Iterator kases = caseLabels.iterator(); kases.hasNext();) { + Object x = kases.next(); + if (x != CAstControlFlowMap.SWITCH_DEFAULT) { + CAstNode target = ctrl.getTarget(n, x); + context.cfg().addEdge(labelToBlock.get(x), context.cfg().getBlock(target)); + } + } + + if (ctrl.getTarget(n, CAstControlFlowMap.SWITCH_DEFAULT) == null) { + context.cfg().addEdge(defaultGotoBlock, context.cfg().getCurrentBlock()); + } else { + CAstNode target = ctrl.getTarget(n, CAstControlFlowMap.SWITCH_DEFAULT); + context.cfg().addEdge(defaultGotoBlock, context.cfg().getBlock(target)); + } + } + + protected boolean visitSwitch(CAstNode n, WalkContext c, CAstVisitor visitor) { + WalkContext context = (WalkContext) c; + if (isSimpleSwitch(n, context, visitor)) { + doSimpleSwitch(n, context, visitor); + } else { + doIfConvertSwitch(n, context, visitor); + } + return true; + } + + // Make final to prevent overriding + protected final void leaveSwitchValue(CAstNode n, WalkContext c, CAstVisitor visitor) { /* empty */ + } + + protected final void leaveSwitch(CAstNode n, WalkContext c, CAstVisitor visitor) { /* empty */ + } + + protected boolean visitThrow(CAstNode n, WalkContext c, CAstVisitor visitor) { /* empty */ + return false; + } + + protected void leaveThrow(CAstNode n, WalkContext c, CAstVisitor visitor) { + WalkContext context = (WalkContext) c; + doThrow(context, c.getValue(n.getChild(0))); + + context.cfg().addPreNode(n, context.getUnwindState()); + context.cfg().newBlock(false); + + Collection labels = context.getControlFlow().getTargetLabels(n); + for (Iterator iter = labels.iterator(); iter.hasNext();) { + Object label = iter.next(); + CAstNode target = context.getControlFlow().getTarget(n, label); + if (target == CAstControlFlowMap.EXCEPTION_TO_EXIT) + context.cfg().addPreEdgeToExit(n, true); + else + context.cfg().addPreEdge(n, target, true); + } + } + + protected boolean visitCatch(CAstNode n, WalkContext c, CAstVisitor visitor) { + WalkContext context = (WalkContext) c; + + // unreachable catch block + if (context.getControlFlow().getSourceNodes(n).isEmpty()) { + return true; + } + + String id = (String) n.getChild(0).getValue(); + context.cfg().setCurrentBlockAsHandler(); + if (!context.currentScope().contains(id)) { + context.currentScope().declare(new FinalCAstSymbol(id)); + } + context.cfg().addInstruction( + insts.GetCaughtExceptionInstruction(context.cfg().getCurrentBlock().getNumber(), context.currentScope().lookup(id) + .valueNumber())); + + context.cfg().addPreNode(n, context.getUnwindState()); + + CAstType caughtType = getTypeForNode(context, n); + if (caughtType != null) { + TypeReference caughtRef = makeType(caughtType); + context.setCatchType(n, caughtRef); + } else { + context.setCatchType(n, defaultCatchType()); + } + + return false; + } + + protected void leaveCatch(CAstNode n, WalkContext c, CAstVisitor visitor) { /* empty */ + } + + protected boolean visitUnwind(CAstNode n, WalkContext c, CAstVisitor visitor) { /* empty */ + return false; + } + + protected void leaveUnwind(CAstNode n, WalkContext c, CAstVisitor visitor) { /* empty */ + } + + private boolean hasIncomingEdges(CAstNode n, WalkContext context) { + if (context.cfg().hasDelayedEdges(n)) { + return true; + } else { + for (int i = 0; i < n.getChildCount(); i++) { + if (hasIncomingEdges(n.getChild(i), context)) { + return true; + } + } + + return false; + } + } + + protected boolean visitTry(final CAstNode n, WalkContext c, CAstVisitor visitor) { + final WalkContext context = (WalkContext) c; + boolean addSkipCatchGoto = false; + visitor.visit(n.getChild(0), context, visitor); + PreBasicBlock endOfTry = context.cfg().getCurrentBlock(); + + if (!hasIncomingEdges(n.getChild(1), context)) { + if (loader instanceof CAstAbstractLoader) { + ((CAstAbstractLoader) loader).addMessage(context.getModule(), new Warning(Warning.MILD) { + @Override + public String getMsg() { + return "Dead catch block at " + getPosition(context.getSourceMap(), n.getChild(1)); + } + }); + } + return true; + } + + if (!context.cfg().isDeadBlock(context.cfg().getCurrentBlock())) { + addSkipCatchGoto = true; + context.cfg().addInstruction(insts.GotoInstruction()); + context.cfg().newBlock(false); + } + + context.cfg().noteCatchBlock(); + visitor.visit(n.getChild(1), context, visitor); + + if (!context.cfg().isDeadBlock(context.cfg().getCurrentBlock())) { + context.cfg().newBlock(true); + } + + if (addSkipCatchGoto) { + PreBasicBlock afterBlock = context.cfg().getCurrentBlock(); + context.cfg().addEdge(endOfTry, afterBlock); + } + return true; + } + + // Make final to prevent overriding + protected final void leaveTryBlock(CAstNode n, WalkContext c, CAstVisitor visitor) { /* empty */ + } + + protected final void leaveTry(CAstNode n, WalkContext c, CAstVisitor visitor) { /* empty */ + } + + protected boolean visitEmpty(CAstNode n, WalkContext c, CAstVisitor visitor) { /* empty */ + return false; + } + + protected void leaveEmpty(CAstNode n, WalkContext c, CAstVisitor visitor) { + WalkContext context = (WalkContext) c; + c.setValue(n, context.currentScope().getConstantValue(null)); + } + + protected boolean visitPrimitive(CAstNode n, WalkContext c, CAstVisitor visitor) { /* empty */ + return false; + } + + protected void leavePrimitive(CAstNode n, WalkContext c, CAstVisitor visitor) { + WalkContext context = (WalkContext) c; + int result = context.currentScope().allocateTempValue(); + c.setValue(n, result); + + doPrimitive(result, context, n); + } + + protected boolean visitVoid(CAstNode n, WalkContext c, CAstVisitor visitor) { /* empty */ + return false; + } + + protected void leaveVoid(CAstNode n, WalkContext c, CAstVisitor visitor) { + c.setValue(n, -1); + } + + protected boolean visitAssert(CAstNode n, WalkContext c, CAstVisitor visitor) { /* empty */ + return false; + } + + protected void leaveAssert(CAstNode n, WalkContext c, CAstVisitor visitor) { + WalkContext context = (WalkContext) c; + boolean fromSpec = true; + int result = c.getValue(n.getChild(0)); + if (n.getChildCount() == 2) { + assert n.getChild(1).getKind() == CAstNode.CONSTANT; + assert n.getChild(1).getValue() instanceof Boolean; + fromSpec = n.getChild(1).getValue().equals(Boolean.TRUE); + } + context.cfg().addInstruction(new AstAssertInstruction(result, fromSpec)); + } + + protected boolean visitEachElementGet(CAstNode n, WalkContext c, CAstVisitor visitor) { + return false; + } + + protected void leaveEachElementGet(CAstNode n, WalkContext c, CAstVisitor visitor) { + int result = ((WalkContext) c).currentScope().allocateTempValue(); + c.setValue(n, result); + ((WalkContext) c).cfg().addInstruction(new EachElementGetInstruction(result, c.getValue(n.getChild(0)))); + } + + protected boolean visitEachElementHasNext(CAstNode n, WalkContext c, CAstVisitor visitor) { + return false; + } + + @Override + protected void leaveEachElementHasNext(CAstNode n, WalkContext c, CAstVisitor visitor) { + int result = ((WalkContext) c).currentScope().allocateTempValue(); + c.setValue(n, result); + ((WalkContext) c).cfg().addInstruction(new EachElementHasNextInstruction(result, c.getValue(n.getChild(0)))); + } + + protected boolean visitTypeLiteralExpr(CAstNode n, WalkContext c, CAstVisitor visitor) { + return false; + } + + protected void leaveTypeLiteralExpr(CAstNode n, WalkContext c, CAstVisitor visitor) { + WalkContext wc = (WalkContext) c; + assert n.getChild(0).getKind() == CAstNode.CONSTANT; + String typeNameStr = (String) n.getChild(0).getValue(); + TypeName typeName = TypeName.string2TypeName(typeNameStr); + TypeReference typeRef = TypeReference.findOrCreate(loader.getReference(), typeName); + + int result = wc.currentScope().allocateTempValue(); + c.setValue(n, result); + + wc.cfg().addInstruction(insts.LoadMetadataInstruction(result, loader.getLanguage().getConstantType(typeRef), typeRef)); + } + + protected boolean visitIsDefinedExpr(CAstNode n, WalkContext c, CAstVisitor visitor) { + return false; + } + + protected void leaveIsDefinedExpr(CAstNode n, WalkContext c, CAstVisitor visitor) { + WalkContext wc = (WalkContext) c; + int ref = c.getValue(n.getChild(0)); + int result = wc.currentScope().allocateTempValue(); + c.setValue(n, result); + if (n.getChildCount() == 1) { + wc.cfg().addInstruction(new AstIsDefinedInstruction(result, ref)); + } else { + doIsFieldDefined(wc, result, ref, n.getChild(1)); + } + } + + protected boolean visitEcho(CAstNode n, WalkContext c, CAstVisitor visitor) { + return false; + } + + protected void leaveEcho(CAstNode n, WalkContext c, CAstVisitor visitor) { + WalkContext wc = (WalkContext) c; + + int rvals[] = new int[n.getChildCount()]; + for (int i = 0; i < n.getChildCount(); i++) { + rvals[i] = c.getValue(n.getChild(i)); + } + + wc.cfg().addInstruction(new AstEchoInstruction(rvals)); + } + + public CAstEntity getIncludedEntity(CAstNode n) { + if (n.getChild(0).getKind() == CAstNode.NAMED_ENTITY_REF) { + assert namedEntityResolver != null; + return (CAstEntity) namedEntityResolver.get(n.getChild(0).getChild(0).getValue()); + } else { + return (CAstEntity) n.getChild(0).getValue(); + } + } + + protected void leaveInclude(final CAstNode n, WalkContext c, CAstVisitor visitor) { + WalkContext wc = (WalkContext) c; + + CAstEntity included = getIncludedEntity(n); + + if (included == null) { + System.err.println(("cannot find include for " + CAstPrinter.print(n))); + System.err.println(("from:\n" + namedEntityResolver)); + } else { + final boolean isMacroExpansion = (included.getKind() == CAstEntity.MACRO_ENTITY); + + System.err.println("found " + included.getName() + " for " + CAstPrinter.print(n)); + + final CAstEntity copy = (new CAstCloner(new CAstImpl(), true) { + + private CAstNode copyIncludeExpr(CAstNode expr) { + if (expr.getValue() != null) { + return Ast.makeConstant(expr.getValue()); + } else if (expr instanceof CAstOperator) { + return expr; + } else { + CAstNode nc[] = new CAstNode[expr.getChildCount()]; + + for (int i = 0; i < expr.getChildCount(); i++) { + nc[i] = copyIncludeExpr(expr.getChild(i)); + } + + return Ast.makeNode(expr.getKind(), nc); + } + } + + protected CAstNode copyNodes(CAstNode root, final CAstControlFlowMap cfg, NonCopyingContext c, Map, CAstNode> nodeMap) { + if (isMacroExpansion && root.getKind() == CAstNode.MACRO_VAR) { + int arg = ((Number) root.getChild(0).getValue()).intValue(); + CAstNode expr = copyIncludeExpr(n.getChild(arg)); + nodeMap.put(Pair.make(root, c.key()), expr); + return expr; + } else { + return super.copyNodesHackForEclipse(root, cfg, c, nodeMap); + } + } + }).rewrite(included); + + if (copy.getAST() == null) { + System.err.println((copy.getName() + " has no AST")); + + } else { + visit(copy.getAST(), new DelegatingContext(wc) { + public CAstSourcePositionMap getSourceMap() { + return copy.getSourceMap(); + } + + public CAstControlFlowMap getControlFlow() { + return copy.getControlFlow(); + } + }, visitor); + + visitor.visitScopedEntities(copy, copy.getAllScopedEntities(), wc, visitor); + } + } + } + + protected final void walkEntities(CAstEntity N, WalkContext c) { + visitEntities(N, c, this); + } + + public final class RootContext implements WalkContext { + private final Scope globalScope; + + private final CAstEntity N; + + private final ModuleEntry module; + + private final Map entityNames = new LinkedHashMap(); + + public RootContext(CAstEntity N, ModuleEntry module) { + this.N = N; + this.module = module; + this.globalScope = makeGlobalScope(); + } + + public ModuleEntry getModule() { + return module; + } + + public String file() { + return module.getName(); + } + + public CAstEntity top() { + return N; + } + + public Scope currentScope() { + return globalScope; + } + + public Set entityScopes() { + return Collections.singleton(globalScope); + } + + public CAstSourcePositionMap getSourceMap() { + return N.getSourceMap(); + } + + public CAstControlFlowMap getControlFlow() { + return N.getControlFlow(); + } + + public IncipientCFG cfg() { + return null; + } + + public UnwindState getUnwindState() { + return null; + } + + public String getName() { + return null; + } + + public void setCatchType(int blockNumber, TypeReference catchType) { + } + + public void setCatchType(CAstNode castNode, TypeReference catchType) { + } + + public TypeReference[][] getCatchTypes() { + return null; + } + + public void addEntityName(CAstEntity e, String name) { + entityNames.put(e, name); + } + + public String getEntityName(CAstEntity e) { + if (e == null) { + return null; + } else { + assert entityNames.containsKey(e); + return "L" + entityNames.get(e); + } + } + + public boolean hasValue(CAstNode n) { + assert false; + return false; + } + + public int setValue(CAstNode n, int v) { + assert false; + return 0; + } + + public int getValue(CAstNode n) { + assert false; + return -1; + } + + public Set, Integer>> exposeNameSet(CAstEntity entity, boolean writeSet) { + assert false; + return null; + } + + public Set getAccesses(CAstEntity e) { + assert false; + return null; + } + + public Scope getGlobalScope(){ + return globalScope; + } + + }; + + /** + * translate module, represented by {@link CAstEntity} N + */ + public void translate(final CAstEntity N, final ModuleEntry module) { + if (DEBUG_TOP) + System.err.println(("translating " + module.getName())); + // this.inlinedSourceMap = inlinedSourceMap; + final ExposedNamesCollector exposedNamesCollector = new ExposedNamesCollector(); + exposedNamesCollector.run(N); + entity2ExposedNames = exposedNamesCollector.getEntity2ExposedNames(); + // CAstEntity rewrite = (new ExposedParamRenamer(new CAstImpl(), + // entity2ExposedNames)).rewrite(N); + walkEntities(N, new RootContext(N, module)); + } + + public void translate(final CAstEntity N, final WalkContext context) { + final ExposedNamesCollector exposedNamesCollector = new ExposedNamesCollector(); + exposedNamesCollector.run(N); + entity2ExposedNames = exposedNamesCollector.getEntity2ExposedNames(); + walkEntities(N, context); + } + +} diff --git a/com.ibm.wala.cast/source/java/com/ibm/wala/cast/loader/CAstAbstractModuleLoader.java b/com.ibm.wala.cast/source/java/com/ibm/wala/cast/loader/CAstAbstractModuleLoader.java index 60e70be1f..8b200975a 100644 --- a/com.ibm.wala.cast/source/java/com/ibm/wala/cast/loader/CAstAbstractModuleLoader.java +++ b/com.ibm.wala.cast/source/java/com/ibm/wala/cast/loader/CAstAbstractModuleLoader.java @@ -1,196 +1,196 @@ -/****************************************************************************** - * Copyright (c) 2009 IBM Corporation. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * IBM Corporation - initial API and implementation - *****************************************************************************/ -package com.ibm.wala.cast.loader; - -import java.io.ByteArrayOutputStream; -import java.io.File; -import java.io.IOException; -import java.io.PrintStream; -import java.io.PrintWriter; -import java.net.MalformedURLException; -import java.util.Iterator; -import java.util.LinkedHashSet; -import java.util.List; -import java.util.Set; - -import com.ibm.wala.cast.ir.translator.TranslatorToCAst; -import com.ibm.wala.cast.ir.translator.TranslatorToIR; -import com.ibm.wala.cast.tree.CAst; -import com.ibm.wala.cast.tree.CAstEntity; -import com.ibm.wala.cast.tree.impl.CAstImpl; -import com.ibm.wala.cast.util.CAstPrinter; -import com.ibm.wala.cast.util.TemporaryFile; -import com.ibm.wala.classLoader.IClass; -import com.ibm.wala.classLoader.IClassLoader; -import com.ibm.wala.classLoader.Module; -import com.ibm.wala.classLoader.ModuleEntry; -import com.ibm.wala.classLoader.SourceFileModule; -import com.ibm.wala.classLoader.SourceModule; -import com.ibm.wala.ipa.cha.IClassHierarchy; -import com.ibm.wala.types.TypeName; -import com.ibm.wala.util.collections.Pair; -import com.ibm.wala.util.warnings.Warning; - -/** - * abstract class loader that performs CAst and IR generation for relevant - * entities in a list of {@link Module}s. Subclasses provide the CAst / IR - * translators appropriate for the language. - * - */ -public abstract class CAstAbstractModuleLoader extends CAstAbstractLoader { - - private static final boolean DEBUG = false; - - public CAstAbstractModuleLoader(IClassHierarchy cha, IClassLoader parent) { - super(cha, parent); - } - - public CAstAbstractModuleLoader(IClassHierarchy cha) { - this(cha, null); - } - - /** - * create the appropriate CAst translator for the language and source module - */ - protected abstract TranslatorToCAst getTranslatorToCAst(CAst ast, SourceModule M) throws IOException; - - /** - * should IR be generated for entity? - */ - protected abstract boolean shouldTranslate(CAstEntity entity); - - /** - * create the appropriate IR translator for the language - */ - protected abstract TranslatorToIR initTranslator(); - - protected File getLocalFile(SourceModule M) throws IOException { - if (M instanceof SourceFileModule) { - return ((SourceFileModule) M).getFile(); - } else { - File f = File.createTempFile("module", ".txt"); - f.deleteOnExit(); - TemporaryFile.streamToFile(f.getAbsolutePath(), M.getInputStream()); - return f; - } - } - - /** - * subclasses should override to perform actions after CAst and IR have been - * generated. by default, do nothing - */ - protected void finishTranslation() { - - } - - public void init(final List modules) { - - final CAst ast = new CAstImpl(); - - // convert everything to CAst - final Set> topLevelEntities = new LinkedHashSet>(); - for (Iterator mes = modules.iterator(); mes.hasNext();) { - translateModuleToCAst(mes.next(), ast, topLevelEntities); - } - - // generate IR as needed - final TranslatorToIR xlatorToIR = initTranslator(); - - for (Iterator> tles = topLevelEntities.iterator(); tles.hasNext();) { - Pair p = tles.next(); - if (shouldTranslate(p.fst)) { - xlatorToIR.translate(p.fst, p.snd); - } - } - - if (DEBUG) { - for (Iterator ts = types.keySet().iterator(); ts.hasNext();) { - TypeName tn = (TypeName) ts.next(); - try { - System.err.println(("found type " + tn + " : " + types.get(tn) + " < " + ((IClass) types.get(tn)).getSuperclass())); - } catch (Exception e) { - System.err.println(e); - } - } - } - - finishTranslation(); - } - - /** - * translate moduleEntry to CAst and store result in topLevelEntities - * - * @param ast - * @param topLevelEntities - */ - private void translateModuleEntryToCAst(ModuleEntry moduleEntry, CAst ast, Set> topLevelEntities) { - try { - if (moduleEntry.isModuleFile()) { - // nested module - translateModuleToCAst(moduleEntry.asModule(), ast, topLevelEntities); - } else if (moduleEntry instanceof SourceModule) { - TranslatorToCAst xlatorToCAst = getTranslatorToCAst(ast, (SourceModule) moduleEntry); - - CAstEntity fileEntity = xlatorToCAst.translateToCAst(); - - if (fileEntity != null) { - if (DEBUG) { - CAstPrinter.printTo(fileEntity, new PrintWriter(System.err)); - } - topLevelEntities.add(Pair.make(fileEntity, moduleEntry)); - - } else { - addMessage(moduleEntry, new Warning(Warning.SEVERE) { - @Override - public String getMsg() { - return "parse error"; - } - }); - } - } - } catch (final MalformedURLException e) { - addMessage(moduleEntry, new Warning(Warning.SEVERE) { - @Override - public String getMsg() { - return "Malformed URL issue: " + e.getMessage(); - } - }); - } catch (final IOException e) { - addMessage(moduleEntry, new Warning(Warning.SEVERE) { - @Override - public String getMsg() { - return "I/O issue: " + e.getMessage(); - } - }); - } catch (final RuntimeException e) { - final ByteArrayOutputStream s = new ByteArrayOutputStream(); - PrintStream ps = new PrintStream(s); - e.printStackTrace(ps); - addMessage(moduleEntry, new Warning(Warning.SEVERE) { - @Override - public String getMsg() { - return "Parsing issue: " + new String(s.toByteArray()); - } - }); - } - } - - /** - * translate all relevant entities in the module to CAst, storing the results - * in topLevelEntities - */ - private void translateModuleToCAst(Module module, CAst ast, Set> topLevelEntities) { - for (Iterator mes = module.getEntries(); mes.hasNext();) { - translateModuleEntryToCAst(mes.next(), ast, topLevelEntities); - } - } - -} +/****************************************************************************** + * Copyright (c) 2009 IBM Corporation. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *****************************************************************************/ +package com.ibm.wala.cast.loader; + +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.IOException; +import java.io.PrintStream; +import java.io.PrintWriter; +import java.net.MalformedURLException; +import java.util.Iterator; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Set; + +import com.ibm.wala.cast.ir.translator.TranslatorToCAst; +import com.ibm.wala.cast.ir.translator.TranslatorToIR; +import com.ibm.wala.cast.tree.CAst; +import com.ibm.wala.cast.tree.CAstEntity; +import com.ibm.wala.cast.tree.impl.CAstImpl; +import com.ibm.wala.cast.util.CAstPrinter; +import com.ibm.wala.cast.util.TemporaryFile; +import com.ibm.wala.classLoader.IClass; +import com.ibm.wala.classLoader.IClassLoader; +import com.ibm.wala.classLoader.Module; +import com.ibm.wala.classLoader.ModuleEntry; +import com.ibm.wala.classLoader.SourceFileModule; +import com.ibm.wala.classLoader.SourceModule; +import com.ibm.wala.ipa.cha.IClassHierarchy; +import com.ibm.wala.types.TypeName; +import com.ibm.wala.util.collections.Pair; +import com.ibm.wala.util.warnings.Warning; + +/** + * abstract class loader that performs CAst and IR generation for relevant + * entities in a list of {@link Module}s. Subclasses provide the CAst / IR + * translators appropriate for the language. + * + */ +public abstract class CAstAbstractModuleLoader extends CAstAbstractLoader { + + private static final boolean DEBUG = false; + + public CAstAbstractModuleLoader(IClassHierarchy cha, IClassLoader parent) { + super(cha, parent); + } + + public CAstAbstractModuleLoader(IClassHierarchy cha) { + this(cha, null); + } + + /** + * create the appropriate CAst translator for the language and source module + */ + protected abstract TranslatorToCAst getTranslatorToCAst(CAst ast, SourceModule M) throws IOException; + + /** + * should IR be generated for entity? + */ + protected abstract boolean shouldTranslate(CAstEntity entity); + + /** + * create the appropriate IR translator for the language + */ + protected abstract TranslatorToIR initTranslator(); + + protected File getLocalFile(SourceModule M) throws IOException { + if (M instanceof SourceFileModule) { + return ((SourceFileModule) M).getFile(); + } else { + File f = File.createTempFile("module", ".txt"); + f.deleteOnExit(); + TemporaryFile.streamToFile(f.getAbsolutePath(), M.getInputStream()); + return f; + } + } + + /** + * subclasses should override to perform actions after CAst and IR have been + * generated. by default, do nothing + */ + protected void finishTranslation() { + + } + + public void init(final List modules) { + + final CAst ast = new CAstImpl(); + + // convert everything to CAst + final Set> topLevelEntities = new LinkedHashSet>(); + for (Iterator mes = modules.iterator(); mes.hasNext();) { + translateModuleToCAst(mes.next(), ast, topLevelEntities); + } + + // generate IR as needed + final TranslatorToIR xlatorToIR = initTranslator(); + + for (Iterator> tles = topLevelEntities.iterator(); tles.hasNext();) { + Pair p = tles.next(); + if (shouldTranslate(p.fst)) { + xlatorToIR.translate(p.fst, p.snd); + } + } + + if (DEBUG) { + for (Iterator ts = types.keySet().iterator(); ts.hasNext();) { + TypeName tn = (TypeName) ts.next(); + try { + System.err.println(("found type " + tn + " : " + types.get(tn) + " < " + ((IClass) types.get(tn)).getSuperclass())); + } catch (Exception e) { + System.err.println(e); + } + } + } + + finishTranslation(); + } + + /** + * translate moduleEntry to CAst and store result in topLevelEntities + * + * @param ast + * @param topLevelEntities + */ + private void translateModuleEntryToCAst(ModuleEntry moduleEntry, CAst ast, Set> topLevelEntities) { + try { + if (moduleEntry.isModuleFile()) { + // nested module + translateModuleToCAst(moduleEntry.asModule(), ast, topLevelEntities); + } else if (moduleEntry instanceof SourceModule) { + TranslatorToCAst xlatorToCAst = getTranslatorToCAst(ast, (SourceModule) moduleEntry); + + CAstEntity fileEntity = xlatorToCAst.translateToCAst(); + + if (fileEntity != null) { + if (DEBUG) { + CAstPrinter.printTo(fileEntity, new PrintWriter(System.err)); + } + topLevelEntities.add(Pair.make(fileEntity, moduleEntry)); + + } else { + addMessage(moduleEntry, new Warning(Warning.SEVERE) { + @Override + public String getMsg() { + return "parse error"; + } + }); + } + } + } catch (final MalformedURLException e) { + addMessage(moduleEntry, new Warning(Warning.SEVERE) { + @Override + public String getMsg() { + return "Malformed URL issue: " + e.getMessage(); + } + }); + } catch (final IOException e) { + addMessage(moduleEntry, new Warning(Warning.SEVERE) { + @Override + public String getMsg() { + return "I/O issue: " + e.getMessage(); + } + }); + } catch (final RuntimeException e) { + final ByteArrayOutputStream s = new ByteArrayOutputStream(); + PrintStream ps = new PrintStream(s); + e.printStackTrace(ps); + addMessage(moduleEntry, new Warning(Warning.SEVERE) { + @Override + public String getMsg() { + return "Parsing issue: " + new String(s.toByteArray()); + } + }); + } + } + + /** + * translate all relevant entities in the module to CAst, storing the results + * in topLevelEntities + */ + private void translateModuleToCAst(Module module, CAst ast, Set> topLevelEntities) { + for (Iterator mes = module.getEntries(); mes.hasNext();) { + translateModuleEntryToCAst(mes.next(), ast, topLevelEntities); + } + } + +} diff --git a/com.ibm.wala.cast/source/java/com/ibm/wala/cast/tree/impl/CAstRewriterFactory.java b/com.ibm.wala.cast/source/java/com/ibm/wala/cast/tree/impl/CAstRewriterFactory.java index fb1a6889f..688a39864 100644 --- a/com.ibm.wala.cast/source/java/com/ibm/wala/cast/tree/impl/CAstRewriterFactory.java +++ b/com.ibm.wala.cast/source/java/com/ibm/wala/cast/tree/impl/CAstRewriterFactory.java @@ -1,12 +1,12 @@ -package com.ibm.wala.cast.tree.impl; - -import com.ibm.wala.cast.tree.CAst; - -public interface - CAstRewriterFactory, - K extends CAstRewriter.CopyKey> -{ - - public CAstRewriter createCAstRewriter(CAst ast); - -} +package com.ibm.wala.cast.tree.impl; + +import com.ibm.wala.cast.tree.CAst; + +public interface + CAstRewriterFactory, + K extends CAstRewriter.CopyKey> +{ + + public CAstRewriter createCAstRewriter(CAst ast); + +} diff --git a/com.ibm.wala.cast/source/java/com/ibm/wala/cast/tree/impl/CAstSymbolImplBase.java b/com.ibm.wala.cast/source/java/com/ibm/wala/cast/tree/impl/CAstSymbolImplBase.java index 356e90a86..4f157752d 100644 --- a/com.ibm.wala.cast/source/java/com/ibm/wala/cast/tree/impl/CAstSymbolImplBase.java +++ b/com.ibm.wala.cast/source/java/com/ibm/wala/cast/tree/impl/CAstSymbolImplBase.java @@ -1,59 +1,59 @@ -package com.ibm.wala.cast.tree.impl; - -import com.ibm.wala.cast.tree.CAstSymbol; - -public abstract class CAstSymbolImplBase implements CAstSymbol { - private final String _name; - private final boolean _isFinal; - private final boolean _isCaseInsensitive; - private final Object _defaultInitValue; - - public CAstSymbolImplBase(String name) { - this(name, false); - } - - public CAstSymbolImplBase(String name, boolean isFinal) { - this(name, isFinal, false); - } - - public CAstSymbolImplBase(String name, boolean isFinal, boolean isCaseSensitive) { - this(name, isFinal, isCaseSensitive, null); - } - - public CAstSymbolImplBase(String name, Object defaultInitValue) { - this(name, false, defaultInitValue); - } - - public CAstSymbolImplBase(String name, boolean isFinal, Object defaultInitValue) { - this(name, isFinal, false, defaultInitValue); - } - - public CAstSymbolImplBase(String name, boolean isFinal, boolean isCaseSensitive, Object defaultInitValue) { - this._name= name; - this._isFinal= isFinal; - this._isCaseInsensitive= isCaseSensitive; - this._defaultInitValue= defaultInitValue; - } - - public String name() { - return _name; - } - - public boolean isFinal() { - return _isFinal; - } - - public boolean isCaseInsensitive() { - return _isCaseInsensitive; - } - - public Object defaultInitValue() { - return _defaultInitValue; - } - - public abstract boolean isInternalName(); - - public String toString() { - return _name; - } -} +package com.ibm.wala.cast.tree.impl; + +import com.ibm.wala.cast.tree.CAstSymbol; + +public abstract class CAstSymbolImplBase implements CAstSymbol { + private final String _name; + private final boolean _isFinal; + private final boolean _isCaseInsensitive; + private final Object _defaultInitValue; + + public CAstSymbolImplBase(String name) { + this(name, false); + } + + public CAstSymbolImplBase(String name, boolean isFinal) { + this(name, isFinal, false); + } + + public CAstSymbolImplBase(String name, boolean isFinal, boolean isCaseSensitive) { + this(name, isFinal, isCaseSensitive, null); + } + + public CAstSymbolImplBase(String name, Object defaultInitValue) { + this(name, false, defaultInitValue); + } + + public CAstSymbolImplBase(String name, boolean isFinal, Object defaultInitValue) { + this(name, isFinal, false, defaultInitValue); + } + + public CAstSymbolImplBase(String name, boolean isFinal, boolean isCaseSensitive, Object defaultInitValue) { + this._name= name; + this._isFinal= isFinal; + this._isCaseInsensitive= isCaseSensitive; + this._defaultInitValue= defaultInitValue; + } + + public String name() { + return _name; + } + + public boolean isFinal() { + return _isFinal; + } + + public boolean isCaseInsensitive() { + return _isCaseInsensitive; + } + + public Object defaultInitValue() { + return _defaultInitValue; + } + + public abstract boolean isInternalName(); + + public String toString() { + return _name; + } +} diff --git a/com.ibm.wala.core.testdata/src/annotations/AnnotatedClass1.java b/com.ibm.wala.core.testdata/src/annotations/AnnotatedClass1.java index bd3047082..96eedd4f6 100644 --- a/com.ibm.wala.core.testdata/src/annotations/AnnotatedClass1.java +++ b/com.ibm.wala.core.testdata/src/annotations/AnnotatedClass1.java @@ -1,14 +1,14 @@ -package annotations; - -@RuntimeInvisableAnnotation -@RuntimeVisableAnnotation -@DefaultVisableAnnotation -public class AnnotatedClass1 { - - @RuntimeVisableAnnotationForMethod - @RuntimeInvisableAnnotationForMethod - public void m1(){ - - } - -} +package annotations; + +@RuntimeInvisableAnnotation +@RuntimeVisableAnnotation +@DefaultVisableAnnotation +public class AnnotatedClass1 { + + @RuntimeVisableAnnotationForMethod + @RuntimeInvisableAnnotationForMethod + public void m1(){ + + } + +} diff --git a/com.ibm.wala.core.testdata/src/annotations/AnnotatedClass2.java b/com.ibm.wala.core.testdata/src/annotations/AnnotatedClass2.java index ae38bd9fb..5e6207314 100644 --- a/com.ibm.wala.core.testdata/src/annotations/AnnotatedClass2.java +++ b/com.ibm.wala.core.testdata/src/annotations/AnnotatedClass2.java @@ -1,9 +1,9 @@ -package annotations; - -@RuntimeInvisableAnnotation -@RuntimeInvisableAnnotation2 -@RuntimeVisableAnnotation -@RuntimeVisableAnnotation2 -public class AnnotatedClass2 { - -} +package annotations; + +@RuntimeInvisableAnnotation +@RuntimeInvisableAnnotation2 +@RuntimeVisableAnnotation +@RuntimeVisableAnnotation2 +public class AnnotatedClass2 { + +} diff --git a/com.ibm.wala.core.testdata/src/annotations/DefaultVisableAnnotation.java b/com.ibm.wala.core.testdata/src/annotations/DefaultVisableAnnotation.java index d8f1fc2e5..36485361d 100644 --- a/com.ibm.wala.core.testdata/src/annotations/DefaultVisableAnnotation.java +++ b/com.ibm.wala.core.testdata/src/annotations/DefaultVisableAnnotation.java @@ -1,5 +1,5 @@ -package annotations; - -public @interface DefaultVisableAnnotation { - -} +package annotations; + +public @interface DefaultVisableAnnotation { + +} diff --git a/com.ibm.wala.core.testdata/src/annotations/RuntimeInvisableAnnotation.java b/com.ibm.wala.core.testdata/src/annotations/RuntimeInvisableAnnotation.java index e295bd825..b81acaff0 100644 --- a/com.ibm.wala.core.testdata/src/annotations/RuntimeInvisableAnnotation.java +++ b/com.ibm.wala.core.testdata/src/annotations/RuntimeInvisableAnnotation.java @@ -1,9 +1,9 @@ -package annotations; - -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; - -@Retention(RetentionPolicy.CLASS) -public @interface RuntimeInvisableAnnotation { - -} +package annotations; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +@Retention(RetentionPolicy.CLASS) +public @interface RuntimeInvisableAnnotation { + +} diff --git a/com.ibm.wala.core.testdata/src/annotations/RuntimeInvisableAnnotation2.java b/com.ibm.wala.core.testdata/src/annotations/RuntimeInvisableAnnotation2.java index 130421b67..685089fd1 100644 --- a/com.ibm.wala.core.testdata/src/annotations/RuntimeInvisableAnnotation2.java +++ b/com.ibm.wala.core.testdata/src/annotations/RuntimeInvisableAnnotation2.java @@ -1,9 +1,9 @@ -package annotations; - -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; - -@Retention(RetentionPolicy.CLASS) -public @interface RuntimeInvisableAnnotation2 { - -} +package annotations; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +@Retention(RetentionPolicy.CLASS) +public @interface RuntimeInvisableAnnotation2 { + +} diff --git a/com.ibm.wala.core.testdata/src/annotations/RuntimeInvisableAnnotationForMethod.java b/com.ibm.wala.core.testdata/src/annotations/RuntimeInvisableAnnotationForMethod.java index 7bc9f58f2..447aeaf80 100644 --- a/com.ibm.wala.core.testdata/src/annotations/RuntimeInvisableAnnotationForMethod.java +++ b/com.ibm.wala.core.testdata/src/annotations/RuntimeInvisableAnnotationForMethod.java @@ -1,12 +1,12 @@ -package annotations; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -@Retention(RetentionPolicy.CLASS) -@Target(ElementType.METHOD) -public @interface RuntimeInvisableAnnotationForMethod { - -} +package annotations; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Retention(RetentionPolicy.CLASS) +@Target(ElementType.METHOD) +public @interface RuntimeInvisableAnnotationForMethod { + +} diff --git a/com.ibm.wala.core.testdata/src/annotations/RuntimeVisableAnnotation.java b/com.ibm.wala.core.testdata/src/annotations/RuntimeVisableAnnotation.java index f4df08c42..4c2dd4199 100644 --- a/com.ibm.wala.core.testdata/src/annotations/RuntimeVisableAnnotation.java +++ b/com.ibm.wala.core.testdata/src/annotations/RuntimeVisableAnnotation.java @@ -1,9 +1,9 @@ -package annotations; - -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; - -@Retention(RetentionPolicy.RUNTIME) -public @interface RuntimeVisableAnnotation { - -} +package annotations; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +@Retention(RetentionPolicy.RUNTIME) +public @interface RuntimeVisableAnnotation { + +} diff --git a/com.ibm.wala.core.testdata/src/annotations/RuntimeVisableAnnotation2.java b/com.ibm.wala.core.testdata/src/annotations/RuntimeVisableAnnotation2.java index 019db19a3..915623681 100644 --- a/com.ibm.wala.core.testdata/src/annotations/RuntimeVisableAnnotation2.java +++ b/com.ibm.wala.core.testdata/src/annotations/RuntimeVisableAnnotation2.java @@ -1,9 +1,9 @@ -package annotations; - -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; - -@Retention(RetentionPolicy.RUNTIME) -public @interface RuntimeVisableAnnotation2 { - -} +package annotations; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +@Retention(RetentionPolicy.RUNTIME) +public @interface RuntimeVisableAnnotation2 { + +} diff --git a/com.ibm.wala.core.testdata/src/annotations/RuntimeVisableAnnotationForMethod.java b/com.ibm.wala.core.testdata/src/annotations/RuntimeVisableAnnotationForMethod.java index c077295c9..1241c0cb1 100644 --- a/com.ibm.wala.core.testdata/src/annotations/RuntimeVisableAnnotationForMethod.java +++ b/com.ibm.wala.core.testdata/src/annotations/RuntimeVisableAnnotationForMethod.java @@ -1,12 +1,12 @@ -package annotations; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -@Retention(RetentionPolicy.RUNTIME) -@Target(ElementType.METHOD) -public @interface RuntimeVisableAnnotationForMethod { - -} +package annotations; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.METHOD) +public @interface RuntimeVisableAnnotationForMethod { + +} diff --git a/com.ibm.wala.core.testdata/src/cell/Cell.java b/com.ibm.wala.core.testdata/src/cell/Cell.java index 2a82cba07..08fc62c41 100644 --- a/com.ibm.wala.core.testdata/src/cell/Cell.java +++ b/com.ibm.wala.core.testdata/src/cell/Cell.java @@ -1,24 +1,24 @@ -/******************************************************************************* - * Copyright (c) 2007 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 cell; - -public class Cell { - @SuppressWarnings("unused") - private T field; - - public Cell(T t1) { - field = t1; - } - - public void set(T t2) { - this.field = t2; - } -} +/******************************************************************************* + * Copyright (c) 2007 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 cell; + +public class Cell { + @SuppressWarnings("unused") + private T field; + + public Cell(T t1) { + field = t1; + } + + public void set(T t2) { + this.field = t2; + } +} diff --git a/com.ibm.wala.core.testdata/src/classConstant/ClassConstant.java b/com.ibm.wala.core.testdata/src/classConstant/ClassConstant.java index d434626b4..bc5d12c67 100644 --- a/com.ibm.wala.core.testdata/src/classConstant/ClassConstant.java +++ b/com.ibm.wala.core.testdata/src/classConstant/ClassConstant.java @@ -1,10 +1,10 @@ -package classConstant; - -class ClassConstant { - - public static void main(String args[]) { - Class x = ClassConstant.class; - x.hashCode(); - } - -} +package classConstant; + +class ClassConstant { + + public static void main(String args[]) { + Class x = ClassConstant.class; + x.hashCode(); + } + +} diff --git a/com.ibm.wala.core.testdata/src/cornerCases/Abstract1.java b/com.ibm.wala.core.testdata/src/cornerCases/Abstract1.java index b820f8788..a57160650 100644 --- a/com.ibm.wala.core.testdata/src/cornerCases/Abstract1.java +++ b/com.ibm.wala.core.testdata/src/cornerCases/Abstract1.java @@ -1,20 +1,20 @@ -/******************************************************************************* - * Copyright (c) 2007 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 cornerCases; - -/** - * @author sfink - * - */ -public abstract class Abstract1 { - - void foo() {} -} +/******************************************************************************* + * Copyright (c) 2007 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 cornerCases; + +/** + * @author sfink + * + */ +public abstract class Abstract1 { + + void foo() {} +} diff --git a/com.ibm.wala.core.testdata/src/cornerCases/Abstract2.java b/com.ibm.wala.core.testdata/src/cornerCases/Abstract2.java index d274e3d31..7d4582f8b 100644 --- a/com.ibm.wala.core.testdata/src/cornerCases/Abstract2.java +++ b/com.ibm.wala.core.testdata/src/cornerCases/Abstract2.java @@ -1,20 +1,20 @@ -/******************************************************************************* - * Copyright (c) 2007 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 cornerCases; - -/** - * @author sfink - * - */ -public abstract class Abstract2 { - - void foo() {} -} +/******************************************************************************* + * Copyright (c) 2007 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 cornerCases; + +/** + * @author sfink + * + */ +public abstract class Abstract2 { + + void foo() {} +} diff --git a/com.ibm.wala.core.testdata/src/cornerCases/AliasNames.java b/com.ibm.wala.core.testdata/src/cornerCases/AliasNames.java index a8171a547..096612d53 100644 --- a/com.ibm.wala.core.testdata/src/cornerCases/AliasNames.java +++ b/com.ibm.wala.core.testdata/src/cornerCases/AliasNames.java @@ -1,19 +1,19 @@ -/******************************************************************************* - * Copyright (c) 2007 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 cornerCases; - -public class AliasNames { - - public static void foo(String[] a) { - @SuppressWarnings("unused") - String s = a[0].toString(); - } -} +/******************************************************************************* + * Copyright (c) 2007 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 cornerCases; + +public class AliasNames { + + public static void foo(String[] a) { + @SuppressWarnings("unused") + String s = a[0].toString(); + } +} diff --git a/com.ibm.wala.core.testdata/src/cornerCases/Concrete2.java b/com.ibm.wala.core.testdata/src/cornerCases/Concrete2.java index a8d61ed96..687b3fc6e 100644 --- a/com.ibm.wala.core.testdata/src/cornerCases/Concrete2.java +++ b/com.ibm.wala.core.testdata/src/cornerCases/Concrete2.java @@ -1,19 +1,19 @@ -/******************************************************************************* - * Copyright (c) 2007 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 cornerCases; - -/** - * @author sfink - * - */ -public class Concrete2 extends Abstract2 { - -} +/******************************************************************************* + * Copyright (c) 2007 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 cornerCases; + +/** + * @author sfink + * + */ +public class Concrete2 extends Abstract2 { + +} diff --git a/com.ibm.wala.core.testdata/src/cornerCases/Locals.java b/com.ibm.wala.core.testdata/src/cornerCases/Locals.java index b0cf556d9..6098d5d6a 100644 --- a/com.ibm.wala.core.testdata/src/cornerCases/Locals.java +++ b/com.ibm.wala.core.testdata/src/cornerCases/Locals.java @@ -1,25 +1,25 @@ -/******************************************************************************* - * Copyright (c) 2007 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 cornerCases; - -/** - * @author sfink - * - * Simple input test for local variable table - */ -public class Locals { - - public static void foo(String[] a) { - System.out.println(a); - Object b = a; - System.out.println(b); - } -} +/******************************************************************************* + * Copyright (c) 2007 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 cornerCases; + +/** + * @author sfink + * + * Simple input test for local variable table + */ +public class Locals { + + public static void foo(String[] a) { + System.out.println(a); + Object b = a; + System.out.println(b); + } +} diff --git a/com.ibm.wala.core.testdata/src/cornerCases/Main.java b/com.ibm.wala.core.testdata/src/cornerCases/Main.java index 6b61b9be6..84fc515b4 100644 --- a/com.ibm.wala.core.testdata/src/cornerCases/Main.java +++ b/com.ibm.wala.core.testdata/src/cornerCases/Main.java @@ -1,53 +1,53 @@ -/******************************************************************************* - * Copyright (c) 2002 - 2006 IBM Corporation. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * IBM Corporation - initial API and implementation - *******************************************************************************/ - -package cornerCases; - -import sun.java2d.FontSupport; - -/** - * @author sfink - * - * TODO To change the template for this generated type comment go to - * Window - Preferences - Java - Code Style - Code Templates - */ -public class Main { - - public static void main(String[] args) { - testCastToString(); - } - - /** - * Test bug 38496: propagation of a string constant to a checkcast - */ - private static void testCastToString() { - Object o = "a constant string"; - String s = (String)o; - s.toString(); - } - - public static class YuckyField { - FontSupport f; - } - - /** - * Bug 38540: type inference crashed on this method when class - * FontSupport was not found - */ - public static Object foo() { - getFontSupport(); - return new YuckyField().f; - } - - public static FontSupport getFontSupport() { - return null; - } -} +/******************************************************************************* + * 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 cornerCases; + +import sun.java2d.FontSupport; + +/** + * @author sfink + * + * TODO To change the template for this generated type comment go to + * Window - Preferences - Java - Code Style - Code Templates + */ +public class Main { + + public static void main(String[] args) { + testCastToString(); + } + + /** + * Test bug 38496: propagation of a string constant to a checkcast + */ + private static void testCastToString() { + Object o = "a constant string"; + String s = (String)o; + s.toString(); + } + + public static class YuckyField { + FontSupport f; + } + + /** + * Bug 38540: type inference crashed on this method when class + * FontSupport was not found + */ + public static Object foo() { + getFontSupport(); + return new YuckyField().f; + } + + public static FontSupport getFontSupport() { + return null; + } +} diff --git a/com.ibm.wala.core.testdata/src/cornerCases/TryFinally.java b/com.ibm.wala.core.testdata/src/cornerCases/TryFinally.java index 3aeeb6d79..59b11b436 100644 --- a/com.ibm.wala.core.testdata/src/cornerCases/TryFinally.java +++ b/com.ibm.wala.core.testdata/src/cornerCases/TryFinally.java @@ -1,33 +1,33 @@ -/******************************************************************************* - * Copyright (c) 2009 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 cornerCases; - -import java.io.BufferedInputStream; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.InputStream; - -public class TryFinally { - - public void test1(InputStream i1, InputStream i2) throws IOException { - BufferedInputStream in = new BufferedInputStream(i1); - try { - FileOutputStream zipOut = new FileOutputStream("someFile.txt"); - try { - zipOut.write(0); - } finally { - zipOut.close(); - } - } finally { - in.close(); - } - } -} +/******************************************************************************* + * Copyright (c) 2009 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 cornerCases; + +import java.io.BufferedInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; + +public class TryFinally { + + public void test1(InputStream i1, InputStream i2) throws IOException { + BufferedInputStream in = new BufferedInputStream(i1); + try { + FileOutputStream zipOut = new FileOutputStream("someFile.txt"); + try { + zipOut.write(0); + } finally { + zipOut.close(); + } + } finally { + in.close(); + } + } +} diff --git a/com.ibm.wala.core.testdata/src/cornerCases/YuckyInterface.java b/com.ibm.wala.core.testdata/src/cornerCases/YuckyInterface.java index db45504e1..ce2abf46f 100644 --- a/com.ibm.wala.core.testdata/src/cornerCases/YuckyInterface.java +++ b/com.ibm.wala.core.testdata/src/cornerCases/YuckyInterface.java @@ -1,24 +1,24 @@ -/******************************************************************************* - * Copyright (c) 2007 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 cornerCases; - -import sun.java2d.FontSupport; - -/** - * @author sfink - * - * When analyzed with J2EEClassHierarchy exclusions, the superinterface - * FontSupport should not be found because we exclude sun.java2d.* - */ -public interface YuckyInterface extends FontSupport { - - -} +/******************************************************************************* + * Copyright (c) 2007 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 cornerCases; + +import sun.java2d.FontSupport; + +/** + * @author sfink + * + * When analyzed with J2EEClassHierarchy exclusions, the superinterface + * FontSupport should not be found because we exclude sun.java2d.* + */ +public interface YuckyInterface extends FontSupport { + + +} diff --git a/com.ibm.wala.core.testdata/src/demandpa/A.java b/com.ibm.wala.core.testdata/src/demandpa/A.java index 0bd122308..417e1030b 100644 --- a/com.ibm.wala.core.testdata/src/demandpa/A.java +++ b/com.ibm.wala.core.testdata/src/demandpa/A.java @@ -1,55 +1,55 @@ -/******************************************************************************* - * 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. - * - * This file is a derivative of code released by the University of - * California under the terms listed below. - * - * Refinement Analysis Tools is Copyright (c) 2007 The Regents of the - * University of California (Regents). Provided that this notice and - * the following two paragraphs are included in any distribution of - * Refinement Analysis Tools or its derivative work, Regents agrees - * not to assert any of Regents' copyright rights in Refinement - * Analysis Tools against recipient for recipient's reproduction, - * preparation of derivative works, public display, public - * performance, distribution or sublicensing of Refinement Analysis - * Tools and derivative works, in source code and object code form. - * This agreement not to assert does not confer, by implication, - * estoppel, or otherwise any license or rights in any intellectual - * property of Regents, including, but not limited to, any patents - * of Regents or Regents' employees. - * - * IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, - * INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, - * INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE - * AND ITS DOCUMENTATION, EVEN IF REGENTS HAS BEEN ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE AND FURTHER DISCLAIMS ANY STATUTORY - * WARRANTY OF NON-INFRINGEMENT. THE SOFTWARE AND ACCOMPANYING - * DOCUMENTATION, IF ANY, PROVIDED HEREUNDER IS PROVIDED "AS - * IS". REGENTS HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, - * UPDATES, ENHANCEMENTS, OR MODIFICATIONS. - */ -package demandpa; - -class A { - - Object f; - - Object foo() { - return new Integer(3); - } - - public Object getF() { - return f; - } - - public void setF(Object f) { - this.f = f; - } -} +/******************************************************************************* + * 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. + * + * This file is a derivative of code released by the University of + * California under the terms listed below. + * + * Refinement Analysis Tools is Copyright (c) 2007 The Regents of the + * University of California (Regents). Provided that this notice and + * the following two paragraphs are included in any distribution of + * Refinement Analysis Tools or its derivative work, Regents agrees + * not to assert any of Regents' copyright rights in Refinement + * Analysis Tools against recipient for recipient's reproduction, + * preparation of derivative works, public display, public + * performance, distribution or sublicensing of Refinement Analysis + * Tools and derivative works, in source code and object code form. + * This agreement not to assert does not confer, by implication, + * estoppel, or otherwise any license or rights in any intellectual + * property of Regents, including, but not limited to, any patents + * of Regents or Regents' employees. + * + * IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, + * INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, + * INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE + * AND ITS DOCUMENTATION, EVEN IF REGENTS HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE AND FURTHER DISCLAIMS ANY STATUTORY + * WARRANTY OF NON-INFRINGEMENT. THE SOFTWARE AND ACCOMPANYING + * DOCUMENTATION, IF ANY, PROVIDED HEREUNDER IS PROVIDED "AS + * IS". REGENTS HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, + * UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + */ +package demandpa; + +class A { + + Object f; + + Object foo() { + return new Integer(3); + } + + public Object getF() { + return f; + } + + public void setF(Object f) { + this.f = f; + } +} diff --git a/com.ibm.wala.core.testdata/src/demandpa/ArraySet.java b/com.ibm.wala.core.testdata/src/demandpa/ArraySet.java index 1bff0b1e5..889fdab53 100644 --- a/com.ibm.wala.core.testdata/src/demandpa/ArraySet.java +++ b/com.ibm.wala.core.testdata/src/demandpa/ArraySet.java @@ -1,66 +1,66 @@ -/******************************************************************************* - * 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. - * - * This file is a derivative of code released by the University of - * California under the terms listed below. - * - * Refinement Analysis Tools is Copyright (c) 2007 The Regents of the - * University of California (Regents). Provided that this notice and - * the following two paragraphs are included in any distribution of - * Refinement Analysis Tools or its derivative work, Regents agrees - * not to assert any of Regents' copyright rights in Refinement - * Analysis Tools against recipient for recipient's reproduction, - * preparation of derivative works, public display, public - * performance, distribution or sublicensing of Refinement Analysis - * Tools and derivative works, in source code and object code form. - * This agreement not to assert does not confer, by implication, - * estoppel, or otherwise any license or rights in any intellectual - * property of Regents, including, but not limited to, any patents - * of Regents or Regents' employees. - * - * IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, - * INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, - * INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE - * AND ITS DOCUMENTATION, EVEN IF REGENTS HAS BEEN ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE AND FURTHER DISCLAIMS ANY STATUTORY - * WARRANTY OF NON-INFRINGEMENT. THE SOFTWARE AND ACCOMPANYING - * DOCUMENTATION, IF ANY, PROVIDED HEREUNDER IS PROVIDED "AS - * IS". REGENTS HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, - * UPDATES, ENHANCEMENTS, OR MODIFICATIONS. - */ -package demandpa; - -class ArraySet { - - static void foo() { - } - - Object[] elems = new Object[10]; - - void add(Object o) { - elems[0] = o; - } - - Object get() { - return elems[0]; - } - - Iter iterator() { - return new ArraySetIter(); - } - - class ArraySetIter implements Iter { - public Object next() { - return elems[0]; - } - - } - -} +/******************************************************************************* + * 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. + * + * This file is a derivative of code released by the University of + * California under the terms listed below. + * + * Refinement Analysis Tools is Copyright (c) 2007 The Regents of the + * University of California (Regents). Provided that this notice and + * the following two paragraphs are included in any distribution of + * Refinement Analysis Tools or its derivative work, Regents agrees + * not to assert any of Regents' copyright rights in Refinement + * Analysis Tools against recipient for recipient's reproduction, + * preparation of derivative works, public display, public + * performance, distribution or sublicensing of Refinement Analysis + * Tools and derivative works, in source code and object code form. + * This agreement not to assert does not confer, by implication, + * estoppel, or otherwise any license or rights in any intellectual + * property of Regents, including, but not limited to, any patents + * of Regents or Regents' employees. + * + * IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, + * INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, + * INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE + * AND ITS DOCUMENTATION, EVEN IF REGENTS HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE AND FURTHER DISCLAIMS ANY STATUTORY + * WARRANTY OF NON-INFRINGEMENT. THE SOFTWARE AND ACCOMPANYING + * DOCUMENTATION, IF ANY, PROVIDED HEREUNDER IS PROVIDED "AS + * IS". REGENTS HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, + * UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + */ +package demandpa; + +class ArraySet { + + static void foo() { + } + + Object[] elems = new Object[10]; + + void add(Object o) { + elems[0] = o; + } + + Object get() { + return elems[0]; + } + + Iter iterator() { + return new ArraySetIter(); + } + + class ArraySetIter implements Iter { + public Object next() { + return elems[0]; + } + + } + +} diff --git a/com.ibm.wala.core.testdata/src/demandpa/B.java b/com.ibm.wala.core.testdata/src/demandpa/B.java index ee23302d0..2e0fe8e8a 100644 --- a/com.ibm.wala.core.testdata/src/demandpa/B.java +++ b/com.ibm.wala.core.testdata/src/demandpa/B.java @@ -1,45 +1,45 @@ -/******************************************************************************* - * 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. - * - * This file is a derivative of code released by the University of - * California under the terms listed below. - * - * Refinement Analysis Tools is Copyright (c) 2007 The Regents of the - * University of California (Regents). Provided that this notice and - * the following two paragraphs are included in any distribution of - * Refinement Analysis Tools or its derivative work, Regents agrees - * not to assert any of Regents' copyright rights in Refinement - * Analysis Tools against recipient for recipient's reproduction, - * preparation of derivative works, public display, public - * performance, distribution or sublicensing of Refinement Analysis - * Tools and derivative works, in source code and object code form. - * This agreement not to assert does not confer, by implication, - * estoppel, or otherwise any license or rights in any intellectual - * property of Regents, including, but not limited to, any patents - * of Regents or Regents' employees. - * - * IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, - * INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, - * INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE - * AND ITS DOCUMENTATION, EVEN IF REGENTS HAS BEEN ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE AND FURTHER DISCLAIMS ANY STATUTORY - * WARRANTY OF NON-INFRINGEMENT. THE SOFTWARE AND ACCOMPANYING - * DOCUMENTATION, IF ANY, PROVIDED HEREUNDER IS PROVIDED "AS - * IS". REGENTS HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, - * UPDATES, ENHANCEMENTS, OR MODIFICATIONS. - */ -package demandpa; - -class B extends A { - @Override - Object foo() { - return new Float(4); - } -} +/******************************************************************************* + * 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. + * + * This file is a derivative of code released by the University of + * California under the terms listed below. + * + * Refinement Analysis Tools is Copyright (c) 2007 The Regents of the + * University of California (Regents). Provided that this notice and + * the following two paragraphs are included in any distribution of + * Refinement Analysis Tools or its derivative work, Regents agrees + * not to assert any of Regents' copyright rights in Refinement + * Analysis Tools against recipient for recipient's reproduction, + * preparation of derivative works, public display, public + * performance, distribution or sublicensing of Refinement Analysis + * Tools and derivative works, in source code and object code form. + * This agreement not to assert does not confer, by implication, + * estoppel, or otherwise any license or rights in any intellectual + * property of Regents, including, but not limited to, any patents + * of Regents or Regents' employees. + * + * IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, + * INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, + * INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE + * AND ITS DOCUMENTATION, EVEN IF REGENTS HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE AND FURTHER DISCLAIMS ANY STATUTORY + * WARRANTY OF NON-INFRINGEMENT. THE SOFTWARE AND ACCOMPANYING + * DOCUMENTATION, IF ANY, PROVIDED HEREUNDER IS PROVIDED "AS + * IS". REGENTS HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, + * UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + */ +package demandpa; + +class B extends A { + @Override + Object foo() { + return new Float(4); + } +} diff --git a/com.ibm.wala.core.testdata/src/demandpa/DemandPATestUtil.java b/com.ibm.wala.core.testdata/src/demandpa/DemandPATestUtil.java index 88d5cf70c..93b3a8438 100644 --- a/com.ibm.wala.core.testdata/src/demandpa/DemandPATestUtil.java +++ b/com.ibm.wala.core.testdata/src/demandpa/DemandPATestUtil.java @@ -1,55 +1,55 @@ -/******************************************************************************* - * 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. - * - * This file is a derivative of code released by the University of - * California under the terms listed below. - * - * Refinement Analysis Tools is Copyright (c) 2007 The Regents of the - * University of California (Regents). Provided that this notice and - * the following two paragraphs are included in any distribution of - * Refinement Analysis Tools or its derivative work, Regents agrees - * not to assert any of Regents' copyright rights in Refinement - * Analysis Tools against recipient for recipient's reproduction, - * preparation of derivative works, public display, public - * performance, distribution or sublicensing of Refinement Analysis - * Tools and derivative works, in source code and object code form. - * This agreement not to assert does not confer, by implication, - * estoppel, or otherwise any license or rights in any intellectual - * property of Regents, including, but not limited to, any patents - * of Regents or Regents' employees. - * - * IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, - * INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, - * INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE - * AND ITS DOCUMENTATION, EVEN IF REGENTS HAS BEEN ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE AND FURTHER DISCLAIMS ANY STATUTORY - * WARRANTY OF NON-INFRINGEMENT. THE SOFTWARE AND ACCOMPANYING - * DOCUMENTATION, IF ANY, PROVIDED HEREUNDER IS PROVIDED "AS - * IS". REGENTS HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, - * UPDATES, ENHANCEMENTS, OR MODIFICATIONS. - */ -package demandpa; - -/** - * utility functions for identifying interesting variables in tests and making - * otherwise unused variables used - * - * @author manu - * - */ -public class DemandPATestUtil { - - public static void makeVarUsed(Object o) { - } - - public static void testThisVar(Object o) { - } - -} +/******************************************************************************* + * 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. + * + * This file is a derivative of code released by the University of + * California under the terms listed below. + * + * Refinement Analysis Tools is Copyright (c) 2007 The Regents of the + * University of California (Regents). Provided that this notice and + * the following two paragraphs are included in any distribution of + * Refinement Analysis Tools or its derivative work, Regents agrees + * not to assert any of Regents' copyright rights in Refinement + * Analysis Tools against recipient for recipient's reproduction, + * preparation of derivative works, public display, public + * performance, distribution or sublicensing of Refinement Analysis + * Tools and derivative works, in source code and object code form. + * This agreement not to assert does not confer, by implication, + * estoppel, or otherwise any license or rights in any intellectual + * property of Regents, including, but not limited to, any patents + * of Regents or Regents' employees. + * + * IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, + * INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, + * INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE + * AND ITS DOCUMENTATION, EVEN IF REGENTS HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE AND FURTHER DISCLAIMS ANY STATUTORY + * WARRANTY OF NON-INFRINGEMENT. THE SOFTWARE AND ACCOMPANYING + * DOCUMENTATION, IF ANY, PROVIDED HEREUNDER IS PROVIDED "AS + * IS". REGENTS HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, + * UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + */ +package demandpa; + +/** + * utility functions for identifying interesting variables in tests and making + * otherwise unused variables used + * + * @author manu + * + */ +public class DemandPATestUtil { + + public static void makeVarUsed(Object o) { + } + + public static void testThisVar(Object o) { + } + +} diff --git a/com.ibm.wala.core.testdata/src/demandpa/Iter.java b/com.ibm.wala.core.testdata/src/demandpa/Iter.java index ba6efbe62..4d1e53edd 100644 --- a/com.ibm.wala.core.testdata/src/demandpa/Iter.java +++ b/com.ibm.wala.core.testdata/src/demandpa/Iter.java @@ -1,44 +1,44 @@ -/******************************************************************************* - * 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. - * - * This file is a derivative of code released by the University of - * California under the terms listed below. - * - * Refinement Analysis Tools is Copyright (c) 2007 The Regents of the - * University of California (Regents). Provided that this notice and - * the following two paragraphs are included in any distribution of - * Refinement Analysis Tools or its derivative work, Regents agrees - * not to assert any of Regents' copyright rights in Refinement - * Analysis Tools against recipient for recipient's reproduction, - * preparation of derivative works, public display, public - * performance, distribution or sublicensing of Refinement Analysis - * Tools and derivative works, in source code and object code form. - * This agreement not to assert does not confer, by implication, - * estoppel, or otherwise any license or rights in any intellectual - * property of Regents, including, but not limited to, any patents - * of Regents or Regents' employees. - * - * IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, - * INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, - * INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE - * AND ITS DOCUMENTATION, EVEN IF REGENTS HAS BEEN ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE AND FURTHER DISCLAIMS ANY STATUTORY - * WARRANTY OF NON-INFRINGEMENT. THE SOFTWARE AND ACCOMPANYING - * DOCUMENTATION, IF ANY, PROVIDED HEREUNDER IS PROVIDED "AS - * IS". REGENTS HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, - * UPDATES, ENHANCEMENTS, OR MODIFICATIONS. - */ -package demandpa; - -interface Iter { - - Object next(); - -} +/******************************************************************************* + * 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. + * + * This file is a derivative of code released by the University of + * California under the terms listed below. + * + * Refinement Analysis Tools is Copyright (c) 2007 The Regents of the + * University of California (Regents). Provided that this notice and + * the following two paragraphs are included in any distribution of + * Refinement Analysis Tools or its derivative work, Regents agrees + * not to assert any of Regents' copyright rights in Refinement + * Analysis Tools against recipient for recipient's reproduction, + * preparation of derivative works, public display, public + * performance, distribution or sublicensing of Refinement Analysis + * Tools and derivative works, in source code and object code form. + * This agreement not to assert does not confer, by implication, + * estoppel, or otherwise any license or rights in any intellectual + * property of Regents, including, but not limited to, any patents + * of Regents or Regents' employees. + * + * IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, + * INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, + * INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE + * AND ITS DOCUMENTATION, EVEN IF REGENTS HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE AND FURTHER DISCLAIMS ANY STATUTORY + * WARRANTY OF NON-INFRINGEMENT. THE SOFTWARE AND ACCOMPANYING + * DOCUMENTATION, IF ANY, PROVIDED HEREUNDER IS PROVIDED "AS + * IS". REGENTS HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, + * UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + */ +package demandpa; + +interface Iter { + + Object next(); + +} diff --git a/com.ibm.wala.core.testdata/src/demandpa/TestArrayList.java b/com.ibm.wala.core.testdata/src/demandpa/TestArrayList.java index 7cb2a9b7e..c79f4d47a 100644 --- a/com.ibm.wala.core.testdata/src/demandpa/TestArrayList.java +++ b/com.ibm.wala.core.testdata/src/demandpa/TestArrayList.java @@ -1,59 +1,59 @@ -/******************************************************************************* - * 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. - * - * This file is a derivative of code released by the University of - * California under the terms listed below. - * - * Refinement Analysis Tools is Copyright (c) 2007 The Regents of the - * University of California (Regents). Provided that this notice and - * the following two paragraphs are included in any distribution of - * Refinement Analysis Tools or its derivative work, Regents agrees - * not to assert any of Regents' copyright rights in Refinement - * Analysis Tools against recipient for recipient's reproduction, - * preparation of derivative works, public display, public - * performance, distribution or sublicensing of Refinement Analysis - * Tools and derivative works, in source code and object code form. - * This agreement not to assert does not confer, by implication, - * estoppel, or otherwise any license or rights in any intellectual - * property of Regents, including, but not limited to, any patents - * of Regents or Regents' employees. - * - * IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, - * INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, - * INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE - * AND ITS DOCUMENTATION, EVEN IF REGENTS HAS BEEN ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE AND FURTHER DISCLAIMS ANY STATUTORY - * WARRANTY OF NON-INFRINGEMENT. THE SOFTWARE AND ACCOMPANYING - * DOCUMENTATION, IF ANY, PROVIDED HEREUNDER IS PROVIDED "AS - * IS". REGENTS HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, - * UPDATES, ENHANCEMENTS, OR MODIFICATIONS. - */ -package demandpa; - -import java.util.ArrayList; - -public class TestArrayList { - - /** - * @param args - */ - @SuppressWarnings("unchecked") - public static void main(String[] args) { - ArrayList l1 = new ArrayList(); - ArrayList l2 = new ArrayList(); - l1.add(new Object()); - l2.add(new Object()); - Object o1 = l1.get(0); - Object o2 = l2.get(0); - DemandPATestUtil.makeVarUsed(o1); - DemandPATestUtil.testThisVar(o2); - } - -} +/******************************************************************************* + * 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. + * + * This file is a derivative of code released by the University of + * California under the terms listed below. + * + * Refinement Analysis Tools is Copyright (c) 2007 The Regents of the + * University of California (Regents). Provided that this notice and + * the following two paragraphs are included in any distribution of + * Refinement Analysis Tools or its derivative work, Regents agrees + * not to assert any of Regents' copyright rights in Refinement + * Analysis Tools against recipient for recipient's reproduction, + * preparation of derivative works, public display, public + * performance, distribution or sublicensing of Refinement Analysis + * Tools and derivative works, in source code and object code form. + * This agreement not to assert does not confer, by implication, + * estoppel, or otherwise any license or rights in any intellectual + * property of Regents, including, but not limited to, any patents + * of Regents or Regents' employees. + * + * IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, + * INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, + * INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE + * AND ITS DOCUMENTATION, EVEN IF REGENTS HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE AND FURTHER DISCLAIMS ANY STATUTORY + * WARRANTY OF NON-INFRINGEMENT. THE SOFTWARE AND ACCOMPANYING + * DOCUMENTATION, IF ANY, PROVIDED HEREUNDER IS PROVIDED "AS + * IS". REGENTS HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, + * UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + */ +package demandpa; + +import java.util.ArrayList; + +public class TestArrayList { + + /** + * @param args + */ + @SuppressWarnings("unchecked") + public static void main(String[] args) { + ArrayList l1 = new ArrayList(); + ArrayList l2 = new ArrayList(); + l1.add(new Object()); + l2.add(new Object()); + Object o1 = l1.get(0); + Object o2 = l2.get(0); + DemandPATestUtil.makeVarUsed(o1); + DemandPATestUtil.testThisVar(o2); + } + +} diff --git a/com.ibm.wala.core.testdata/src/demandpa/TestArraySet.java b/com.ibm.wala.core.testdata/src/demandpa/TestArraySet.java index 88224c183..a13266f93 100644 --- a/com.ibm.wala.core.testdata/src/demandpa/TestArraySet.java +++ b/com.ibm.wala.core.testdata/src/demandpa/TestArraySet.java @@ -1,54 +1,54 @@ -/******************************************************************************* - * 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. - * - * This file is a derivative of code released by the University of - * California under the terms listed below. - * - * Refinement Analysis Tools is Copyright (c) 2007 The Regents of the - * University of California (Regents). Provided that this notice and - * the following two paragraphs are included in any distribution of - * Refinement Analysis Tools or its derivative work, Regents agrees - * not to assert any of Regents' copyright rights in Refinement - * Analysis Tools against recipient for recipient's reproduction, - * preparation of derivative works, public display, public - * performance, distribution or sublicensing of Refinement Analysis - * Tools and derivative works, in source code and object code form. - * This agreement not to assert does not confer, by implication, - * estoppel, or otherwise any license or rights in any intellectual - * property of Regents, including, but not limited to, any patents - * of Regents or Regents' employees. - * - * IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, - * INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, - * INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE - * AND ITS DOCUMENTATION, EVEN IF REGENTS HAS BEEN ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE AND FURTHER DISCLAIMS ANY STATUTORY - * WARRANTY OF NON-INFRINGEMENT. THE SOFTWARE AND ACCOMPANYING - * DOCUMENTATION, IF ANY, PROVIDED HEREUNDER IS PROVIDED "AS - * IS". REGENTS HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, - * UPDATES, ENHANCEMENTS, OR MODIFICATIONS. - */ -package demandpa; - -public class TestArraySet { - - public static void main(String[] args) { - ArraySet s1 = new ArraySet(); - ArraySet s2 = new ArraySet(); - s1.add(new A()); - s2.add(new B()); - A a = (A) s1.get(); - B b = (B) s2.get(); - DemandPATestUtil.makeVarUsed(b); - DemandPATestUtil.testThisVar(a); - - } - -} +/******************************************************************************* + * 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. + * + * This file is a derivative of code released by the University of + * California under the terms listed below. + * + * Refinement Analysis Tools is Copyright (c) 2007 The Regents of the + * University of California (Regents). Provided that this notice and + * the following two paragraphs are included in any distribution of + * Refinement Analysis Tools or its derivative work, Regents agrees + * not to assert any of Regents' copyright rights in Refinement + * Analysis Tools against recipient for recipient's reproduction, + * preparation of derivative works, public display, public + * performance, distribution or sublicensing of Refinement Analysis + * Tools and derivative works, in source code and object code form. + * This agreement not to assert does not confer, by implication, + * estoppel, or otherwise any license or rights in any intellectual + * property of Regents, including, but not limited to, any patents + * of Regents or Regents' employees. + * + * IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, + * INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, + * INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE + * AND ITS DOCUMENTATION, EVEN IF REGENTS HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE AND FURTHER DISCLAIMS ANY STATUTORY + * WARRANTY OF NON-INFRINGEMENT. THE SOFTWARE AND ACCOMPANYING + * DOCUMENTATION, IF ANY, PROVIDED HEREUNDER IS PROVIDED "AS + * IS". REGENTS HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, + * UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + */ +package demandpa; + +public class TestArraySet { + + public static void main(String[] args) { + ArraySet s1 = new ArraySet(); + ArraySet s2 = new ArraySet(); + s1.add(new A()); + s2.add(new B()); + A a = (A) s1.get(); + B b = (B) s2.get(); + DemandPATestUtil.makeVarUsed(b); + DemandPATestUtil.testThisVar(a); + + } + +} diff --git a/com.ibm.wala.core.testdata/src/demandpa/TestArraySetIter.java b/com.ibm.wala.core.testdata/src/demandpa/TestArraySetIter.java index 1f373062b..e095d7593 100644 --- a/com.ibm.wala.core.testdata/src/demandpa/TestArraySetIter.java +++ b/com.ibm.wala.core.testdata/src/demandpa/TestArraySetIter.java @@ -1,52 +1,52 @@ -/******************************************************************************* - * 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. - * - * This file is a derivative of code released by the University of - * California under the terms listed below. - * - * Refinement Analysis Tools is Copyright (c) 2007 The Regents of the - * University of California (Regents). Provided that this notice and - * the following two paragraphs are included in any distribution of - * Refinement Analysis Tools or its derivative work, Regents agrees - * not to assert any of Regents' copyright rights in Refinement - * Analysis Tools against recipient for recipient's reproduction, - * preparation of derivative works, public display, public - * performance, distribution or sublicensing of Refinement Analysis - * Tools and derivative works, in source code and object code form. - * This agreement not to assert does not confer, by implication, - * estoppel, or otherwise any license or rights in any intellectual - * property of Regents, including, but not limited to, any patents - * of Regents or Regents' employees. - * - * IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, - * INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, - * INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE - * AND ITS DOCUMENTATION, EVEN IF REGENTS HAS BEEN ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE AND FURTHER DISCLAIMS ANY STATUTORY - * WARRANTY OF NON-INFRINGEMENT. THE SOFTWARE AND ACCOMPANYING - * DOCUMENTATION, IF ANY, PROVIDED HEREUNDER IS PROVIDED "AS - * IS". REGENTS HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, - * UPDATES, ENHANCEMENTS, OR MODIFICATIONS. - */ -package demandpa; - -class TestArraySetIter { - - public static void main(String[] args) { - ArraySet s1 = new ArraySet(); - ArraySet s2 = new ArraySet(); - s1.add(new A()); - s2.add(new B()); - A a = (A) s1.iterator().next(); - B b = (B) s2.iterator().next(); - DemandPATestUtil.makeVarUsed(b); - DemandPATestUtil.testThisVar(a); - } -} +/******************************************************************************* + * 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. + * + * This file is a derivative of code released by the University of + * California under the terms listed below. + * + * Refinement Analysis Tools is Copyright (c) 2007 The Regents of the + * University of California (Regents). Provided that this notice and + * the following two paragraphs are included in any distribution of + * Refinement Analysis Tools or its derivative work, Regents agrees + * not to assert any of Regents' copyright rights in Refinement + * Analysis Tools against recipient for recipient's reproduction, + * preparation of derivative works, public display, public + * performance, distribution or sublicensing of Refinement Analysis + * Tools and derivative works, in source code and object code form. + * This agreement not to assert does not confer, by implication, + * estoppel, or otherwise any license or rights in any intellectual + * property of Regents, including, but not limited to, any patents + * of Regents or Regents' employees. + * + * IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, + * INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, + * INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE + * AND ITS DOCUMENTATION, EVEN IF REGENTS HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE AND FURTHER DISCLAIMS ANY STATUTORY + * WARRANTY OF NON-INFRINGEMENT. THE SOFTWARE AND ACCOMPANYING + * DOCUMENTATION, IF ANY, PROVIDED HEREUNDER IS PROVIDED "AS + * IS". REGENTS HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, + * UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + */ +package demandpa; + +class TestArraySetIter { + + public static void main(String[] args) { + ArraySet s1 = new ArraySet(); + ArraySet s2 = new ArraySet(); + s1.add(new A()); + s2.add(new B()); + A a = (A) s1.iterator().next(); + B b = (B) s2.iterator().next(); + DemandPATestUtil.makeVarUsed(b); + DemandPATestUtil.testThisVar(a); + } +} diff --git a/com.ibm.wala.core.testdata/src/demandpa/TestArrays.java b/com.ibm.wala.core.testdata/src/demandpa/TestArrays.java index 816396564..49e10a47a 100644 --- a/com.ibm.wala.core.testdata/src/demandpa/TestArrays.java +++ b/com.ibm.wala.core.testdata/src/demandpa/TestArrays.java @@ -1,52 +1,52 @@ -/******************************************************************************* - * 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. - * - * This file is a derivative of code released by the University of - * California under the terms listed below. - * - * Refinement Analysis Tools is Copyright (c) 2007 The Regents of the - * University of California (Regents). Provided that this notice and - * the following two paragraphs are included in any distribution of - * Refinement Analysis Tools or its derivative work, Regents agrees - * not to assert any of Regents' copyright rights in Refinement - * Analysis Tools against recipient for recipient's reproduction, - * preparation of derivative works, public display, public - * performance, distribution or sublicensing of Refinement Analysis - * Tools and derivative works, in source code and object code form. - * This agreement not to assert does not confer, by implication, - * estoppel, or otherwise any license or rights in any intellectual - * property of Regents, including, but not limited to, any patents - * of Regents or Regents' employees. - * - * IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, - * INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, - * INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE - * AND ITS DOCUMENTATION, EVEN IF REGENTS HAS BEEN ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE AND FURTHER DISCLAIMS ANY STATUTORY - * WARRANTY OF NON-INFRINGEMENT. THE SOFTWARE AND ACCOMPANYING - * DOCUMENTATION, IF ANY, PROVIDED HEREUNDER IS PROVIDED "AS - * IS". REGENTS HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, - * UPDATES, ENHANCEMENTS, OR MODIFICATIONS. - */ -package demandpa; - -public class TestArrays { - - /** - * @param args - */ - public static void main(String[] args) { - Object[] arr = new Object[10]; - arr[0] = new Object(); - arr[1] = new Object(); - DemandPATestUtil.testThisVar(arr[1]); - } - -} +/******************************************************************************* + * 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. + * + * This file is a derivative of code released by the University of + * California under the terms listed below. + * + * Refinement Analysis Tools is Copyright (c) 2007 The Regents of the + * University of California (Regents). Provided that this notice and + * the following two paragraphs are included in any distribution of + * Refinement Analysis Tools or its derivative work, Regents agrees + * not to assert any of Regents' copyright rights in Refinement + * Analysis Tools against recipient for recipient's reproduction, + * preparation of derivative works, public display, public + * performance, distribution or sublicensing of Refinement Analysis + * Tools and derivative works, in source code and object code form. + * This agreement not to assert does not confer, by implication, + * estoppel, or otherwise any license or rights in any intellectual + * property of Regents, including, but not limited to, any patents + * of Regents or Regents' employees. + * + * IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, + * INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, + * INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE + * AND ITS DOCUMENTATION, EVEN IF REGENTS HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE AND FURTHER DISCLAIMS ANY STATUTORY + * WARRANTY OF NON-INFRINGEMENT. THE SOFTWARE AND ACCOMPANYING + * DOCUMENTATION, IF ANY, PROVIDED HEREUNDER IS PROVIDED "AS + * IS". REGENTS HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, + * UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + */ +package demandpa; + +public class TestArrays { + + /** + * @param args + */ + public static void main(String[] args) { + Object[] arr = new Object[10]; + arr[0] = new Object(); + arr[1] = new Object(); + DemandPATestUtil.testThisVar(arr[1]); + } + +} diff --git a/com.ibm.wala.core.testdata/src/demandpa/TestClone.java b/com.ibm.wala.core.testdata/src/demandpa/TestClone.java index 081f8e4ab..af7fa569d 100644 --- a/com.ibm.wala.core.testdata/src/demandpa/TestClone.java +++ b/com.ibm.wala.core.testdata/src/demandpa/TestClone.java @@ -1,68 +1,68 @@ -/******************************************************************************* - * 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. - * - * This file is a derivative of code released by the University of - * California under the terms listed below. - * - * Refinement Analysis Tools is Copyright (c) 2007 The Regents of the - * University of California (Regents). Provided that this notice and - * the following two paragraphs are included in any distribution of - * Refinement Analysis Tools or its derivative work, Regents agrees - * not to assert any of Regents' copyright rights in Refinement - * Analysis Tools against recipient for recipient's reproduction, - * preparation of derivative works, public display, public - * performance, distribution or sublicensing of Refinement Analysis - * Tools and derivative works, in source code and object code form. - * This agreement not to assert does not confer, by implication, - * estoppel, or otherwise any license or rights in any intellectual - * property of Regents, including, but not limited to, any patents - * of Regents or Regents' employees. - * - * IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, - * INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, - * INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE - * AND ITS DOCUMENTATION, EVEN IF REGENTS HAS BEEN ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE AND FURTHER DISCLAIMS ANY STATUTORY - * WARRANTY OF NON-INFRINGEMENT. THE SOFTWARE AND ACCOMPANYING - * DOCUMENTATION, IF ANY, PROVIDED HEREUNDER IS PROVIDED "AS - * IS". REGENTS HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, - * UPDATES, ENHANCEMENTS, OR MODIFICATIONS. - */ -package demandpa; - -public class TestClone { - - private static class A implements Cloneable { - - public A copy() { - A ret = null; - try { - ret = (A) clone(); - } catch (CloneNotSupportedException e) { - e.printStackTrace(); - } - return ret; - } - } - - private static class B extends A { - } - - // private static class C extends A { - // Object g; - // } - - public static void main(String[] args) { - A a = new B(); - A a2 = a.copy(); - DemandPATestUtil.testThisVar(a2); - - } -} +/******************************************************************************* + * 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. + * + * This file is a derivative of code released by the University of + * California under the terms listed below. + * + * Refinement Analysis Tools is Copyright (c) 2007 The Regents of the + * University of California (Regents). Provided that this notice and + * the following two paragraphs are included in any distribution of + * Refinement Analysis Tools or its derivative work, Regents agrees + * not to assert any of Regents' copyright rights in Refinement + * Analysis Tools against recipient for recipient's reproduction, + * preparation of derivative works, public display, public + * performance, distribution or sublicensing of Refinement Analysis + * Tools and derivative works, in source code and object code form. + * This agreement not to assert does not confer, by implication, + * estoppel, or otherwise any license or rights in any intellectual + * property of Regents, including, but not limited to, any patents + * of Regents or Regents' employees. + * + * IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, + * INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, + * INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE + * AND ITS DOCUMENTATION, EVEN IF REGENTS HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE AND FURTHER DISCLAIMS ANY STATUTORY + * WARRANTY OF NON-INFRINGEMENT. THE SOFTWARE AND ACCOMPANYING + * DOCUMENTATION, IF ANY, PROVIDED HEREUNDER IS PROVIDED "AS + * IS". REGENTS HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, + * UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + */ +package demandpa; + +public class TestClone { + + private static class A implements Cloneable { + + public A copy() { + A ret = null; + try { + ret = (A) clone(); + } catch (CloneNotSupportedException e) { + e.printStackTrace(); + } + return ret; + } + } + + private static class B extends A { + } + + // private static class C extends A { + // Object g; + // } + + public static void main(String[] args) { + A a = new B(); + A a2 = a.copy(); + DemandPATestUtil.testThisVar(a2); + + } +} diff --git a/com.ibm.wala.core.testdata/src/demandpa/TestCond.java b/com.ibm.wala.core.testdata/src/demandpa/TestCond.java index 802a34410..239b04548 100644 --- a/com.ibm.wala.core.testdata/src/demandpa/TestCond.java +++ b/com.ibm.wala.core.testdata/src/demandpa/TestCond.java @@ -1,53 +1,53 @@ -/******************************************************************************* - * 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. - * - * This file is a derivative of code released by the University of - * California under the terms listed below. - * - * Refinement Analysis Tools is Copyright (c) 2007 The Regents of the - * University of California (Regents). Provided that this notice and - * the following two paragraphs are included in any distribution of - * Refinement Analysis Tools or its derivative work, Regents agrees - * not to assert any of Regents' copyright rights in Refinement - * Analysis Tools against recipient for recipient's reproduction, - * preparation of derivative works, public display, public - * performance, distribution or sublicensing of Refinement Analysis - * Tools and derivative works, in source code and object code form. - * This agreement not to assert does not confer, by implication, - * estoppel, or otherwise any license or rights in any intellectual - * property of Regents, including, but not limited to, any patents - * of Regents or Regents' employees. - * - * IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, - * INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, - * INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE - * AND ITS DOCUMENTATION, EVEN IF REGENTS HAS BEEN ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE AND FURTHER DISCLAIMS ANY STATUTORY - * WARRANTY OF NON-INFRINGEMENT. THE SOFTWARE AND ACCOMPANYING - * DOCUMENTATION, IF ANY, PROVIDED HEREUNDER IS PROVIDED "AS - * IS". REGENTS HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, - * UPDATES, ENHANCEMENTS, OR MODIFICATIONS. - */ -package demandpa; - -public class TestCond { - - public static void main(String[] args) { - Object[] arr = new Object[2]; - arr[0] = new B(); - arr[1] = new A(); - Object x = arr[0]; - if (x instanceof B) { - B b = (B) x; - DemandPATestUtil.testThisVar(b); - } - } - -} +/******************************************************************************* + * 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. + * + * This file is a derivative of code released by the University of + * California under the terms listed below. + * + * Refinement Analysis Tools is Copyright (c) 2007 The Regents of the + * University of California (Regents). Provided that this notice and + * the following two paragraphs are included in any distribution of + * Refinement Analysis Tools or its derivative work, Regents agrees + * not to assert any of Regents' copyright rights in Refinement + * Analysis Tools against recipient for recipient's reproduction, + * preparation of derivative works, public display, public + * performance, distribution or sublicensing of Refinement Analysis + * Tools and derivative works, in source code and object code form. + * This agreement not to assert does not confer, by implication, + * estoppel, or otherwise any license or rights in any intellectual + * property of Regents, including, but not limited to, any patents + * of Regents or Regents' employees. + * + * IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, + * INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, + * INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE + * AND ITS DOCUMENTATION, EVEN IF REGENTS HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE AND FURTHER DISCLAIMS ANY STATUTORY + * WARRANTY OF NON-INFRINGEMENT. THE SOFTWARE AND ACCOMPANYING + * DOCUMENTATION, IF ANY, PROVIDED HEREUNDER IS PROVIDED "AS + * IS". REGENTS HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, + * UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + */ +package demandpa; + +public class TestCond { + + public static void main(String[] args) { + Object[] arr = new Object[2]; + arr[0] = new B(); + arr[1] = new A(); + Object x = arr[0]; + if (x instanceof B) { + B b = (B) x; + DemandPATestUtil.testThisVar(b); + } + } + +} diff --git a/com.ibm.wala.core.testdata/src/demandpa/TestException.java b/com.ibm.wala.core.testdata/src/demandpa/TestException.java index cb3c7748e..c1e03e454 100644 --- a/com.ibm.wala.core.testdata/src/demandpa/TestException.java +++ b/com.ibm.wala.core.testdata/src/demandpa/TestException.java @@ -1,56 +1,56 @@ -/******************************************************************************* - * 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. - * - * This file is a derivative of code released by the University of - * California under the terms listed below. - * - * Refinement Analysis Tools is Copyright (c) 2007 The Regents of the - * University of California (Regents). Provided that this notice and - * the following two paragraphs are included in any distribution of - * Refinement Analysis Tools or its derivative work, Regents agrees - * not to assert any of Regents' copyright rights in Refinement - * Analysis Tools against recipient for recipient's reproduction, - * preparation of derivative works, public display, public - * performance, distribution or sublicensing of Refinement Analysis - * Tools and derivative works, in source code and object code form. - * This agreement not to assert does not confer, by implication, - * estoppel, or otherwise any license or rights in any intellectual - * property of Regents, including, but not limited to, any patents - * of Regents or Regents' employees. - * - * IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, - * INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, - * INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE - * AND ITS DOCUMENTATION, EVEN IF REGENTS HAS BEEN ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE AND FURTHER DISCLAIMS ANY STATUTORY - * WARRANTY OF NON-INFRINGEMENT. THE SOFTWARE AND ACCOMPANYING - * DOCUMENTATION, IF ANY, PROVIDED HEREUNDER IS PROVIDED "AS - * IS". REGENTS HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, - * UPDATES, ENHANCEMENTS, OR MODIFICATIONS. - */ -package demandpa; - -public class TestException { - - /** - * @param args - */ - public static void main(String[] args) { - try { - foo(null); - } catch (Exception e) { - DemandPATestUtil.testThisVar(e); - } - } - - public static void foo(Object o) throws IllegalAccessException { - throw new IllegalAccessException(); - } -} +/******************************************************************************* + * 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. + * + * This file is a derivative of code released by the University of + * California under the terms listed below. + * + * Refinement Analysis Tools is Copyright (c) 2007 The Regents of the + * University of California (Regents). Provided that this notice and + * the following two paragraphs are included in any distribution of + * Refinement Analysis Tools or its derivative work, Regents agrees + * not to assert any of Regents' copyright rights in Refinement + * Analysis Tools against recipient for recipient's reproduction, + * preparation of derivative works, public display, public + * performance, distribution or sublicensing of Refinement Analysis + * Tools and derivative works, in source code and object code form. + * This agreement not to assert does not confer, by implication, + * estoppel, or otherwise any license or rights in any intellectual + * property of Regents, including, but not limited to, any patents + * of Regents or Regents' employees. + * + * IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, + * INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, + * INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE + * AND ITS DOCUMENTATION, EVEN IF REGENTS HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE AND FURTHER DISCLAIMS ANY STATUTORY + * WARRANTY OF NON-INFRINGEMENT. THE SOFTWARE AND ACCOMPANYING + * DOCUMENTATION, IF ANY, PROVIDED HEREUNDER IS PROVIDED "AS + * IS". REGENTS HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, + * UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + */ +package demandpa; + +public class TestException { + + /** + * @param args + */ + public static void main(String[] args) { + try { + foo(null); + } catch (Exception e) { + DemandPATestUtil.testThisVar(e); + } + } + + public static void foo(Object o) throws IllegalAccessException { + throw new IllegalAccessException(); + } +} diff --git a/com.ibm.wala.core.testdata/src/demandpa/TestFactory.java b/com.ibm.wala.core.testdata/src/demandpa/TestFactory.java index 052882c57..9f6d73f63 100644 --- a/com.ibm.wala.core.testdata/src/demandpa/TestFactory.java +++ b/com.ibm.wala.core.testdata/src/demandpa/TestFactory.java @@ -1,56 +1,56 @@ -/******************************************************************************* - * 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. - * - * This file is a derivative of code released by the University of - * California under the terms listed below. - * - * Refinement Analysis Tools is Copyright (c) 2007 The Regents of the - * University of California (Regents). Provided that this notice and - * the following two paragraphs are included in any distribution of - * Refinement Analysis Tools or its derivative work, Regents agrees - * not to assert any of Regents' copyright rights in Refinement - * Analysis Tools against recipient for recipient's reproduction, - * preparation of derivative works, public display, public - * performance, distribution or sublicensing of Refinement Analysis - * Tools and derivative works, in source code and object code form. - * This agreement not to assert does not confer, by implication, - * estoppel, or otherwise any license or rights in any intellectual - * property of Regents, including, but not limited to, any patents - * of Regents or Regents' employees. - * - * IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, - * INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, - * INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE - * AND ITS DOCUMENTATION, EVEN IF REGENTS HAS BEEN ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE AND FURTHER DISCLAIMS ANY STATUTORY - * WARRANTY OF NON-INFRINGEMENT. THE SOFTWARE AND ACCOMPANYING - * DOCUMENTATION, IF ANY, PROVIDED HEREUNDER IS PROVIDED "AS - * IS". REGENTS HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, - * UPDATES, ENHANCEMENTS, OR MODIFICATIONS. - */ -package demandpa; - -public class TestFactory { - - static A makeA() { - return new A(); - } - - /** - * @param args - */ - public static void main(String[] args) { - A a1 = makeA(); - A a2 = makeA(); - DemandPATestUtil.makeVarUsed(a1); - DemandPATestUtil.testThisVar(a2); - } - -} +/******************************************************************************* + * 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. + * + * This file is a derivative of code released by the University of + * California under the terms listed below. + * + * Refinement Analysis Tools is Copyright (c) 2007 The Regents of the + * University of California (Regents). Provided that this notice and + * the following two paragraphs are included in any distribution of + * Refinement Analysis Tools or its derivative work, Regents agrees + * not to assert any of Regents' copyright rights in Refinement + * Analysis Tools against recipient for recipient's reproduction, + * preparation of derivative works, public display, public + * performance, distribution or sublicensing of Refinement Analysis + * Tools and derivative works, in source code and object code form. + * This agreement not to assert does not confer, by implication, + * estoppel, or otherwise any license or rights in any intellectual + * property of Regents, including, but not limited to, any patents + * of Regents or Regents' employees. + * + * IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, + * INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, + * INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE + * AND ITS DOCUMENTATION, EVEN IF REGENTS HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE AND FURTHER DISCLAIMS ANY STATUTORY + * WARRANTY OF NON-INFRINGEMENT. THE SOFTWARE AND ACCOMPANYING + * DOCUMENTATION, IF ANY, PROVIDED HEREUNDER IS PROVIDED "AS + * IS". REGENTS HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, + * UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + */ +package demandpa; + +public class TestFactory { + + static A makeA() { + return new A(); + } + + /** + * @param args + */ + public static void main(String[] args) { + A a1 = makeA(); + A a2 = makeA(); + DemandPATestUtil.makeVarUsed(a1); + DemandPATestUtil.testThisVar(a2); + } + +} diff --git a/com.ibm.wala.core.testdata/src/demandpa/TestFields.java b/com.ibm.wala.core.testdata/src/demandpa/TestFields.java index a17b6410d..d33884142 100644 --- a/com.ibm.wala.core.testdata/src/demandpa/TestFields.java +++ b/com.ibm.wala.core.testdata/src/demandpa/TestFields.java @@ -1,58 +1,58 @@ -/******************************************************************************* - * 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. - * - * This file is a derivative of code released by the University of - * California under the terms listed below. - * - * Refinement Analysis Tools is Copyright (c) 2007 The Regents of the - * University of California (Regents). Provided that this notice and - * the following two paragraphs are included in any distribution of - * Refinement Analysis Tools or its derivative work, Regents agrees - * not to assert any of Regents' copyright rights in Refinement - * Analysis Tools against recipient for recipient's reproduction, - * preparation of derivative works, public display, public - * performance, distribution or sublicensing of Refinement Analysis - * Tools and derivative works, in source code and object code form. - * This agreement not to assert does not confer, by implication, - * estoppel, or otherwise any license or rights in any intellectual - * property of Regents, including, but not limited to, any patents - * of Regents or Regents' employees. - * - * IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, - * INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, - * INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE - * AND ITS DOCUMENTATION, EVEN IF REGENTS HAS BEEN ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE AND FURTHER DISCLAIMS ANY STATUTORY - * WARRANTY OF NON-INFRINGEMENT. THE SOFTWARE AND ACCOMPANYING - * DOCUMENTATION, IF ANY, PROVIDED HEREUNDER IS PROVIDED "AS - * IS". REGENTS HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, - * UPDATES, ENHANCEMENTS, OR MODIFICATIONS. - */ -package demandpa; - -public class TestFields { - - /** - * @param args - */ - public static void main(String[] args) { - Object o1 = new Object(); - Object o2 = new Object(); - A a1 = new A(); - A a2 = new A(); - a1.f = o1; - a2.f = o2; - Object o3 = a1.f; - Object o4 = a2.f; - DemandPATestUtil.makeVarUsed(o3); - DemandPATestUtil.testThisVar(o4); - } - -} +/******************************************************************************* + * 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. + * + * This file is a derivative of code released by the University of + * California under the terms listed below. + * + * Refinement Analysis Tools is Copyright (c) 2007 The Regents of the + * University of California (Regents). Provided that this notice and + * the following two paragraphs are included in any distribution of + * Refinement Analysis Tools or its derivative work, Regents agrees + * not to assert any of Regents' copyright rights in Refinement + * Analysis Tools against recipient for recipient's reproduction, + * preparation of derivative works, public display, public + * performance, distribution or sublicensing of Refinement Analysis + * Tools and derivative works, in source code and object code form. + * This agreement not to assert does not confer, by implication, + * estoppel, or otherwise any license or rights in any intellectual + * property of Regents, including, but not limited to, any patents + * of Regents or Regents' employees. + * + * IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, + * INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, + * INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE + * AND ITS DOCUMENTATION, EVEN IF REGENTS HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE AND FURTHER DISCLAIMS ANY STATUTORY + * WARRANTY OF NON-INFRINGEMENT. THE SOFTWARE AND ACCOMPANYING + * DOCUMENTATION, IF ANY, PROVIDED HEREUNDER IS PROVIDED "AS + * IS". REGENTS HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, + * UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + */ +package demandpa; + +public class TestFields { + + /** + * @param args + */ + public static void main(String[] args) { + Object o1 = new Object(); + Object o2 = new Object(); + A a1 = new A(); + A a2 = new A(); + a1.f = o1; + a2.f = o2; + Object o3 = a1.f; + Object o4 = a2.f; + DemandPATestUtil.makeVarUsed(o3); + DemandPATestUtil.testThisVar(o4); + } + +} diff --git a/com.ibm.wala.core.testdata/src/demandpa/TestFieldsHarder.java b/com.ibm.wala.core.testdata/src/demandpa/TestFieldsHarder.java index d8b32a9cb..529375e56 100644 --- a/com.ibm.wala.core.testdata/src/demandpa/TestFieldsHarder.java +++ b/com.ibm.wala.core.testdata/src/demandpa/TestFieldsHarder.java @@ -1,48 +1,48 @@ -/** - * Refinement Analysis Tools is Copyright (c) 2007 The Regents of the - * University of California (Regents). Provided that this notice and - * the following two paragraphs are included in any distribution of - * Refinement Analysis Tools or its derivative work, Regents agrees - * not to assert any of Regents' copyright rights in Refinement - * Analysis Tools against recipient for recipient's reproduction, - * preparation of derivative works, public display, public - * performance, distribution or sublicensing of Refinement Analysis - * Tools and derivative works, in source code and object code form. - * This agreement not to assert does not confer, by implication, - * estoppel, or otherwise any license or rights in any intellectual - * property of Regents, including, but not limited to, any patents - * of Regents or Regents' employees. - * - * IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, - * INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, - * INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE - * AND ITS DOCUMENTATION, EVEN IF REGENTS HAS BEEN ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE AND FURTHER DISCLAIMS ANY STATUTORY - * WARRANTY OF NON-INFRINGEMENT. THE SOFTWARE AND ACCOMPANYING - * DOCUMENTATION, IF ANY, PROVIDED HEREUNDER IS PROVIDED "AS - * IS". REGENTS HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, - * UPDATES, ENHANCEMENTS, OR MODIFICATIONS. - */ -package demandpa; - -public class TestFieldsHarder { - - /** - * @param args - */ - public static void main(String[] args) { - Object o1 = new Object(); - A a1 = new A(); - a1.f = o1; - A a2 = new A(); - a2.f = a1; - A a3 = (A) a2.f; - Object o2 = a3.f; - DemandPATestUtil.testThisVar(o2); - } - -} +/** + * Refinement Analysis Tools is Copyright (c) 2007 The Regents of the + * University of California (Regents). Provided that this notice and + * the following two paragraphs are included in any distribution of + * Refinement Analysis Tools or its derivative work, Regents agrees + * not to assert any of Regents' copyright rights in Refinement + * Analysis Tools against recipient for recipient's reproduction, + * preparation of derivative works, public display, public + * performance, distribution or sublicensing of Refinement Analysis + * Tools and derivative works, in source code and object code form. + * This agreement not to assert does not confer, by implication, + * estoppel, or otherwise any license or rights in any intellectual + * property of Regents, including, but not limited to, any patents + * of Regents or Regents' employees. + * + * IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, + * INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, + * INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE + * AND ITS DOCUMENTATION, EVEN IF REGENTS HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE AND FURTHER DISCLAIMS ANY STATUTORY + * WARRANTY OF NON-INFRINGEMENT. THE SOFTWARE AND ACCOMPANYING + * DOCUMENTATION, IF ANY, PROVIDED HEREUNDER IS PROVIDED "AS + * IS". REGENTS HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, + * UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + */ +package demandpa; + +public class TestFieldsHarder { + + /** + * @param args + */ + public static void main(String[] args) { + Object o1 = new Object(); + A a1 = new A(); + a1.f = o1; + A a2 = new A(); + a2.f = a1; + A a3 = (A) a2.f; + Object o2 = a3.f; + DemandPATestUtil.testThisVar(o2); + } + +} diff --git a/com.ibm.wala.core.testdata/src/demandpa/TestGetterSetter.java b/com.ibm.wala.core.testdata/src/demandpa/TestGetterSetter.java index ca17b495d..5cea468ae 100644 --- a/com.ibm.wala.core.testdata/src/demandpa/TestGetterSetter.java +++ b/com.ibm.wala.core.testdata/src/demandpa/TestGetterSetter.java @@ -1,59 +1,59 @@ -/******************************************************************************* - * 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. - * - * This file is a derivative of code released by the University of - * California under the terms listed below. - * - * Refinement Analysis Tools is Copyright (c) 2007 The Regents of the - * University of California (Regents). Provided that this notice and - * the following two paragraphs are included in any distribution of - * Refinement Analysis Tools or its derivative work, Regents agrees - * not to assert any of Regents' copyright rights in Refinement - * Analysis Tools against recipient for recipient's reproduction, - * preparation of derivative works, public display, public - * performance, distribution or sublicensing of Refinement Analysis - * Tools and derivative works, in source code and object code form. - * This agreement not to assert does not confer, by implication, - * estoppel, or otherwise any license or rights in any intellectual - * property of Regents, including, but not limited to, any patents - * of Regents or Regents' employees. - * - * IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, - * INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, - * INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE - * AND ITS DOCUMENTATION, EVEN IF REGENTS HAS BEEN ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE AND FURTHER DISCLAIMS ANY STATUTORY - * WARRANTY OF NON-INFRINGEMENT. THE SOFTWARE AND ACCOMPANYING - * DOCUMENTATION, IF ANY, PROVIDED HEREUNDER IS PROVIDED "AS - * IS". REGENTS HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, - * UPDATES, ENHANCEMENTS, OR MODIFICATIONS. - */ -package demandpa; - -public class TestGetterSetter { - - /** - * @param args - */ - public static void main(String[] args) { - Object o1 = new Object(); - Object o2 = new Object(); - A a1 = new A(); - A a2 = new A(); - a1.setF(o1); - a2.f = o2; - Object o3 = a1.getF(); - Object o4 = a2.f; - DemandPATestUtil.makeVarUsed(o4); - DemandPATestUtil.testThisVar(o3); - - } - -} +/******************************************************************************* + * 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. + * + * This file is a derivative of code released by the University of + * California under the terms listed below. + * + * Refinement Analysis Tools is Copyright (c) 2007 The Regents of the + * University of California (Regents). Provided that this notice and + * the following two paragraphs are included in any distribution of + * Refinement Analysis Tools or its derivative work, Regents agrees + * not to assert any of Regents' copyright rights in Refinement + * Analysis Tools against recipient for recipient's reproduction, + * preparation of derivative works, public display, public + * performance, distribution or sublicensing of Refinement Analysis + * Tools and derivative works, in source code and object code form. + * This agreement not to assert does not confer, by implication, + * estoppel, or otherwise any license or rights in any intellectual + * property of Regents, including, but not limited to, any patents + * of Regents or Regents' employees. + * + * IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, + * INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, + * INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE + * AND ITS DOCUMENTATION, EVEN IF REGENTS HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE AND FURTHER DISCLAIMS ANY STATUTORY + * WARRANTY OF NON-INFRINGEMENT. THE SOFTWARE AND ACCOMPANYING + * DOCUMENTATION, IF ANY, PROVIDED HEREUNDER IS PROVIDED "AS + * IS". REGENTS HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, + * UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + */ +package demandpa; + +public class TestGetterSetter { + + /** + * @param args + */ + public static void main(String[] args) { + Object o1 = new Object(); + Object o2 = new Object(); + A a1 = new A(); + A a2 = new A(); + a1.setF(o1); + a2.f = o2; + Object o3 = a1.getF(); + Object o4 = a2.f; + DemandPATestUtil.makeVarUsed(o4); + DemandPATestUtil.testThisVar(o3); + + } + +} diff --git a/com.ibm.wala.core.testdata/src/demandpa/TestGlobal.java b/com.ibm.wala.core.testdata/src/demandpa/TestGlobal.java index c544abd56..0f1d7240d 100644 --- a/com.ibm.wala.core.testdata/src/demandpa/TestGlobal.java +++ b/com.ibm.wala.core.testdata/src/demandpa/TestGlobal.java @@ -1,56 +1,56 @@ -/******************************************************************************* - * 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. - * - * This file is a derivative of code released by the University of - * California under the terms listed below. - * - * Refinement Analysis Tools is Copyright (c) 2007 The Regents of the - * University of California (Regents). Provided that this notice and - * the following two paragraphs are included in any distribution of - * Refinement Analysis Tools or its derivative work, Regents agrees - * not to assert any of Regents' copyright rights in Refinement - * Analysis Tools against recipient for recipient's reproduction, - * preparation of derivative works, public display, public - * performance, distribution or sublicensing of Refinement Analysis - * Tools and derivative works, in source code and object code form. - * This agreement not to assert does not confer, by implication, - * estoppel, or otherwise any license or rights in any intellectual - * property of Regents, including, but not limited to, any patents - * of Regents or Regents' employees. - * - * IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, - * INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, - * INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE - * AND ITS DOCUMENTATION, EVEN IF REGENTS HAS BEEN ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE AND FURTHER DISCLAIMS ANY STATUTORY - * WARRANTY OF NON-INFRINGEMENT. THE SOFTWARE AND ACCOMPANYING - * DOCUMENTATION, IF ANY, PROVIDED HEREUNDER IS PROVIDED "AS - * IS". REGENTS HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, - * UPDATES, ENHANCEMENTS, OR MODIFICATIONS. - */ -package demandpa; - -public class TestGlobal { - - static Object g = new Object(); - - /** - * @param args - */ - - static Object getGlobal() { - return g; - } - - public static void main(String[] args) { - DemandPATestUtil.testThisVar(getGlobal()); - } - -} +/******************************************************************************* + * 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. + * + * This file is a derivative of code released by the University of + * California under the terms listed below. + * + * Refinement Analysis Tools is Copyright (c) 2007 The Regents of the + * University of California (Regents). Provided that this notice and + * the following two paragraphs are included in any distribution of + * Refinement Analysis Tools or its derivative work, Regents agrees + * not to assert any of Regents' copyright rights in Refinement + * Analysis Tools against recipient for recipient's reproduction, + * preparation of derivative works, public display, public + * performance, distribution or sublicensing of Refinement Analysis + * Tools and derivative works, in source code and object code form. + * This agreement not to assert does not confer, by implication, + * estoppel, or otherwise any license or rights in any intellectual + * property of Regents, including, but not limited to, any patents + * of Regents or Regents' employees. + * + * IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, + * INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, + * INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE + * AND ITS DOCUMENTATION, EVEN IF REGENTS HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE AND FURTHER DISCLAIMS ANY STATUTORY + * WARRANTY OF NON-INFRINGEMENT. THE SOFTWARE AND ACCOMPANYING + * DOCUMENTATION, IF ANY, PROVIDED HEREUNDER IS PROVIDED "AS + * IS". REGENTS HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, + * UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + */ +package demandpa; + +public class TestGlobal { + + static Object g = new Object(); + + /** + * @param args + */ + + static Object getGlobal() { + return g; + } + + public static void main(String[] args) { + DemandPATestUtil.testThisVar(getGlobal()); + } + +} diff --git a/com.ibm.wala.core.testdata/src/demandpa/TestHashMapGet.java b/com.ibm.wala.core.testdata/src/demandpa/TestHashMapGet.java index 564874d4b..a44e0c5d2 100644 --- a/com.ibm.wala.core.testdata/src/demandpa/TestHashMapGet.java +++ b/com.ibm.wala.core.testdata/src/demandpa/TestHashMapGet.java @@ -1,56 +1,56 @@ -/******************************************************************************* - * 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. - * - * This file is a derivative of code released by the University of - * California under the terms listed below. - * - * Refinement Analysis Tools is Copyright (c) 2007 The Regents of the - * University of California (Regents). Provided that this notice and - * the following two paragraphs are included in any distribution of - * Refinement Analysis Tools or its derivative work, Regents agrees - * not to assert any of Regents' copyright rights in Refinement - * Analysis Tools against recipient for recipient's reproduction, - * preparation of derivative works, public display, public - * performance, distribution or sublicensing of Refinement Analysis - * Tools and derivative works, in source code and object code form. - * This agreement not to assert does not confer, by implication, - * estoppel, or otherwise any license or rights in any intellectual - * property of Regents, including, but not limited to, any patents - * of Regents or Regents' employees. - * - * IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, - * INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, - * INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE - * AND ITS DOCUMENTATION, EVEN IF REGENTS HAS BEEN ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE AND FURTHER DISCLAIMS ANY STATUTORY - * WARRANTY OF NON-INFRINGEMENT. THE SOFTWARE AND ACCOMPANYING - * DOCUMENTATION, IF ANY, PROVIDED HEREUNDER IS PROVIDED "AS - * IS". REGENTS HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, - * UPDATES, ENHANCEMENTS, OR MODIFICATIONS. - */ -package demandpa; - - -public class TestHashMapGet { - - public static void main(String[] args) { - DummyHashMap s1 = new DummyHashMap(); - DummyHashMap s2 = new DummyHashMap(); - Object key1 = new Object(); - Object key2 = new Object(); - s1.put(key1, new Object()); - s2.put(key2, new Object()); - Object o1 = s1.get(key1); - Object o2 = s2.get(key2); - DemandPATestUtil.makeVarUsed(o1); - DemandPATestUtil.testThisVar(o2); - } - -} +/******************************************************************************* + * 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. + * + * This file is a derivative of code released by the University of + * California under the terms listed below. + * + * Refinement Analysis Tools is Copyright (c) 2007 The Regents of the + * University of California (Regents). Provided that this notice and + * the following two paragraphs are included in any distribution of + * Refinement Analysis Tools or its derivative work, Regents agrees + * not to assert any of Regents' copyright rights in Refinement + * Analysis Tools against recipient for recipient's reproduction, + * preparation of derivative works, public display, public + * performance, distribution or sublicensing of Refinement Analysis + * Tools and derivative works, in source code and object code form. + * This agreement not to assert does not confer, by implication, + * estoppel, or otherwise any license or rights in any intellectual + * property of Regents, including, but not limited to, any patents + * of Regents or Regents' employees. + * + * IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, + * INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, + * INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE + * AND ITS DOCUMENTATION, EVEN IF REGENTS HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE AND FURTHER DISCLAIMS ANY STATUTORY + * WARRANTY OF NON-INFRINGEMENT. THE SOFTWARE AND ACCOMPANYING + * DOCUMENTATION, IF ANY, PROVIDED HEREUNDER IS PROVIDED "AS + * IS". REGENTS HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, + * UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + */ +package demandpa; + + +public class TestHashMapGet { + + public static void main(String[] args) { + DummyHashMap s1 = new DummyHashMap(); + DummyHashMap s2 = new DummyHashMap(); + Object key1 = new Object(); + Object key2 = new Object(); + s1.put(key1, new Object()); + s2.put(key2, new Object()); + Object o1 = s1.get(key1); + Object o2 = s2.get(key2); + DemandPATestUtil.makeVarUsed(o1); + DemandPATestUtil.testThisVar(o2); + } + +} diff --git a/com.ibm.wala.core.testdata/src/demandpa/TestHashSet.java b/com.ibm.wala.core.testdata/src/demandpa/TestHashSet.java index 93b81a895..ba13d4ac4 100644 --- a/com.ibm.wala.core.testdata/src/demandpa/TestHashSet.java +++ b/com.ibm.wala.core.testdata/src/demandpa/TestHashSet.java @@ -1,53 +1,53 @@ -/******************************************************************************* - * 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. - * - * This file is a derivative of code released by the University of - * California under the terms listed below. - * - * Refinement Analysis Tools is Copyright (c) 2007 The Regents of the - * University of California (Regents). Provided that this notice and - * the following two paragraphs are included in any distribution of - * Refinement Analysis Tools or its derivative work, Regents agrees - * not to assert any of Regents' copyright rights in Refinement - * Analysis Tools against recipient for recipient's reproduction, - * preparation of derivative works, public display, public - * performance, distribution or sublicensing of Refinement Analysis - * Tools and derivative works, in source code and object code form. - * This agreement not to assert does not confer, by implication, - * estoppel, or otherwise any license or rights in any intellectual - * property of Regents, including, but not limited to, any patents - * of Regents or Regents' employees. - * - * IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, - * INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, - * INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE - * AND ITS DOCUMENTATION, EVEN IF REGENTS HAS BEEN ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE AND FURTHER DISCLAIMS ANY STATUTORY - * WARRANTY OF NON-INFRINGEMENT. THE SOFTWARE AND ACCOMPANYING - * DOCUMENTATION, IF ANY, PROVIDED HEREUNDER IS PROVIDED "AS - * IS". REGENTS HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, - * UPDATES, ENHANCEMENTS, OR MODIFICATIONS. - */ -package demandpa; - - -public class TestHashSet { - - public static void main(String[] args) { - DummyHashSet s1 = new DummyHashSet(); - DummyHashSet s2 = new DummyHashSet(); - s1.add(new Object()); - s2.add(new Object()); - Object o1 = s1.iterator().next(); - Object o2 = s2.iterator().next(); - DemandPATestUtil.makeVarUsed(o1); - DemandPATestUtil.testThisVar(o2); - } -} +/******************************************************************************* + * 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. + * + * This file is a derivative of code released by the University of + * California under the terms listed below. + * + * Refinement Analysis Tools is Copyright (c) 2007 The Regents of the + * University of California (Regents). Provided that this notice and + * the following two paragraphs are included in any distribution of + * Refinement Analysis Tools or its derivative work, Regents agrees + * not to assert any of Regents' copyright rights in Refinement + * Analysis Tools against recipient for recipient's reproduction, + * preparation of derivative works, public display, public + * performance, distribution or sublicensing of Refinement Analysis + * Tools and derivative works, in source code and object code form. + * This agreement not to assert does not confer, by implication, + * estoppel, or otherwise any license or rights in any intellectual + * property of Regents, including, but not limited to, any patents + * of Regents or Regents' employees. + * + * IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, + * INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, + * INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE + * AND ITS DOCUMENTATION, EVEN IF REGENTS HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE AND FURTHER DISCLAIMS ANY STATUTORY + * WARRANTY OF NON-INFRINGEMENT. THE SOFTWARE AND ACCOMPANYING + * DOCUMENTATION, IF ANY, PROVIDED HEREUNDER IS PROVIDED "AS + * IS". REGENTS HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, + * UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + */ +package demandpa; + + +public class TestHashSet { + + public static void main(String[] args) { + DummyHashSet s1 = new DummyHashSet(); + DummyHashSet s2 = new DummyHashSet(); + s1.add(new Object()); + s2.add(new Object()); + Object o1 = s1.iterator().next(); + Object o2 = s2.iterator().next(); + DemandPATestUtil.makeVarUsed(o1); + DemandPATestUtil.testThisVar(o2); + } +} diff --git a/com.ibm.wala.core.testdata/src/demandpa/TestHashtableEnum.java b/com.ibm.wala.core.testdata/src/demandpa/TestHashtableEnum.java index 4a4f53df0..48161956a 100644 --- a/com.ibm.wala.core.testdata/src/demandpa/TestHashtableEnum.java +++ b/com.ibm.wala.core.testdata/src/demandpa/TestHashtableEnum.java @@ -1,60 +1,60 @@ -/******************************************************************************* - * 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. - * - * This file is a derivative of code released by the University of - * California under the terms listed below. - * - * Refinement Analysis Tools is Copyright (c) 2007 The Regents of the - * University of California (Regents). Provided that this notice and - * the following two paragraphs are included in any distribution of - * Refinement Analysis Tools or its derivative work, Regents agrees - * not to assert any of Regents' copyright rights in Refinement - * Analysis Tools against recipient for recipient's reproduction, - * preparation of derivative works, public display, public - * performance, distribution or sublicensing of Refinement Analysis - * Tools and derivative works, in source code and object code form. - * This agreement not to assert does not confer, by implication, - * estoppel, or otherwise any license or rights in any intellectual - * property of Regents, including, but not limited to, any patents - * of Regents or Regents' employees. - * - * IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, - * INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, - * INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE - * AND ITS DOCUMENTATION, EVEN IF REGENTS HAS BEEN ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE AND FURTHER DISCLAIMS ANY STATUTORY - * WARRANTY OF NON-INFRINGEMENT. THE SOFTWARE AND ACCOMPANYING - * DOCUMENTATION, IF ANY, PROVIDED HEREUNDER IS PROVIDED "AS - * IS". REGENTS HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, - * UPDATES, ENHANCEMENTS, OR MODIFICATIONS. - */ -package demandpa; - - -public class TestHashtableEnum { - - /** - * @param args - */ - public static void main(String[] args) { - DummyHashMap h1 = new DummyHashMap(); - DummyHashMap h2 = new DummyHashMap(); - Object key1 = new Object(); - Object key2 = new Object(); - h1.put(key1, new Object()); - h2.put(key2, new Object()); - Object o1 = h1.elements().next(); - Object o2 = h2.elements().next(); - DemandPATestUtil.makeVarUsed(o1); - DemandPATestUtil.testThisVar(o2); - - } - -} +/******************************************************************************* + * 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. + * + * This file is a derivative of code released by the University of + * California under the terms listed below. + * + * Refinement Analysis Tools is Copyright (c) 2007 The Regents of the + * University of California (Regents). Provided that this notice and + * the following two paragraphs are included in any distribution of + * Refinement Analysis Tools or its derivative work, Regents agrees + * not to assert any of Regents' copyright rights in Refinement + * Analysis Tools against recipient for recipient's reproduction, + * preparation of derivative works, public display, public + * performance, distribution or sublicensing of Refinement Analysis + * Tools and derivative works, in source code and object code form. + * This agreement not to assert does not confer, by implication, + * estoppel, or otherwise any license or rights in any intellectual + * property of Regents, including, but not limited to, any patents + * of Regents or Regents' employees. + * + * IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, + * INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, + * INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE + * AND ITS DOCUMENTATION, EVEN IF REGENTS HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE AND FURTHER DISCLAIMS ANY STATUTORY + * WARRANTY OF NON-INFRINGEMENT. THE SOFTWARE AND ACCOMPANYING + * DOCUMENTATION, IF ANY, PROVIDED HEREUNDER IS PROVIDED "AS + * IS". REGENTS HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, + * UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + */ +package demandpa; + + +public class TestHashtableEnum { + + /** + * @param args + */ + public static void main(String[] args) { + DummyHashMap h1 = new DummyHashMap(); + DummyHashMap h2 = new DummyHashMap(); + Object key1 = new Object(); + Object key2 = new Object(); + h1.put(key1, new Object()); + h2.put(key2, new Object()); + Object o1 = h1.elements().next(); + Object o2 = h2.elements().next(); + DemandPATestUtil.makeVarUsed(o1); + DemandPATestUtil.testThisVar(o2); + + } + +} diff --git a/com.ibm.wala.core.testdata/src/demandpa/TestId.java b/com.ibm.wala.core.testdata/src/demandpa/TestId.java index 0486c7b3c..ffcbeffd3 100644 --- a/com.ibm.wala.core.testdata/src/demandpa/TestId.java +++ b/com.ibm.wala.core.testdata/src/demandpa/TestId.java @@ -1,58 +1,58 @@ -/******************************************************************************* - * 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. - * - * This file is a derivative of code released by the University of - * California under the terms listed below. - * - * Refinement Analysis Tools is Copyright (c) 2007 The Regents of the - * University of California (Regents). Provided that this notice and - * the following two paragraphs are included in any distribution of - * Refinement Analysis Tools or its derivative work, Regents agrees - * not to assert any of Regents' copyright rights in Refinement - * Analysis Tools against recipient for recipient's reproduction, - * preparation of derivative works, public display, public - * performance, distribution or sublicensing of Refinement Analysis - * Tools and derivative works, in source code and object code form. - * This agreement not to assert does not confer, by implication, - * estoppel, or otherwise any license or rights in any intellectual - * property of Regents, including, but not limited to, any patents - * of Regents or Regents' employees. - * - * IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, - * INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, - * INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE - * AND ITS DOCUMENTATION, EVEN IF REGENTS HAS BEEN ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE AND FURTHER DISCLAIMS ANY STATUTORY - * WARRANTY OF NON-INFRINGEMENT. THE SOFTWARE AND ACCOMPANYING - * DOCUMENTATION, IF ANY, PROVIDED HEREUNDER IS PROVIDED "AS - * IS". REGENTS HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, - * UPDATES, ENHANCEMENTS, OR MODIFICATIONS. - */ -package demandpa; - -public class TestId { - - static Object id(Object o) { - return o; - } - - /** - * @param args - */ - public static void main(String[] args) { - Object o1 = new Object(); - Object o2 = new Object(); - Object o3 = id(o1); - Object o4 = id(o2); - DemandPATestUtil.makeVarUsed(o3); - DemandPATestUtil.testThisVar(o4); - } - -} +/******************************************************************************* + * 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. + * + * This file is a derivative of code released by the University of + * California under the terms listed below. + * + * Refinement Analysis Tools is Copyright (c) 2007 The Regents of the + * University of California (Regents). Provided that this notice and + * the following two paragraphs are included in any distribution of + * Refinement Analysis Tools or its derivative work, Regents agrees + * not to assert any of Regents' copyright rights in Refinement + * Analysis Tools against recipient for recipient's reproduction, + * preparation of derivative works, public display, public + * performance, distribution or sublicensing of Refinement Analysis + * Tools and derivative works, in source code and object code form. + * This agreement not to assert does not confer, by implication, + * estoppel, or otherwise any license or rights in any intellectual + * property of Regents, including, but not limited to, any patents + * of Regents or Regents' employees. + * + * IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, + * INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, + * INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE + * AND ITS DOCUMENTATION, EVEN IF REGENTS HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE AND FURTHER DISCLAIMS ANY STATUTORY + * WARRANTY OF NON-INFRINGEMENT. THE SOFTWARE AND ACCOMPANYING + * DOCUMENTATION, IF ANY, PROVIDED HEREUNDER IS PROVIDED "AS + * IS". REGENTS HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, + * UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + */ +package demandpa; + +public class TestId { + + static Object id(Object o) { + return o; + } + + /** + * @param args + */ + public static void main(String[] args) { + Object o1 = new Object(); + Object o2 = new Object(); + Object o3 = id(o1); + Object o4 = id(o2); + DemandPATestUtil.makeVarUsed(o3); + DemandPATestUtil.testThisVar(o4); + } + +} diff --git a/com.ibm.wala.core.testdata/src/demandpa/TestLinkedList.java b/com.ibm.wala.core.testdata/src/demandpa/TestLinkedList.java index 4be25277b..9c79dd786 100644 --- a/com.ibm.wala.core.testdata/src/demandpa/TestLinkedList.java +++ b/com.ibm.wala.core.testdata/src/demandpa/TestLinkedList.java @@ -1,58 +1,58 @@ -/******************************************************************************* - * 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. - * - * This file is a derivative of code released by the University of - * California under the terms listed below. - * - * Refinement Analysis Tools is Copyright (c) 2007 The Regents of the - * University of California (Regents). Provided that this notice and - * the following two paragraphs are included in any distribution of - * Refinement Analysis Tools or its derivative work, Regents agrees - * not to assert any of Regents' copyright rights in Refinement - * Analysis Tools against recipient for recipient's reproduction, - * preparation of derivative works, public display, public - * performance, distribution or sublicensing of Refinement Analysis - * Tools and derivative works, in source code and object code form. - * This agreement not to assert does not confer, by implication, - * estoppel, or otherwise any license or rights in any intellectual - * property of Regents, including, but not limited to, any patents - * of Regents or Regents' employees. - * - * IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, - * INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, - * INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE - * AND ITS DOCUMENTATION, EVEN IF REGENTS HAS BEEN ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE AND FURTHER DISCLAIMS ANY STATUTORY - * WARRANTY OF NON-INFRINGEMENT. THE SOFTWARE AND ACCOMPANYING - * DOCUMENTATION, IF ANY, PROVIDED HEREUNDER IS PROVIDED "AS - * IS". REGENTS HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, - * UPDATES, ENHANCEMENTS, OR MODIFICATIONS. - */ -package demandpa; - - -public class TestLinkedList { - - /** - * @param args - */ - public static void main(String[] args) { - DummyLinkedList l1 = new DummyLinkedList(); - DummyLinkedList l2 = new DummyLinkedList(); - l1.add(new Object()); - l2.add(new Object()); - Object o1 = l1.get(0); - Object o2 = l2.get(0); - DemandPATestUtil.makeVarUsed(o1); - DemandPATestUtil.testThisVar(o2); - - } - -} +/******************************************************************************* + * 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. + * + * This file is a derivative of code released by the University of + * California under the terms listed below. + * + * Refinement Analysis Tools is Copyright (c) 2007 The Regents of the + * University of California (Regents). Provided that this notice and + * the following two paragraphs are included in any distribution of + * Refinement Analysis Tools or its derivative work, Regents agrees + * not to assert any of Regents' copyright rights in Refinement + * Analysis Tools against recipient for recipient's reproduction, + * preparation of derivative works, public display, public + * performance, distribution or sublicensing of Refinement Analysis + * Tools and derivative works, in source code and object code form. + * This agreement not to assert does not confer, by implication, + * estoppel, or otherwise any license or rights in any intellectual + * property of Regents, including, but not limited to, any patents + * of Regents or Regents' employees. + * + * IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, + * INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, + * INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE + * AND ITS DOCUMENTATION, EVEN IF REGENTS HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE AND FURTHER DISCLAIMS ANY STATUTORY + * WARRANTY OF NON-INFRINGEMENT. THE SOFTWARE AND ACCOMPANYING + * DOCUMENTATION, IF ANY, PROVIDED HEREUNDER IS PROVIDED "AS + * IS". REGENTS HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, + * UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + */ +package demandpa; + + +public class TestLinkedList { + + /** + * @param args + */ + public static void main(String[] args) { + DummyLinkedList l1 = new DummyLinkedList(); + DummyLinkedList l2 = new DummyLinkedList(); + l1.add(new Object()); + l2.add(new Object()); + Object o1 = l1.get(0); + Object o2 = l2.get(0); + DemandPATestUtil.makeVarUsed(o1); + DemandPATestUtil.testThisVar(o2); + + } + +} diff --git a/com.ibm.wala.core.testdata/src/demandpa/TestLinkedListIter.java b/com.ibm.wala.core.testdata/src/demandpa/TestLinkedListIter.java index 66f484142..14099f9c1 100644 --- a/com.ibm.wala.core.testdata/src/demandpa/TestLinkedListIter.java +++ b/com.ibm.wala.core.testdata/src/demandpa/TestLinkedListIter.java @@ -1,58 +1,58 @@ -/******************************************************************************* - * 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. - * - * This file is a derivative of code released by the University of - * California under the terms listed below. - * - * Refinement Analysis Tools is Copyright (c) 2007 The Regents of the - * University of California (Regents). Provided that this notice and - * the following two paragraphs are included in any distribution of - * Refinement Analysis Tools or its derivative work, Regents agrees - * not to assert any of Regents' copyright rights in Refinement - * Analysis Tools against recipient for recipient's reproduction, - * preparation of derivative works, public display, public - * performance, distribution or sublicensing of Refinement Analysis - * Tools and derivative works, in source code and object code form. - * This agreement not to assert does not confer, by implication, - * estoppel, or otherwise any license or rights in any intellectual - * property of Regents, including, but not limited to, any patents - * of Regents or Regents' employees. - * - * IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, - * INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, - * INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE - * AND ITS DOCUMENTATION, EVEN IF REGENTS HAS BEEN ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE AND FURTHER DISCLAIMS ANY STATUTORY - * WARRANTY OF NON-INFRINGEMENT. THE SOFTWARE AND ACCOMPANYING - * DOCUMENTATION, IF ANY, PROVIDED HEREUNDER IS PROVIDED "AS - * IS". REGENTS HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, - * UPDATES, ENHANCEMENTS, OR MODIFICATIONS. - */ -package demandpa; - - -public class TestLinkedListIter { - - /** - * @param args - */ - public static void main(String[] args) { - DummyLinkedList l1 = new DummyLinkedList(); - DummyLinkedList l2 = new DummyLinkedList(); - l1.add(new Object()); - l2.add(new Object()); - Object o1 = l1.iterator().next(); - Object o2 = l2.iterator().next(); - DemandPATestUtil.makeVarUsed(o1); - DemandPATestUtil.testThisVar(o2); - - } - -} +/******************************************************************************* + * 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. + * + * This file is a derivative of code released by the University of + * California under the terms listed below. + * + * Refinement Analysis Tools is Copyright (c) 2007 The Regents of the + * University of California (Regents). Provided that this notice and + * the following two paragraphs are included in any distribution of + * Refinement Analysis Tools or its derivative work, Regents agrees + * not to assert any of Regents' copyright rights in Refinement + * Analysis Tools against recipient for recipient's reproduction, + * preparation of derivative works, public display, public + * performance, distribution or sublicensing of Refinement Analysis + * Tools and derivative works, in source code and object code form. + * This agreement not to assert does not confer, by implication, + * estoppel, or otherwise any license or rights in any intellectual + * property of Regents, including, but not limited to, any patents + * of Regents or Regents' employees. + * + * IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, + * INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, + * INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE + * AND ITS DOCUMENTATION, EVEN IF REGENTS HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE AND FURTHER DISCLAIMS ANY STATUTORY + * WARRANTY OF NON-INFRINGEMENT. THE SOFTWARE AND ACCOMPANYING + * DOCUMENTATION, IF ANY, PROVIDED HEREUNDER IS PROVIDED "AS + * IS". REGENTS HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, + * UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + */ +package demandpa; + + +public class TestLinkedListIter { + + /** + * @param args + */ + public static void main(String[] args) { + DummyLinkedList l1 = new DummyLinkedList(); + DummyLinkedList l2 = new DummyLinkedList(); + l1.add(new Object()); + l2.add(new Object()); + Object o1 = l1.iterator().next(); + Object o2 = l2.iterator().next(); + DemandPATestUtil.makeVarUsed(o1); + DemandPATestUtil.testThisVar(o2); + + } + +} diff --git a/com.ibm.wala.core.testdata/src/demandpa/TestLocals.java b/com.ibm.wala.core.testdata/src/demandpa/TestLocals.java index a18639a59..2d61f991a 100644 --- a/com.ibm.wala.core.testdata/src/demandpa/TestLocals.java +++ b/com.ibm.wala.core.testdata/src/demandpa/TestLocals.java @@ -1,50 +1,50 @@ -/******************************************************************************* - * 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. - * - * This file is a derivative of code released by the University of - * California under the terms listed below. - * - * Refinement Analysis Tools is Copyright (c) 2007 The Regents of the - * University of California (Regents). Provided that this notice and - * the following two paragraphs are included in any distribution of - * Refinement Analysis Tools or its derivative work, Regents agrees - * not to assert any of Regents' copyright rights in Refinement - * Analysis Tools against recipient for recipient's reproduction, - * preparation of derivative works, public display, public - * performance, distribution or sublicensing of Refinement Analysis - * Tools and derivative works, in source code and object code form. - * This agreement not to assert does not confer, by implication, - * estoppel, or otherwise any license or rights in any intellectual - * property of Regents, including, but not limited to, any patents - * of Regents or Regents' employees. - * - * IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, - * INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, - * INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE - * AND ITS DOCUMENTATION, EVEN IF REGENTS HAS BEEN ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE AND FURTHER DISCLAIMS ANY STATUTORY - * WARRANTY OF NON-INFRINGEMENT. THE SOFTWARE AND ACCOMPANYING - * DOCUMENTATION, IF ANY, PROVIDED HEREUNDER IS PROVIDED "AS - * IS". REGENTS HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, - * UPDATES, ENHANCEMENTS, OR MODIFICATIONS. - */ -package demandpa; - -public class TestLocals { - - /** - * @param args - */ - public static void main(String[] args) { - Object x = new Object(); - DemandPATestUtil.testThisVar(x); - } - -} +/******************************************************************************* + * 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. + * + * This file is a derivative of code released by the University of + * California under the terms listed below. + * + * Refinement Analysis Tools is Copyright (c) 2007 The Regents of the + * University of California (Regents). Provided that this notice and + * the following two paragraphs are included in any distribution of + * Refinement Analysis Tools or its derivative work, Regents agrees + * not to assert any of Regents' copyright rights in Refinement + * Analysis Tools against recipient for recipient's reproduction, + * preparation of derivative works, public display, public + * performance, distribution or sublicensing of Refinement Analysis + * Tools and derivative works, in source code and object code form. + * This agreement not to assert does not confer, by implication, + * estoppel, or otherwise any license or rights in any intellectual + * property of Regents, including, but not limited to, any patents + * of Regents or Regents' employees. + * + * IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, + * INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, + * INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE + * AND ITS DOCUMENTATION, EVEN IF REGENTS HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE AND FURTHER DISCLAIMS ANY STATUTORY + * WARRANTY OF NON-INFRINGEMENT. THE SOFTWARE AND ACCOMPANYING + * DOCUMENTATION, IF ANY, PROVIDED HEREUNDER IS PROVIDED "AS + * IS". REGENTS HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, + * UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + */ +package demandpa; + +public class TestLocals { + + /** + * @param args + */ + public static void main(String[] args) { + Object x = new Object(); + DemandPATestUtil.testThisVar(x); + } + +} diff --git a/com.ibm.wala.core.testdata/src/demandpa/TestMethodRecursion.java b/com.ibm.wala.core.testdata/src/demandpa/TestMethodRecursion.java index 96603039d..730196f03 100644 --- a/com.ibm.wala.core.testdata/src/demandpa/TestMethodRecursion.java +++ b/com.ibm.wala.core.testdata/src/demandpa/TestMethodRecursion.java @@ -1,69 +1,69 @@ -/******************************************************************************* - * 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. - * - * This file is a derivative of code released by the University of - * California under the terms listed below. - * - * Refinement Analysis Tools is Copyright (c) 2007 The Regents of the - * University of California (Regents). Provided that this notice and - * the following two paragraphs are included in any distribution of - * Refinement Analysis Tools or its derivative work, Regents agrees - * not to assert any of Regents' copyright rights in Refinement - * Analysis Tools against recipient for recipient's reproduction, - * preparation of derivative works, public display, public - * performance, distribution or sublicensing of Refinement Analysis - * Tools and derivative works, in source code and object code form. - * This agreement not to assert does not confer, by implication, - * estoppel, or otherwise any license or rights in any intellectual - * property of Regents, including, but not limited to, any patents - * of Regents or Regents' employees. - * - * IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, - * INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, - * INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE - * AND ITS DOCUMENTATION, EVEN IF REGENTS HAS BEEN ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE AND FURTHER DISCLAIMS ANY STATUTORY - * WARRANTY OF NON-INFRINGEMENT. THE SOFTWARE AND ACCOMPANYING - * DOCUMENTATION, IF ANY, PROVIDED HEREUNDER IS PROVIDED "AS - * IS". REGENTS HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, - * UPDATES, ENHANCEMENTS, OR MODIFICATIONS. - */ - -package demandpa; - -public class TestMethodRecursion { - - static Object foo(Object p1, Object p2, boolean b) { - if (b) { - return p1; - } else { - return bar(id(p2), p1, !b); - } - } - - static Object choose(Object o1, Object o2, boolean b) { - return foo(o1, o2, b); - } - - static Object bar(Object p1, Object p2, boolean b) { - return choose(p1, p2, b); - } - - static Object id(Object x) { - return x; - } - - public static void main(String[] args) { - Object o1 = new Object(); - Object o2 = new Object(); - Object o3 = foo(o1, o2, false); - DemandPATestUtil.testThisVar(o3); - } +/******************************************************************************* + * 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. + * + * This file is a derivative of code released by the University of + * California under the terms listed below. + * + * Refinement Analysis Tools is Copyright (c) 2007 The Regents of the + * University of California (Regents). Provided that this notice and + * the following two paragraphs are included in any distribution of + * Refinement Analysis Tools or its derivative work, Regents agrees + * not to assert any of Regents' copyright rights in Refinement + * Analysis Tools against recipient for recipient's reproduction, + * preparation of derivative works, public display, public + * performance, distribution or sublicensing of Refinement Analysis + * Tools and derivative works, in source code and object code form. + * This agreement not to assert does not confer, by implication, + * estoppel, or otherwise any license or rights in any intellectual + * property of Regents, including, but not limited to, any patents + * of Regents or Regents' employees. + * + * IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, + * INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, + * INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE + * AND ITS DOCUMENTATION, EVEN IF REGENTS HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE AND FURTHER DISCLAIMS ANY STATUTORY + * WARRANTY OF NON-INFRINGEMENT. THE SOFTWARE AND ACCOMPANYING + * DOCUMENTATION, IF ANY, PROVIDED HEREUNDER IS PROVIDED "AS + * IS". REGENTS HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, + * UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + */ + +package demandpa; + +public class TestMethodRecursion { + + static Object foo(Object p1, Object p2, boolean b) { + if (b) { + return p1; + } else { + return bar(id(p2), p1, !b); + } + } + + static Object choose(Object o1, Object o2, boolean b) { + return foo(o1, o2, b); + } + + static Object bar(Object p1, Object p2, boolean b) { + return choose(p1, p2, b); + } + + static Object id(Object x) { + return x; + } + + public static void main(String[] args) { + Object o1 = new Object(); + Object o2 = new Object(); + Object o3 = foo(o1, o2, false); + DemandPATestUtil.testThisVar(o3); + } } \ No newline at end of file diff --git a/com.ibm.wala.core.testdata/src/demandpa/TestMultiDim.java b/com.ibm.wala.core.testdata/src/demandpa/TestMultiDim.java index f6338d35d..d02aa910a 100644 --- a/com.ibm.wala.core.testdata/src/demandpa/TestMultiDim.java +++ b/com.ibm.wala.core.testdata/src/demandpa/TestMultiDim.java @@ -1,53 +1,53 @@ -/******************************************************************************* - * 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. - * - * This file is a derivative of code released by the University of - * California under the terms listed below. - * - * Refinement Analysis Tools is Copyright (c) 2007 The Regents of the - * University of California (Regents). Provided that this notice and - * the following two paragraphs are included in any distribution of - * Refinement Analysis Tools or its derivative work, Regents agrees - * not to assert any of Regents' copyright rights in Refinement - * Analysis Tools against recipient for recipient's reproduction, - * preparation of derivative works, public display, public - * performance, distribution or sublicensing of Refinement Analysis - * Tools and derivative works, in source code and object code form. - * This agreement not to assert does not confer, by implication, - * estoppel, or otherwise any license or rights in any intellectual - * property of Regents, including, but not limited to, any patents - * of Regents or Regents' employees. - * - * IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, - * INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, - * INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE - * AND ITS DOCUMENTATION, EVEN IF REGENTS HAS BEEN ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE AND FURTHER DISCLAIMS ANY STATUTORY - * WARRANTY OF NON-INFRINGEMENT. THE SOFTWARE AND ACCOMPANYING - * DOCUMENTATION, IF ANY, PROVIDED HEREUNDER IS PROVIDED "AS - * IS". REGENTS HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, - * UPDATES, ENHANCEMENTS, OR MODIFICATIONS. - */ -package demandpa; - -public class TestMultiDim { - - /** - * @param args - */ - public static void main(String[] args) { - Object[][][] multi = new Object[10][10][10]; - multi[0] = new Object[10][10]; - Object[][] t = multi[0]; - Object[] t2 = t[0]; - DemandPATestUtil.testThisVar(t2); - } - -} +/******************************************************************************* + * 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. + * + * This file is a derivative of code released by the University of + * California under the terms listed below. + * + * Refinement Analysis Tools is Copyright (c) 2007 The Regents of the + * University of California (Regents). Provided that this notice and + * the following two paragraphs are included in any distribution of + * Refinement Analysis Tools or its derivative work, Regents agrees + * not to assert any of Regents' copyright rights in Refinement + * Analysis Tools against recipient for recipient's reproduction, + * preparation of derivative works, public display, public + * performance, distribution or sublicensing of Refinement Analysis + * Tools and derivative works, in source code and object code form. + * This agreement not to assert does not confer, by implication, + * estoppel, or otherwise any license or rights in any intellectual + * property of Regents, including, but not limited to, any patents + * of Regents or Regents' employees. + * + * IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, + * INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, + * INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE + * AND ITS DOCUMENTATION, EVEN IF REGENTS HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE AND FURTHER DISCLAIMS ANY STATUTORY + * WARRANTY OF NON-INFRINGEMENT. THE SOFTWARE AND ACCOMPANYING + * DOCUMENTATION, IF ANY, PROVIDED HEREUNDER IS PROVIDED "AS + * IS". REGENTS HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, + * UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + */ +package demandpa; + +public class TestMultiDim { + + /** + * @param args + */ + public static void main(String[] args) { + Object[][][] multi = new Object[10][10][10]; + multi[0] = new Object[10][10]; + Object[][] t = multi[0]; + Object[] t2 = t[0]; + DemandPATestUtil.testThisVar(t2); + } + +} diff --git a/com.ibm.wala.core.testdata/src/demandpa/TestNastyPtrs.java b/com.ibm.wala.core.testdata/src/demandpa/TestNastyPtrs.java index 97888e043..f3c3864d5 100644 --- a/com.ibm.wala.core.testdata/src/demandpa/TestNastyPtrs.java +++ b/com.ibm.wala.core.testdata/src/demandpa/TestNastyPtrs.java @@ -1,105 +1,105 @@ -/******************************************************************************* - * 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. - * - * This file is a derivative of code released by the University of - * California under the terms listed below. - * - * Refinement Analysis Tools is Copyright (c) 2007 The Regents of the - * University of California (Regents). Provided that this notice and - * the following two paragraphs are included in any distribution of - * Refinement Analysis Tools or its derivative work, Regents agrees - * not to assert any of Regents' copyright rights in Refinement - * Analysis Tools against recipient for recipient's reproduction, - * preparation of derivative works, public display, public - * performance, distribution or sublicensing of Refinement Analysis - * Tools and derivative works, in source code and object code form. - * This agreement not to assert does not confer, by implication, - * estoppel, or otherwise any license or rights in any intellectual - * property of Regents, including, but not limited to, any patents - * of Regents or Regents' employees. - * - * IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, - * INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, - * INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE - * AND ITS DOCUMENTATION, EVEN IF REGENTS HAS BEEN ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE AND FURTHER DISCLAIMS ANY STATUTORY - * WARRANTY OF NON-INFRINGEMENT. THE SOFTWARE AND ACCOMPANYING - * DOCUMENTATION, IF ANY, PROVIDED HEREUNDER IS PROVIDED "AS - * IS". REGENTS HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, - * UPDATES, ENHANCEMENTS, OR MODIFICATIONS. - */ -package demandpa; - -class TestNastyPtrs { - - static class A { - - A next0; - - A next1; - - A next2; - - A next3; - - A next4; - - A next5; - - A next6; - - A next7; - - A next8; - - A next9; - - } - - public static void main(String[] args) { - - A a0 = new A(); - A a1 = new A(); - A a2 = new A(); - A a3 = new A(); - A a4 = new A(); - A a5 = new A(); - A a6 = new A(); - A a7 = new A(); - A a8 = new A(); - A a9 = new A(); - a0.next0 = a1; - a1.next0 = a2; - a2.next0 = a3; - a3.next0 = a4; - a4.next0 = a5; - a5.next0 = a6; - a6.next0 = a7; - a7.next0 = a8; - a8.next0 = a9; - - A x = a0; - while (args[0] != null) { - x = x.next0; - } - x.next0 = x; - x.next1 = x; - x.next2 = x; - x.next3 = x; - x.next4 = x; - x.next5 = x; - x.next6 = x; - x.next7 = x; - x.next8 = x; - x.next9 = x; - - DemandPATestUtil.testThisVar(x); - } -} +/******************************************************************************* + * 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. + * + * This file is a derivative of code released by the University of + * California under the terms listed below. + * + * Refinement Analysis Tools is Copyright (c) 2007 The Regents of the + * University of California (Regents). Provided that this notice and + * the following two paragraphs are included in any distribution of + * Refinement Analysis Tools or its derivative work, Regents agrees + * not to assert any of Regents' copyright rights in Refinement + * Analysis Tools against recipient for recipient's reproduction, + * preparation of derivative works, public display, public + * performance, distribution or sublicensing of Refinement Analysis + * Tools and derivative works, in source code and object code form. + * This agreement not to assert does not confer, by implication, + * estoppel, or otherwise any license or rights in any intellectual + * property of Regents, including, but not limited to, any patents + * of Regents or Regents' employees. + * + * IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, + * INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, + * INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE + * AND ITS DOCUMENTATION, EVEN IF REGENTS HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE AND FURTHER DISCLAIMS ANY STATUTORY + * WARRANTY OF NON-INFRINGEMENT. THE SOFTWARE AND ACCOMPANYING + * DOCUMENTATION, IF ANY, PROVIDED HEREUNDER IS PROVIDED "AS + * IS". REGENTS HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, + * UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + */ +package demandpa; + +class TestNastyPtrs { + + static class A { + + A next0; + + A next1; + + A next2; + + A next3; + + A next4; + + A next5; + + A next6; + + A next7; + + A next8; + + A next9; + + } + + public static void main(String[] args) { + + A a0 = new A(); + A a1 = new A(); + A a2 = new A(); + A a3 = new A(); + A a4 = new A(); + A a5 = new A(); + A a6 = new A(); + A a7 = new A(); + A a8 = new A(); + A a9 = new A(); + a0.next0 = a1; + a1.next0 = a2; + a2.next0 = a3; + a3.next0 = a4; + a4.next0 = a5; + a5.next0 = a6; + a6.next0 = a7; + a7.next0 = a8; + a8.next0 = a9; + + A x = a0; + while (args[0] != null) { + x = x.next0; + } + x.next0 = x; + x.next1 = x; + x.next2 = x; + x.next3 = x; + x.next4 = x; + x.next5 = x; + x.next6 = x; + x.next7 = x; + x.next8 = x; + x.next9 = x; + + DemandPATestUtil.testThisVar(x); + } +} diff --git a/com.ibm.wala.core.testdata/src/demandpa/TestOnTheFlyCS.java b/com.ibm.wala.core.testdata/src/demandpa/TestOnTheFlyCS.java index 61f2c0fc4..e11fddd24 100644 --- a/com.ibm.wala.core.testdata/src/demandpa/TestOnTheFlyCS.java +++ b/com.ibm.wala.core.testdata/src/demandpa/TestOnTheFlyCS.java @@ -1,67 +1,67 @@ -/******************************************************************************* - * 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. - * - * This file is a derivative of code released by the University of - * California under the terms listed below. - * - * Refinement Analysis Tools is Copyright (c) 2007 The Regents of the - * University of California (Regents). Provided that this notice and - * the following two paragraphs are included in any distribution of - * Refinement Analysis Tools or its derivative work, Regents agrees - * not to assert any of Regents' copyright rights in Refinement - * Analysis Tools against recipient for recipient's reproduction, - * preparation of derivative works, public display, public - * performance, distribution or sublicensing of Refinement Analysis - * Tools and derivative works, in source code and object code form. - * This agreement not to assert does not confer, by implication, - * estoppel, or otherwise any license or rights in any intellectual - * property of Regents, including, but not limited to, any patents - * of Regents or Regents' employees. - * - * IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, - * INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, - * INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE - * AND ITS DOCUMENTATION, EVEN IF REGENTS HAS BEEN ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE AND FURTHER DISCLAIMS ANY STATUTORY - * WARRANTY OF NON-INFRINGEMENT. THE SOFTWARE AND ACCOMPANYING - * DOCUMENTATION, IF ANY, PROVIDED HEREUNDER IS PROVIDED "AS - * IS". REGENTS HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, - * UPDATES, ENHANCEMENTS, OR MODIFICATIONS. - */ -package demandpa; - -public class TestOnTheFlyCS { - - static class C1 { - void doSomething(Object o) { - - } - } - - static class C2 extends C1 { - @Override - void doSomething(Object o) { - DemandPATestUtil.testThisVar(o); - } - } - - private static void callDoSomething(C1 c1, Object o) { - c1.doSomething(o); - } - - /** - * @param args - */ - public static void main(String[] args) { - callDoSomething(new C1(), new Object()); - callDoSomething(new C2(), new Object()); - } - -} +/******************************************************************************* + * 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. + * + * This file is a derivative of code released by the University of + * California under the terms listed below. + * + * Refinement Analysis Tools is Copyright (c) 2007 The Regents of the + * University of California (Regents). Provided that this notice and + * the following two paragraphs are included in any distribution of + * Refinement Analysis Tools or its derivative work, Regents agrees + * not to assert any of Regents' copyright rights in Refinement + * Analysis Tools against recipient for recipient's reproduction, + * preparation of derivative works, public display, public + * performance, distribution or sublicensing of Refinement Analysis + * Tools and derivative works, in source code and object code form. + * This agreement not to assert does not confer, by implication, + * estoppel, or otherwise any license or rights in any intellectual + * property of Regents, including, but not limited to, any patents + * of Regents or Regents' employees. + * + * IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, + * INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, + * INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE + * AND ITS DOCUMENTATION, EVEN IF REGENTS HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE AND FURTHER DISCLAIMS ANY STATUTORY + * WARRANTY OF NON-INFRINGEMENT. THE SOFTWARE AND ACCOMPANYING + * DOCUMENTATION, IF ANY, PROVIDED HEREUNDER IS PROVIDED "AS + * IS". REGENTS HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, + * UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + */ +package demandpa; + +public class TestOnTheFlyCS { + + static class C1 { + void doSomething(Object o) { + + } + } + + static class C2 extends C1 { + @Override + void doSomething(Object o) { + DemandPATestUtil.testThisVar(o); + } + } + + private static void callDoSomething(C1 c1, Object o) { + c1.doSomething(o); + } + + /** + * @param args + */ + public static void main(String[] args) { + callDoSomething(new C1(), new Object()); + callDoSomething(new C2(), new Object()); + } + +} diff --git a/com.ibm.wala.core.testdata/src/demandpa/TestOnTheFlySimple.java b/com.ibm.wala.core.testdata/src/demandpa/TestOnTheFlySimple.java index 8bcfdd927..0ed34e463 100644 --- a/com.ibm.wala.core.testdata/src/demandpa/TestOnTheFlySimple.java +++ b/com.ibm.wala.core.testdata/src/demandpa/TestOnTheFlySimple.java @@ -1,61 +1,61 @@ -/******************************************************************************* - * 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. - * - * This file is a derivative of code released by the University of - * California under the terms listed below. - * - * Refinement Analysis Tools is Copyright (c) 2007 The Regents of the - * University of California (Regents). Provided that this notice and - * the following two paragraphs are included in any distribution of - * Refinement Analysis Tools or its derivative work, Regents agrees - * not to assert any of Regents' copyright rights in Refinement - * Analysis Tools against recipient for recipient's reproduction, - * preparation of derivative works, public display, public - * performance, distribution or sublicensing of Refinement Analysis - * Tools and derivative works, in source code and object code form. - * This agreement not to assert does not confer, by implication, - * estoppel, or otherwise any license or rights in any intellectual - * property of Regents, including, but not limited to, any patents - * of Regents or Regents' employees. - * - * IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, - * INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, - * INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE - * AND ITS DOCUMENTATION, EVEN IF REGENTS HAS BEEN ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE AND FURTHER DISCLAIMS ANY STATUTORY - * WARRANTY OF NON-INFRINGEMENT. THE SOFTWARE AND ACCOMPANYING - * DOCUMENTATION, IF ANY, PROVIDED HEREUNDER IS PROVIDED "AS - * IS". REGENTS HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, - * UPDATES, ENHANCEMENTS, OR MODIFICATIONS. - */ -package demandpa; - -/** - * @author manu - * - */ -public class TestOnTheFlySimple { - - static A makeA() { - return new B(); - } - - /** - * @param args - */ - public static void main(String[] args) { - A a2 = new A(); - DemandPATestUtil.makeVarUsed(a2); - A a = makeA(); - Object o = a.foo(); - DemandPATestUtil.testThisVar(o); - } - -} +/******************************************************************************* + * 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. + * + * This file is a derivative of code released by the University of + * California under the terms listed below. + * + * Refinement Analysis Tools is Copyright (c) 2007 The Regents of the + * University of California (Regents). Provided that this notice and + * the following two paragraphs are included in any distribution of + * Refinement Analysis Tools or its derivative work, Regents agrees + * not to assert any of Regents' copyright rights in Refinement + * Analysis Tools against recipient for recipient's reproduction, + * preparation of derivative works, public display, public + * performance, distribution or sublicensing of Refinement Analysis + * Tools and derivative works, in source code and object code form. + * This agreement not to assert does not confer, by implication, + * estoppel, or otherwise any license or rights in any intellectual + * property of Regents, including, but not limited to, any patents + * of Regents or Regents' employees. + * + * IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, + * INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, + * INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE + * AND ITS DOCUMENTATION, EVEN IF REGENTS HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE AND FURTHER DISCLAIMS ANY STATUTORY + * WARRANTY OF NON-INFRINGEMENT. THE SOFTWARE AND ACCOMPANYING + * DOCUMENTATION, IF ANY, PROVIDED HEREUNDER IS PROVIDED "AS + * IS". REGENTS HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, + * UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + */ +package demandpa; + +/** + * @author manu + * + */ +public class TestOnTheFlySimple { + + static A makeA() { + return new B(); + } + + /** + * @param args + */ + public static void main(String[] args) { + A a2 = new A(); + DemandPATestUtil.makeVarUsed(a2); + A a = makeA(); + Object o = a.foo(); + DemandPATestUtil.testThisVar(o); + } + +} diff --git a/com.ibm.wala.core.testdata/src/demandpa/TestWithinMethodCall.java b/com.ibm.wala.core.testdata/src/demandpa/TestWithinMethodCall.java index 592cdb147..6c5ddcc0d 100644 --- a/com.ibm.wala.core.testdata/src/demandpa/TestWithinMethodCall.java +++ b/com.ibm.wala.core.testdata/src/demandpa/TestWithinMethodCall.java @@ -1,53 +1,53 @@ -/******************************************************************************* - * 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. - * - * This file is a derivative of code released by the University of - * California under the terms listed below. - * - * Refinement Analysis Tools is Copyright (c) 2007 The Regents of the - * University of California (Regents). Provided that this notice and - * the following two paragraphs are included in any distribution of - * Refinement Analysis Tools or its derivative work, Regents agrees - * not to assert any of Regents' copyright rights in Refinement - * Analysis Tools against recipient for recipient's reproduction, - * preparation of derivative works, public display, public - * performance, distribution or sublicensing of Refinement Analysis - * Tools and derivative works, in source code and object code form. - * This agreement not to assert does not confer, by implication, - * estoppel, or otherwise any license or rights in any intellectual - * property of Regents, including, but not limited to, any patents - * of Regents or Regents' employees. - * - * IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, - * INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, - * INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE - * AND ITS DOCUMENTATION, EVEN IF REGENTS HAS BEEN ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE AND FURTHER DISCLAIMS ANY STATUTORY - * WARRANTY OF NON-INFRINGEMENT. THE SOFTWARE AND ACCOMPANYING - * DOCUMENTATION, IF ANY, PROVIDED HEREUNDER IS PROVIDED "AS - * IS". REGENTS HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, - * UPDATES, ENHANCEMENTS, OR MODIFICATIONS. - */ -package demandpa; - -public class TestWithinMethodCall { - - /** - * @param args - */ - public static void main(String[] args) { - Object o = new Object(); - testMethod(o); - } - - private static void testMethod(Object o) { - DemandPATestUtil.testThisVar(o); - } -} +/******************************************************************************* + * 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. + * + * This file is a derivative of code released by the University of + * California under the terms listed below. + * + * Refinement Analysis Tools is Copyright (c) 2007 The Regents of the + * University of California (Regents). Provided that this notice and + * the following two paragraphs are included in any distribution of + * Refinement Analysis Tools or its derivative work, Regents agrees + * not to assert any of Regents' copyright rights in Refinement + * Analysis Tools against recipient for recipient's reproduction, + * preparation of derivative works, public display, public + * performance, distribution or sublicensing of Refinement Analysis + * Tools and derivative works, in source code and object code form. + * This agreement not to assert does not confer, by implication, + * estoppel, or otherwise any license or rights in any intellectual + * property of Regents, including, but not limited to, any patents + * of Regents or Regents' employees. + * + * IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, + * INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, + * INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE + * AND ITS DOCUMENTATION, EVEN IF REGENTS HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE AND FURTHER DISCLAIMS ANY STATUTORY + * WARRANTY OF NON-INFRINGEMENT. THE SOFTWARE AND ACCOMPANYING + * DOCUMENTATION, IF ANY, PROVIDED HEREUNDER IS PROVIDED "AS + * IS". REGENTS HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, + * UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + */ +package demandpa; + +public class TestWithinMethodCall { + + /** + * @param args + */ + public static void main(String[] args) { + Object o = new Object(); + testMethod(o); + } + + private static void testMethod(Object o) { + DemandPATestUtil.testThisVar(o); + } +} diff --git a/com.ibm.wala.core.testdata/src/hello/Hello.java b/com.ibm.wala.core.testdata/src/hello/Hello.java index 6af153f01..7b3ffaa8f 100644 --- a/com.ibm.wala.core.testdata/src/hello/Hello.java +++ b/com.ibm.wala.core.testdata/src/hello/Hello.java @@ -1,22 +1,22 @@ -/******************************************************************************* - * 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 hello; - -public class Hello { - - /** - * @param args - */ - public static void main(String[] args) { - System.out.println("Hello world"); - } - -} +/******************************************************************************* + * 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 hello; + +public class Hello { + + /** + * @param args + */ + public static void main(String[] args) { + System.out.println("Hello world"); + } + +} diff --git a/com.ibm.wala.core.testdata/src/messageFormatTest/MessageFormatBench.java b/com.ibm.wala.core.testdata/src/messageFormatTest/MessageFormatBench.java index c1b2865b9..2e8ea537c 100644 --- a/com.ibm.wala.core.testdata/src/messageFormatTest/MessageFormatBench.java +++ b/com.ibm.wala.core.testdata/src/messageFormatTest/MessageFormatBench.java @@ -1,23 +1,23 @@ -/******************************************************************************* - * 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 messageFormatTest; - -import java.text.MessageFormat; - -public class MessageFormatBench { - public static void main(String[] args) { - Object[] testArgs = {new Long(3), "MyDisk"}; - MessageFormat form = new MessageFormat("The disk \"{1}\" contains {0} file(s)."); - MessageFormat form2 = (MessageFormat) form.clone(); - System.out.println(form2.format(testArgs)); - } - -} +/******************************************************************************* + * 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 messageFormatTest; + +import java.text.MessageFormat; + +public class MessageFormatBench { + public static void main(String[] args) { + Object[] testArgs = {new Long(3), "MyDisk"}; + MessageFormat form = new MessageFormat("The disk \"{1}\" contains {0} file(s)."); + MessageFormat form2 = (MessageFormat) form.clone(); + System.out.println(form2.format(testArgs)); + } + +} diff --git a/com.ibm.wala.core.testdata/src/multiDim/TestMultiDim.java b/com.ibm.wala.core.testdata/src/multiDim/TestMultiDim.java index db20632af..6fe61149c 100644 --- a/com.ibm.wala.core.testdata/src/multiDim/TestMultiDim.java +++ b/com.ibm.wala.core.testdata/src/multiDim/TestMultiDim.java @@ -1,22 +1,22 @@ -package multiDim; - -public class TestMultiDim { - - static void doNothing(Object o) {} - - public static void main(String[] args) { - Object[][] multi = new Object[10][]; - multi[0] = new Object[10]; - testMulti(multi); - } - - static void testMulti(Object[][] multi) { - Object[] t = multi[0]; - doNothing(t); - } - - static void testNewMultiArray() { - String[][][] x = new String[3][4][]; - doNothing(x); - } +package multiDim; + +public class TestMultiDim { + + static void doNothing(Object o) {} + + public static void main(String[] args) { + Object[][] multi = new Object[10][]; + multi[0] = new Object[10]; + testMulti(multi); + } + + static void testMulti(Object[][] multi) { + Object[] t = multi[0]; + doNothing(t); + } + + static void testNewMultiArray() { + String[][][] x = new String[3][4][]; + doNothing(x); + } } \ No newline at end of file diff --git a/com.ibm.wala.core.testdata/src/multiTypes/Foo.java b/com.ibm.wala.core.testdata/src/multiTypes/Foo.java index 5b9497c39..8085fc90a 100644 --- a/com.ibm.wala.core.testdata/src/multiTypes/Foo.java +++ b/com.ibm.wala.core.testdata/src/multiTypes/Foo.java @@ -1,35 +1,35 @@ -/******************************************************************************* - * Copyright (c) 2008 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 multiTypes; - -/** - * Test designed to exercise SubtypesEntrypoint when there is more than one possible type for an argument - * - * @author sjfink - * - */ -public class Foo { - - private static class A { - public void bar() { - } - } - - @SuppressWarnings("unused") - private static class B extends A { - public void bar() { - } - } - - public static void foo(A a) { - a.bar(); - } -} +/******************************************************************************* + * Copyright (c) 2008 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 multiTypes; + +/** + * Test designed to exercise SubtypesEntrypoint when there is more than one possible type for an argument + * + * @author sjfink + * + */ +public class Foo { + + private static class A { + public void bar() { + } + } + + @SuppressWarnings("unused") + private static class B extends A { + public void bar() { + } + } + + public static void foo(A a) { + a.bar(); + } +} diff --git a/com.ibm.wala.core.testdata/src/pi/PiNodeCallGraphTestCase.java b/com.ibm.wala.core.testdata/src/pi/PiNodeCallGraphTestCase.java index 900fe8345..c95ec7b25 100644 --- a/com.ibm.wala.core.testdata/src/pi/PiNodeCallGraphTestCase.java +++ b/com.ibm.wala.core.testdata/src/pi/PiNodeCallGraphTestCase.java @@ -1,72 +1,72 @@ -/******************************************************************************* - * 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 pi; - -class PiNodeCallGraphTestCase { - - interface Whatever { - - void unary1(); - - void unary2(); - - void binary(Whatever arg); - - } - - static class This implements Whatever { - - public void unary1() { - unary2(); - } - - public void unary2() { - - } - - public void binary(Whatever arg) { - this.unary1(); - arg.unary2(); - } - - } - - static class That implements Whatever { - - public void unary1() { - - } - - public void unary2() { - unary1(); - } - - public void binary(Whatever arg) { - this.unary1(); - arg.unary2(); - } - - } - - public native static boolean choice(); - - public static void main(String[] args) { - Whatever x = new This(); - Whatever y = new That(); - Whatever z = choice()? x: y; - - if (z instanceof This) - x.binary(z); - else - y.binary(z); - } - -} +/******************************************************************************* + * 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 pi; + +class PiNodeCallGraphTestCase { + + interface Whatever { + + void unary1(); + + void unary2(); + + void binary(Whatever arg); + + } + + static class This implements Whatever { + + public void unary1() { + unary2(); + } + + public void unary2() { + + } + + public void binary(Whatever arg) { + this.unary1(); + arg.unary2(); + } + + } + + static class That implements Whatever { + + public void unary1() { + + } + + public void unary2() { + unary1(); + } + + public void binary(Whatever arg) { + this.unary1(); + arg.unary2(); + } + + } + + public native static boolean choice(); + + public static void main(String[] args) { + Whatever x = new This(); + Whatever y = new That(); + Whatever z = choice()? x: y; + + if (z instanceof This) + x.binary(z); + else + y.binary(z); + } + +} diff --git a/com.ibm.wala.core.testdata/src/recurse/NList.java b/com.ibm.wala.core.testdata/src/recurse/NList.java index e74adde8e..427e0dde1 100644 --- a/com.ibm.wala.core.testdata/src/recurse/NList.java +++ b/com.ibm.wala.core.testdata/src/recurse/NList.java @@ -1,142 +1,142 @@ -/******************************************************************************* - * 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 recurse; - -import java.util.Collection; -import java.util.Iterator; - -/** - * @author sfink - * - * A simple exercise in recursive data structures. - */ -public class NList implements Collection { - - final int value; - final NList next; - - public NList(int value) { - this.value = value; - if (value > 0) { - this.next = new NList(value - 1); - } else { - this.next = null; - } - } - - - public static void main(String[] args) { - new NList(100); - } - - /* (non-Javadoc) - * @see java.util.Collection#size() - */ - public int size() { - // TODO Auto-generated method stub - return 0; - } - - /* (non-Javadoc) - * @see java.util.Collection#isEmpty() - */ - public boolean isEmpty() { - // TODO Auto-generated method stub - return false; - } - - /* (non-Javadoc) - * @see java.util.Collection#contains(java.lang.Object) - */ - public boolean contains(Object o) { - // TODO Auto-generated method stub - return false; - } - - /* (non-Javadoc) - * @see java.util.Collection#iterator() - */ - public Iterator iterator() { - // TODO Auto-generated method stub - return null; - } - - /* (non-Javadoc) - * @see java.util.Collection#toArray() - */ - public Object[] toArray() { - // TODO Auto-generated method stub - return null; - } - - - /* (non-Javadoc) - * @see java.util.Collection#add(java.lang.Object) - */ - public boolean add(Object o) { - // TODO Auto-generated method stub - return false; - } - - /* (non-Javadoc) - * @see java.util.Collection#remove(java.lang.Object) - */ - public boolean remove(Object o) { - // TODO Auto-generated method stub - return false; - } - - /* (non-Javadoc) - * @see java.util.Collection#containsAll(java.util.Collection) - */ - public boolean containsAll(Collection c) { - // TODO Auto-generated method stub - return false; - } - - /* (non-Javadoc) - * @see java.util.Collection#addAll(java.util.Collection) - */ - public boolean addAll(Collection c) { - // TODO Auto-generated method stub - return false; - } - - /* (non-Javadoc) - * @see java.util.Collection#removeAll(java.util.Collection) - */ - public boolean removeAll(Collection c) { - // TODO Auto-generated method stub - return false; - } - - /* (non-Javadoc) - * @see java.util.Collection#retainAll(java.util.Collection) - */ - public boolean retainAll(Collection c) { - // TODO Auto-generated method stub - return false; - } - - /* (non-Javadoc) - * @see java.util.Collection#clear() - */ - public void clear() { - // TODO Auto-generated method stub - - } - - - public Object[] toArray(Object[] a) { - // TODO Auto-generated method stub - return null; - } -} +/******************************************************************************* + * 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 recurse; + +import java.util.Collection; +import java.util.Iterator; + +/** + * @author sfink + * + * A simple exercise in recursive data structures. + */ +public class NList implements Collection { + + final int value; + final NList next; + + public NList(int value) { + this.value = value; + if (value > 0) { + this.next = new NList(value - 1); + } else { + this.next = null; + } + } + + + public static void main(String[] args) { + new NList(100); + } + + /* (non-Javadoc) + * @see java.util.Collection#size() + */ + public int size() { + // TODO Auto-generated method stub + return 0; + } + + /* (non-Javadoc) + * @see java.util.Collection#isEmpty() + */ + public boolean isEmpty() { + // TODO Auto-generated method stub + return false; + } + + /* (non-Javadoc) + * @see java.util.Collection#contains(java.lang.Object) + */ + public boolean contains(Object o) { + // TODO Auto-generated method stub + return false; + } + + /* (non-Javadoc) + * @see java.util.Collection#iterator() + */ + public Iterator iterator() { + // TODO Auto-generated method stub + return null; + } + + /* (non-Javadoc) + * @see java.util.Collection#toArray() + */ + public Object[] toArray() { + // TODO Auto-generated method stub + return null; + } + + + /* (non-Javadoc) + * @see java.util.Collection#add(java.lang.Object) + */ + public boolean add(Object o) { + // TODO Auto-generated method stub + return false; + } + + /* (non-Javadoc) + * @see java.util.Collection#remove(java.lang.Object) + */ + public boolean remove(Object o) { + // TODO Auto-generated method stub + return false; + } + + /* (non-Javadoc) + * @see java.util.Collection#containsAll(java.util.Collection) + */ + public boolean containsAll(Collection c) { + // TODO Auto-generated method stub + return false; + } + + /* (non-Javadoc) + * @see java.util.Collection#addAll(java.util.Collection) + */ + public boolean addAll(Collection c) { + // TODO Auto-generated method stub + return false; + } + + /* (non-Javadoc) + * @see java.util.Collection#removeAll(java.util.Collection) + */ + public boolean removeAll(Collection c) { + // TODO Auto-generated method stub + return false; + } + + /* (non-Javadoc) + * @see java.util.Collection#retainAll(java.util.Collection) + */ + public boolean retainAll(Collection c) { + // TODO Auto-generated method stub + return false; + } + + /* (non-Javadoc) + * @see java.util.Collection#clear() + */ + public void clear() { + // TODO Auto-generated method stub + + } + + + public Object[] toArray(Object[] a) { + // TODO Auto-generated method stub + return null; + } +} diff --git a/com.ibm.wala.core.testdata/src/reflection/Helper.java b/com.ibm.wala.core.testdata/src/reflection/Helper.java index edac62efe..e72006987 100644 --- a/com.ibm.wala.core.testdata/src/reflection/Helper.java +++ b/com.ibm.wala.core.testdata/src/reflection/Helper.java @@ -1,53 +1,53 @@ -package reflection; - -public class Helper { - @SuppressWarnings("unused") - private final Object a, b; - - public Helper() { - this.a = new Object(); - this.b = new Object(); - System.out.println("Helper constructor with no parameter invoked"); - } - - public Helper(Integer x) { - a = b = null; - x.toString(); - System.out.println(x); - } - - public Helper(Object a) { - this.a = a; - this.b = new Object(); - System.out.println("Helper constructor with one parameter invoked"); - } - - public Helper(Object a, Object b) { - this.a = a; - this.b = b; - System.out.println("Helper constructor with two parameters invoked"); - } - - public void m(Object a, Object b, Object c) { - System.out.println("m method invoked"); - } - public void n(Object a, Object b) { - System.out.println("n method invoked"); - } - public void o(Object a, Object b) { - System.out.println("o method invoked"); - } - public static void s(Object a, Object b) { - System.out.println("s method invoked"); - } - - public static void t(Integer x) { - x.toString(); - } - - public void u(Integer x) { - x.toString(); - System.out.println("u method invoked"); - } - -} +package reflection; + +public class Helper { + @SuppressWarnings("unused") + private final Object a, b; + + public Helper() { + this.a = new Object(); + this.b = new Object(); + System.out.println("Helper constructor with no parameter invoked"); + } + + public Helper(Integer x) { + a = b = null; + x.toString(); + System.out.println(x); + } + + public Helper(Object a) { + this.a = a; + this.b = new Object(); + System.out.println("Helper constructor with one parameter invoked"); + } + + public Helper(Object a, Object b) { + this.a = a; + this.b = b; + System.out.println("Helper constructor with two parameters invoked"); + } + + public void m(Object a, Object b, Object c) { + System.out.println("m method invoked"); + } + public void n(Object a, Object b) { + System.out.println("n method invoked"); + } + public void o(Object a, Object b) { + System.out.println("o method invoked"); + } + public static void s(Object a, Object b) { + System.out.println("s method invoked"); + } + + public static void t(Integer x) { + x.toString(); + } + + public void u(Integer x) { + x.toString(); + System.out.println("u method invoked"); + } + +} diff --git a/com.ibm.wala.core.testdata/src/reflection/Reflect1.java b/com.ibm.wala.core.testdata/src/reflection/Reflect1.java index 6bb15e103..d2f0c8f83 100644 --- a/com.ibm.wala.core.testdata/src/reflection/Reflect1.java +++ b/com.ibm.wala.core.testdata/src/reflection/Reflect1.java @@ -1,20 +1,20 @@ -/******************************************************************************* - * 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 reflection; - -public class Reflect1 { - - public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException { - Class c = Class.forName("java.lang.Integer"); - Integer i = (Integer)c.newInstance(); - System.err.println(i); - } -} +/******************************************************************************* + * 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 reflection; + +public class Reflect1 { + + public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException { + Class c = Class.forName("java.lang.Integer"); + Integer i = (Integer)c.newInstance(); + System.err.println(i); + } +} diff --git a/com.ibm.wala.core.testdata/src/reflection/Reflect10.java b/com.ibm.wala.core.testdata/src/reflection/Reflect10.java index 7541873c1..7dfa4535b 100644 --- a/com.ibm.wala.core.testdata/src/reflection/Reflect10.java +++ b/com.ibm.wala.core.testdata/src/reflection/Reflect10.java @@ -1,16 +1,16 @@ -package reflection; - -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; - -/** - * Test of Method.invoke - */ -public class Reflect10 { - public static void main(String[] args) throws ClassNotFoundException, IllegalArgumentException, InstantiationException, - IllegalAccessException, InvocationTargetException, SecurityException, NoSuchMethodException { - Class c = Class.forName("java.lang.Integer"); - Method[] m = c.getMethods(); - m[0].invoke(new Integer(2), new Object[] {}); - } -} +package reflection; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; + +/** + * Test of Method.invoke + */ +public class Reflect10 { + public static void main(String[] args) throws ClassNotFoundException, IllegalArgumentException, InstantiationException, + IllegalAccessException, InvocationTargetException, SecurityException, NoSuchMethodException { + Class c = Class.forName("java.lang.Integer"); + Method[] m = c.getMethods(); + m[0].invoke(new Integer(2), new Object[] {}); + } +} diff --git a/com.ibm.wala.core.testdata/src/reflection/Reflect11.java b/com.ibm.wala.core.testdata/src/reflection/Reflect11.java index 86d0cc984..bae906052 100644 --- a/com.ibm.wala.core.testdata/src/reflection/Reflect11.java +++ b/com.ibm.wala.core.testdata/src/reflection/Reflect11.java @@ -1,16 +1,16 @@ -package reflection; - -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; - -/** - * Test of Method.invoke - */ -public class Reflect11 { - public static void main(String[] args) throws ClassNotFoundException, IllegalArgumentException, InstantiationException, - IllegalAccessException, InvocationTargetException, SecurityException, NoSuchMethodException { - Class c = Class.forName("java.lang.Integer"); - Method[] m = c.getMethods(); - m[0].invoke(new Integer(2), (Object[]) args); - } -} +package reflection; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; + +/** + * Test of Method.invoke + */ +public class Reflect11 { + public static void main(String[] args) throws ClassNotFoundException, IllegalArgumentException, InstantiationException, + IllegalAccessException, InvocationTargetException, SecurityException, NoSuchMethodException { + Class c = Class.forName("java.lang.Integer"); + Method[] m = c.getMethods(); + m[0].invoke(new Integer(2), (Object[]) args); + } +} diff --git a/com.ibm.wala.core.testdata/src/reflection/Reflect12.java b/com.ibm.wala.core.testdata/src/reflection/Reflect12.java index 1a7a3af42..e71e16a46 100644 --- a/com.ibm.wala.core.testdata/src/reflection/Reflect12.java +++ b/com.ibm.wala.core.testdata/src/reflection/Reflect12.java @@ -1,16 +1,16 @@ -package reflection; - -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; - -/** - * Test of Method.invoke - */ -public class Reflect12 { - public static void main(String[] args) throws ClassNotFoundException, IllegalArgumentException, InstantiationException, - IllegalAccessException, InvocationTargetException, SecurityException, NoSuchMethodException { - Class c = Class.forName("reflection.Helper"); - Method[] m = c.getMethods(); - m[0].invoke(new Helper(), new Object[3]); - } -} +package reflection; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; + +/** + * Test of Method.invoke + */ +public class Reflect12 { + public static void main(String[] args) throws ClassNotFoundException, IllegalArgumentException, InstantiationException, + IllegalAccessException, InvocationTargetException, SecurityException, NoSuchMethodException { + Class c = Class.forName("reflection.Helper"); + Method[] m = c.getMethods(); + m[0].invoke(new Helper(), new Object[3]); + } +} diff --git a/com.ibm.wala.core.testdata/src/reflection/Reflect13.java b/com.ibm.wala.core.testdata/src/reflection/Reflect13.java index 3f76234e1..0a5e7caf9 100644 --- a/com.ibm.wala.core.testdata/src/reflection/Reflect13.java +++ b/com.ibm.wala.core.testdata/src/reflection/Reflect13.java @@ -1,17 +1,17 @@ -package reflection; - -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; - -/** - * Test of Method.invoke - */ -public class Reflect13 { - public static void main(String[] args) throws ClassNotFoundException, IllegalArgumentException, InstantiationException, - IllegalAccessException, InvocationTargetException, SecurityException, NoSuchMethodException { - Class c = Class.forName("reflection.Helper"); - Method[] m = c.getMethods(); - int length = new Integer(args[0]).intValue(); - m[0].invoke(new Helper(), new Object[length]); - } -} +package reflection; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; + +/** + * Test of Method.invoke + */ +public class Reflect13 { + public static void main(String[] args) throws ClassNotFoundException, IllegalArgumentException, InstantiationException, + IllegalAccessException, InvocationTargetException, SecurityException, NoSuchMethodException { + Class c = Class.forName("reflection.Helper"); + Method[] m = c.getMethods(); + int length = new Integer(args[0]).intValue(); + m[0].invoke(new Helper(), new Object[length]); + } +} diff --git a/com.ibm.wala.core.testdata/src/reflection/Reflect14.java b/com.ibm.wala.core.testdata/src/reflection/Reflect14.java index 3b2820941..f9fa3736b 100644 --- a/com.ibm.wala.core.testdata/src/reflection/Reflect14.java +++ b/com.ibm.wala.core.testdata/src/reflection/Reflect14.java @@ -1,22 +1,22 @@ -package reflection; - -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; -import java.lang.reflect.Modifier; - -/** - * Test of Method.invoke - */ -public class Reflect14 { - public static void main(String[] args) throws ClassNotFoundException, IllegalArgumentException, InstantiationException, - IllegalAccessException, InvocationTargetException, SecurityException, NoSuchMethodException { - Class c = Class.forName("reflection.Helper"); - Method[] ms = c.getMethods(); - for (Method m : ms) { - int mods = m.getModifiers(); - if (Modifier.isStatic(mods) && m.getParameterTypes().length == 2) { - m.invoke(null, new Object[2]); - } - } - } -} +package reflection; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; + +/** + * Test of Method.invoke + */ +public class Reflect14 { + public static void main(String[] args) throws ClassNotFoundException, IllegalArgumentException, InstantiationException, + IllegalAccessException, InvocationTargetException, SecurityException, NoSuchMethodException { + Class c = Class.forName("reflection.Helper"); + Method[] ms = c.getMethods(); + for (Method m : ms) { + int mods = m.getModifiers(); + if (Modifier.isStatic(mods) && m.getParameterTypes().length == 2) { + m.invoke(null, new Object[2]); + } + } + } +} diff --git a/com.ibm.wala.core.testdata/src/reflection/Reflect15.java b/com.ibm.wala.core.testdata/src/reflection/Reflect15.java index 3e995341a..ffbedf036 100644 --- a/com.ibm.wala.core.testdata/src/reflection/Reflect15.java +++ b/com.ibm.wala.core.testdata/src/reflection/Reflect15.java @@ -1,22 +1,22 @@ -package reflection; - -import java.lang.reflect.Constructor; -import java.lang.reflect.InvocationTargetException; - -/** - * Test of Class.getConstructors(). - */ -public class Reflect15 { - public static void main(String[] args) throws ClassNotFoundException, IllegalArgumentException, InstantiationException, - IllegalAccessException, InvocationTargetException { - Class c = Class.forName("reflection.Helper"); - Constructor[] ctors = c.getConstructors(); - Helper h = null; - for (Constructor ctor : ctors) { - if (ctor.getParameterTypes().length == 2) { - h = (Helper) ctor.newInstance(new Object[] {new Object(), new Object()}); - } - } - h.n(new Object(), new Object()); - } -} +package reflection; + +import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationTargetException; + +/** + * Test of Class.getConstructors(). + */ +public class Reflect15 { + public static void main(String[] args) throws ClassNotFoundException, IllegalArgumentException, InstantiationException, + IllegalAccessException, InvocationTargetException { + Class c = Class.forName("reflection.Helper"); + Constructor[] ctors = c.getConstructors(); + Helper h = null; + for (Constructor ctor : ctors) { + if (ctor.getParameterTypes().length == 2) { + h = (Helper) ctor.newInstance(new Object[] {new Object(), new Object()}); + } + } + h.n(new Object(), new Object()); + } +} diff --git a/com.ibm.wala.core.testdata/src/reflection/Reflect16.java b/com.ibm.wala.core.testdata/src/reflection/Reflect16.java index 7e3517951..6af939b47 100644 --- a/com.ibm.wala.core.testdata/src/reflection/Reflect16.java +++ b/com.ibm.wala.core.testdata/src/reflection/Reflect16.java @@ -1,17 +1,17 @@ -package reflection; - -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; - -/** - * Test of Method.invoke - */ -public class Reflect16 { - public static void main(String[] args) throws ClassNotFoundException, IllegalArgumentException, InstantiationException, - IllegalAccessException, InvocationTargetException, SecurityException, NoSuchMethodException { - Class c = Class.forName("reflection.Helper"); - Method m = c.getDeclaredMethod("t", new Class[] { Integer.class, Integer.class }); - Integer i = Integer.valueOf(0); - m.invoke(null, new Object[] { i}); - } -} +package reflection; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; + +/** + * Test of Method.invoke + */ +public class Reflect16 { + public static void main(String[] args) throws ClassNotFoundException, IllegalArgumentException, InstantiationException, + IllegalAccessException, InvocationTargetException, SecurityException, NoSuchMethodException { + Class c = Class.forName("reflection.Helper"); + Method m = c.getDeclaredMethod("t", new Class[] { Integer.class, Integer.class }); + Integer i = Integer.valueOf(0); + m.invoke(null, new Object[] { i}); + } +} diff --git a/com.ibm.wala.core.testdata/src/reflection/Reflect17.java b/com.ibm.wala.core.testdata/src/reflection/Reflect17.java index e7531988e..1c296c8e3 100644 --- a/com.ibm.wala.core.testdata/src/reflection/Reflect17.java +++ b/com.ibm.wala.core.testdata/src/reflection/Reflect17.java @@ -1,16 +1,16 @@ -package reflection; - -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; - -/** - * Test of Method.invoke - */ -public class Reflect17 { - public static void main(String[] args) throws ClassNotFoundException, IllegalArgumentException, InstantiationException, - IllegalAccessException, InvocationTargetException, SecurityException, NoSuchMethodException { - Class c = Class.forName("reflection.Helper"); - Method m = c.getDeclaredMethod("t", new Class[] { Integer.class, Integer.class }); - m.invoke(null, new Object[] { null }); - } -} +package reflection; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; + +/** + * Test of Method.invoke + */ +public class Reflect17 { + public static void main(String[] args) throws ClassNotFoundException, IllegalArgumentException, InstantiationException, + IllegalAccessException, InvocationTargetException, SecurityException, NoSuchMethodException { + Class c = Class.forName("reflection.Helper"); + Method m = c.getDeclaredMethod("t", new Class[] { Integer.class, Integer.class }); + m.invoke(null, new Object[] { null }); + } +} diff --git a/com.ibm.wala.core.testdata/src/reflection/Reflect18.java b/com.ibm.wala.core.testdata/src/reflection/Reflect18.java index 50e0f86ec..51c71bcb6 100644 --- a/com.ibm.wala.core.testdata/src/reflection/Reflect18.java +++ b/com.ibm.wala.core.testdata/src/reflection/Reflect18.java @@ -1,18 +1,18 @@ -package reflection; - -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; - -/** - * Test of Method.invoke - */ -public class Reflect18 { - public static void main(String[] args) throws ClassNotFoundException, IllegalArgumentException, InstantiationException, - IllegalAccessException, InvocationTargetException, SecurityException, NoSuchMethodException { - Class c = Class.forName("reflection.Helper"); - Method m = c.getDeclaredMethod("t", new Class[] { Integer.class, Integer.class }); - Integer i = Integer.valueOf(0); - Helper h = new Helper(); - m.invoke(h, new Object[] { i}); - } -} +package reflection; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; + +/** + * Test of Method.invoke + */ +public class Reflect18 { + public static void main(String[] args) throws ClassNotFoundException, IllegalArgumentException, InstantiationException, + IllegalAccessException, InvocationTargetException, SecurityException, NoSuchMethodException { + Class c = Class.forName("reflection.Helper"); + Method m = c.getDeclaredMethod("t", new Class[] { Integer.class, Integer.class }); + Integer i = Integer.valueOf(0); + Helper h = new Helper(); + m.invoke(h, new Object[] { i}); + } +} diff --git a/com.ibm.wala.core.testdata/src/reflection/Reflect19.java b/com.ibm.wala.core.testdata/src/reflection/Reflect19.java index f5fa5d80e..488173342 100644 --- a/com.ibm.wala.core.testdata/src/reflection/Reflect19.java +++ b/com.ibm.wala.core.testdata/src/reflection/Reflect19.java @@ -1,17 +1,17 @@ -package reflection; - -import java.lang.reflect.Constructor; -import java.lang.reflect.InvocationTargetException; - -/** - * Test of Constructor.newInstance - */ -public class Reflect19 { - public static void main(String[] args) throws ClassNotFoundException, IllegalArgumentException, InstantiationException, - IllegalAccessException, InvocationTargetException, SecurityException, NoSuchMethodException { - Class c = Class.forName("reflection.Helper"); - Constructor m = c.getConstructor(new Class[] { Integer.class }); - Integer i = Integer.valueOf(0); - m.newInstance(new Object[] { i }); - } -} +package reflection; + +import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationTargetException; + +/** + * Test of Constructor.newInstance + */ +public class Reflect19 { + public static void main(String[] args) throws ClassNotFoundException, IllegalArgumentException, InstantiationException, + IllegalAccessException, InvocationTargetException, SecurityException, NoSuchMethodException { + Class c = Class.forName("reflection.Helper"); + Constructor m = c.getConstructor(new Class[] { Integer.class }); + Integer i = Integer.valueOf(0); + m.newInstance(new Object[] { i }); + } +} diff --git a/com.ibm.wala.core.testdata/src/reflection/Reflect2.java b/com.ibm.wala.core.testdata/src/reflection/Reflect2.java index b16b1cb87..171c9b248 100644 --- a/com.ibm.wala.core.testdata/src/reflection/Reflect2.java +++ b/com.ibm.wala.core.testdata/src/reflection/Reflect2.java @@ -1,18 +1,18 @@ -/******************************************************************************* - * Copyright (c) 2008 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 reflection; - -public class Reflect2 { - - public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException { - Class.forName("java.lang.Integer"); - } -} +/******************************************************************************* + * Copyright (c) 2008 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 reflection; + +public class Reflect2 { + + public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException { + Class.forName("java.lang.Integer"); + } +} diff --git a/com.ibm.wala.core.testdata/src/reflection/Reflect20.java b/com.ibm.wala.core.testdata/src/reflection/Reflect20.java index b5b2d710e..d774233a7 100644 --- a/com.ibm.wala.core.testdata/src/reflection/Reflect20.java +++ b/com.ibm.wala.core.testdata/src/reflection/Reflect20.java @@ -1,22 +1,22 @@ -package reflection; - -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; - - -/** - * Test of Constructor.newInstance - */ -public class Reflect20 { - public static void main(String[] args) throws ClassNotFoundException, SecurityException, - NoSuchMethodException, IllegalAccessException, InstantiationException, - IllegalArgumentException, InvocationTargetException { - Class helperClass = Class.forName("reflection.Helper"); - Class objectClass = Class.forName("java.lang.Object"); - Class[] paramArrayTypes = new Class[]{objectClass, objectClass}; - Method m = helperClass.getMethod("o", paramArrayTypes); - Object helperObject = helperClass.newInstance(); - Object[] paramArrayObjects = new Object[]{new Object(), new Object()}; - m.invoke(helperObject, paramArrayObjects); - } -} +package reflection; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; + + +/** + * Test of Constructor.newInstance + */ +public class Reflect20 { + public static void main(String[] args) throws ClassNotFoundException, SecurityException, + NoSuchMethodException, IllegalAccessException, InstantiationException, + IllegalArgumentException, InvocationTargetException { + Class helperClass = Class.forName("reflection.Helper"); + Class objectClass = Class.forName("java.lang.Object"); + Class[] paramArrayTypes = new Class[]{objectClass, objectClass}; + Method m = helperClass.getMethod("o", paramArrayTypes); + Object helperObject = helperClass.newInstance(); + Object[] paramArrayObjects = new Object[]{new Object(), new Object()}; + m.invoke(helperObject, paramArrayObjects); + } +} diff --git a/com.ibm.wala.core.testdata/src/reflection/Reflect21.java b/com.ibm.wala.core.testdata/src/reflection/Reflect21.java index a0ec0978e..847c77bd8 100644 --- a/com.ibm.wala.core.testdata/src/reflection/Reflect21.java +++ b/com.ibm.wala.core.testdata/src/reflection/Reflect21.java @@ -1,21 +1,21 @@ -package reflection; - -import java.lang.reflect.Constructor; -import java.lang.reflect.InvocationTargetException; - - -/** - * Test of Constructor.newInstance - */ -public class Reflect21 { - public static void main(String[] args) throws ClassNotFoundException, SecurityException, - NoSuchMethodException, IllegalAccessException, InstantiationException, - IllegalArgumentException, InvocationTargetException { - Class helperClass = Class.forName("reflection.Helper"); - Class objectClass = Class.forName("java.lang.Object"); - Class[] paramArrayTypes = new Class[]{objectClass, objectClass}; - Constructor constr = helperClass.getDeclaredConstructor(paramArrayTypes); - Object[] paramArrayObjects = new Object[]{new Object(), new Object()}; - constr.newInstance(paramArrayObjects); - } -} +package reflection; + +import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationTargetException; + + +/** + * Test of Constructor.newInstance + */ +public class Reflect21 { + public static void main(String[] args) throws ClassNotFoundException, SecurityException, + NoSuchMethodException, IllegalAccessException, InstantiationException, + IllegalArgumentException, InvocationTargetException { + Class helperClass = Class.forName("reflection.Helper"); + Class objectClass = Class.forName("java.lang.Object"); + Class[] paramArrayTypes = new Class[]{objectClass, objectClass}; + Constructor constr = helperClass.getDeclaredConstructor(paramArrayTypes); + Object[] paramArrayObjects = new Object[]{new Object(), new Object()}; + constr.newInstance(paramArrayObjects); + } +} diff --git a/com.ibm.wala.core.testdata/src/reflection/Reflect22.java b/com.ibm.wala.core.testdata/src/reflection/Reflect22.java index cde494032..35ca4a4b5 100644 --- a/com.ibm.wala.core.testdata/src/reflection/Reflect22.java +++ b/com.ibm.wala.core.testdata/src/reflection/Reflect22.java @@ -1,28 +1,28 @@ -package reflection; - -import java.lang.reflect.Constructor; -import java.lang.reflect.InvocationTargetException; - - -/** - * Test of Constructor.newInstance - */ -public class Reflect22 { - public static void main(String[] args) throws ClassNotFoundException, SecurityException, - NoSuchMethodException, IllegalAccessException, InstantiationException, - IllegalArgumentException, InvocationTargetException { - Class helperClass = Class.forName("reflection.Helper"); - Constructor[] constrs = helperClass.getDeclaredConstructors(); - for (Constructor constr : constrs) { - if (constr.getParameterTypes().length == 1) { - Class paramType = constr.getParameterTypes()[0]; - if (paramType.getName().equals("java.lang.Integer")) { - Integer i = new Integer(1); - Object[] initArgs = new Object[]{i}; - constr.newInstance(initArgs); - break; - } - } - } - } -} +package reflection; + +import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationTargetException; + + +/** + * Test of Constructor.newInstance + */ +public class Reflect22 { + public static void main(String[] args) throws ClassNotFoundException, SecurityException, + NoSuchMethodException, IllegalAccessException, InstantiationException, + IllegalArgumentException, InvocationTargetException { + Class helperClass = Class.forName("reflection.Helper"); + Constructor[] constrs = helperClass.getDeclaredConstructors(); + for (Constructor constr : constrs) { + if (constr.getParameterTypes().length == 1) { + Class paramType = constr.getParameterTypes()[0]; + if (paramType.getName().equals("java.lang.Integer")) { + Integer i = new Integer(1); + Object[] initArgs = new Object[]{i}; + constr.newInstance(initArgs); + break; + } + } + } + } +} diff --git a/com.ibm.wala.core.testdata/src/reflection/Reflect23.java b/com.ibm.wala.core.testdata/src/reflection/Reflect23.java index addd35681..9d4c82304 100644 --- a/com.ibm.wala.core.testdata/src/reflection/Reflect23.java +++ b/com.ibm.wala.core.testdata/src/reflection/Reflect23.java @@ -1,30 +1,30 @@ -package reflection; - -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; -import java.lang.reflect.Modifier; - - -/** - * Test of Constructor.newInstance - */ -public class Reflect23 { - public static void main(String[] args) throws ClassNotFoundException, SecurityException, - NoSuchMethodException, IllegalAccessException, InstantiationException, - IllegalArgumentException, InvocationTargetException { - Class helperClass = Class.forName("reflection.Helper"); - Object helperObject = helperClass.newInstance(); - Method[] methods = helperClass.getDeclaredMethods(); - for (Method m : methods) { - if (m.getParameterTypes().length == 1) { - Class paramType = m.getParameterTypes()[0]; - if (! Modifier.isStatic(m.getModifiers()) && paramType.getName().equals("java.lang.Integer")) { - Integer i = new Integer(1); - Object[] initArgs = new Object[]{i}; - m.invoke(helperObject, initArgs); - break; - } - } - } - } -} +package reflection; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; + + +/** + * Test of Constructor.newInstance + */ +public class Reflect23 { + public static void main(String[] args) throws ClassNotFoundException, SecurityException, + NoSuchMethodException, IllegalAccessException, InstantiationException, + IllegalArgumentException, InvocationTargetException { + Class helperClass = Class.forName("reflection.Helper"); + Object helperObject = helperClass.newInstance(); + Method[] methods = helperClass.getDeclaredMethods(); + for (Method m : methods) { + if (m.getParameterTypes().length == 1) { + Class paramType = m.getParameterTypes()[0]; + if (! Modifier.isStatic(m.getModifiers()) && paramType.getName().equals("java.lang.Integer")) { + Integer i = new Integer(1); + Object[] initArgs = new Object[]{i}; + m.invoke(helperObject, initArgs); + break; + } + } + } + } +} diff --git a/com.ibm.wala.core.testdata/src/reflection/Reflect3.java b/com.ibm.wala.core.testdata/src/reflection/Reflect3.java index aea540ad5..00dd21514 100644 --- a/com.ibm.wala.core.testdata/src/reflection/Reflect3.java +++ b/com.ibm.wala.core.testdata/src/reflection/Reflect3.java @@ -1,17 +1,17 @@ -package reflection; - -import java.util.Hashtable; - -public class Reflect3 { - - public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException { - Class c = Class.forName("java.util.Properties"); - Hashtable h = (Hashtable) c.newInstance(); - System.out.println(h.toString()); - } - - @SuppressWarnings("unused") - private static class Hash extends Hashtable { - - } -} +package reflection; + +import java.util.Hashtable; + +public class Reflect3 { + + public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException { + Class c = Class.forName("java.util.Properties"); + Hashtable h = (Hashtable) c.newInstance(); + System.out.println(h.toString()); + } + + @SuppressWarnings("unused") + private static class Hash extends Hashtable { + + } +} diff --git a/com.ibm.wala.core.testdata/src/reflection/Reflect4.java b/com.ibm.wala.core.testdata/src/reflection/Reflect4.java index bfa301435..0d2af03d5 100644 --- a/com.ibm.wala.core.testdata/src/reflection/Reflect4.java +++ b/com.ibm.wala.core.testdata/src/reflection/Reflect4.java @@ -1,12 +1,12 @@ -package reflection; - -import java.io.FilePermission; - -public class Reflect4 { - - public static void main(String[] args) throws IllegalAccessException, InstantiationException, ClassNotFoundException { - Class c = Class.forName("java.io.FilePermission"); - FilePermission h = (FilePermission) c.newInstance(); - System.out.println(h.toString()); - } -} +package reflection; + +import java.io.FilePermission; + +public class Reflect4 { + + public static void main(String[] args) throws IllegalAccessException, InstantiationException, ClassNotFoundException { + Class c = Class.forName("java.io.FilePermission"); + FilePermission h = (FilePermission) c.newInstance(); + System.out.println(h.toString()); + } +} diff --git a/com.ibm.wala.core.testdata/src/reflection/Reflect5.java b/com.ibm.wala.core.testdata/src/reflection/Reflect5.java index b30ab8c30..0ccbd2fb5 100644 --- a/com.ibm.wala.core.testdata/src/reflection/Reflect5.java +++ b/com.ibm.wala.core.testdata/src/reflection/Reflect5.java @@ -1,19 +1,19 @@ -package reflection; - - -public class Reflect5 { - - public static void main(String[] args) throws IllegalAccessException, InstantiationException, ClassNotFoundException { - Class c = Class.forName("reflection.Reflect5$A"); - A h = (A) c.newInstance(); - System.out.println(h.toString()); - } - - public static class A { - private A() { - } - public String toString() { - return "Instance of A"; - } - } -} +package reflection; + + +public class Reflect5 { + + public static void main(String[] args) throws IllegalAccessException, InstantiationException, ClassNotFoundException { + Class c = Class.forName("reflection.Reflect5$A"); + A h = (A) c.newInstance(); + System.out.println(h.toString()); + } + + public static class A { + private A() { + } + public String toString() { + return "Instance of A"; + } + } +} diff --git a/com.ibm.wala.core.testdata/src/reflection/Reflect6.java b/com.ibm.wala.core.testdata/src/reflection/Reflect6.java index 3d44804a3..8c6b7d27a 100644 --- a/com.ibm.wala.core.testdata/src/reflection/Reflect6.java +++ b/com.ibm.wala.core.testdata/src/reflection/Reflect6.java @@ -1,19 +1,19 @@ -package reflection; - - -public class Reflect6 { - - public static void main(String[] args) throws IllegalAccessException, InstantiationException, ClassNotFoundException { - Class c = Class.forName("reflection.Reflect6$A"); - A h = (A) c.newInstance(); - System.out.println(h.toString()); - } - - public static class A { - private A(int i) { - } - public String toString() { - return "Instance of A"; - } - } -} +package reflection; + + +public class Reflect6 { + + public static void main(String[] args) throws IllegalAccessException, InstantiationException, ClassNotFoundException { + Class c = Class.forName("reflection.Reflect6$A"); + A h = (A) c.newInstance(); + System.out.println(h.toString()); + } + + public static class A { + private A(int i) { + } + public String toString() { + return "Instance of A"; + } + } +} diff --git a/com.ibm.wala.core.testdata/src/reflection/Reflect7.java b/com.ibm.wala.core.testdata/src/reflection/Reflect7.java index 0e20f20b7..1f86889c1 100644 --- a/com.ibm.wala.core.testdata/src/reflection/Reflect7.java +++ b/com.ibm.wala.core.testdata/src/reflection/Reflect7.java @@ -1,23 +1,23 @@ -package reflection; - -import java.io.FilePermission; -import java.lang.reflect.Constructor; -import java.lang.reflect.InvocationTargetException; - -/** - * - * @author pistoia - * - */ -public class Reflect7 { - @SuppressWarnings("unchecked") - public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, - IllegalArgumentException, InstantiationException, IllegalAccessException, InvocationTargetException { - Class c = Class.forName("java.io.FilePermission"); - Class[] paramTypes = new Class[] { "".getClass(), "".getClass() }; - Constructor constr = c.getConstructor(paramTypes); - Object[] params = new String[] { "log.txt", "read" }; - FilePermission fp = constr.newInstance(params); - fp.toString(); - } -} +package reflection; + +import java.io.FilePermission; +import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationTargetException; + +/** + * + * @author pistoia + * + */ +public class Reflect7 { + @SuppressWarnings("unchecked") + public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, + IllegalArgumentException, InstantiationException, IllegalAccessException, InvocationTargetException { + Class c = Class.forName("java.io.FilePermission"); + Class[] paramTypes = new Class[] { "".getClass(), "".getClass() }; + Constructor constr = c.getConstructor(paramTypes); + Object[] params = new String[] { "log.txt", "read" }; + FilePermission fp = constr.newInstance(params); + fp.toString(); + } +} diff --git a/com.ibm.wala.core.testdata/src/reflection/Reflect8.java b/com.ibm.wala.core.testdata/src/reflection/Reflect8.java index e76a2895f..58485fe4b 100644 --- a/com.ibm.wala.core.testdata/src/reflection/Reflect8.java +++ b/com.ibm.wala.core.testdata/src/reflection/Reflect8.java @@ -1,17 +1,17 @@ -package reflection; - -import java.lang.reflect.Constructor; -import java.lang.reflect.InvocationTargetException; - -/** - * Test of Class.getConstructors(). - */ -public class Reflect8 { - public static void main(String[] args) throws ClassNotFoundException, IllegalArgumentException, InstantiationException, - IllegalAccessException, InvocationTargetException { - Class c = Class.forName("java.lang.Integer"); - Constructor[] ctors = c.getConstructors(); - Integer i = (Integer) ctors[0].newInstance(new Integer(1)); - i.toString(); - } -} +package reflection; + +import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationTargetException; + +/** + * Test of Class.getConstructors(). + */ +public class Reflect8 { + public static void main(String[] args) throws ClassNotFoundException, IllegalArgumentException, InstantiationException, + IllegalAccessException, InvocationTargetException { + Class c = Class.forName("java.lang.Integer"); + Constructor[] ctors = c.getConstructors(); + Integer i = (Integer) ctors[0].newInstance(new Integer(1)); + i.toString(); + } +} diff --git a/com.ibm.wala.core.testdata/src/reflection/Reflect9.java b/com.ibm.wala.core.testdata/src/reflection/Reflect9.java index 23470b5f4..28a56abd0 100644 --- a/com.ibm.wala.core.testdata/src/reflection/Reflect9.java +++ b/com.ibm.wala.core.testdata/src/reflection/Reflect9.java @@ -1,16 +1,16 @@ -package reflection; - -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; - -/** - * Test of Method.invoke - */ -public class Reflect9 { - public static void main(String[] args) throws ClassNotFoundException, IllegalArgumentException, InstantiationException, - IllegalAccessException, InvocationTargetException, SecurityException, NoSuchMethodException { - Class c = Class.forName("java.lang.Integer"); - Method m = c.getDeclaredMethod("toString", new Class[] {}); - m.invoke(new Integer(2), new Object[] {}); - } -} +package reflection; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; + +/** + * Test of Method.invoke + */ +public class Reflect9 { + public static void main(String[] args) throws ClassNotFoundException, IllegalArgumentException, InstantiationException, + IllegalAccessException, InvocationTargetException, SecurityException, NoSuchMethodException { + Class c = Class.forName("java.lang.Integer"); + Method m = c.getDeclaredMethod("toString", new Class[] {}); + m.invoke(new Integer(2), new Object[] {}); + } +} diff --git a/com.ibm.wala.core.testdata/src/slice/A.java b/com.ibm.wala.core.testdata/src/slice/A.java index 9c2211f9c..b0c65f996 100644 --- a/com.ibm.wala.core.testdata/src/slice/A.java +++ b/com.ibm.wala.core.testdata/src/slice/A.java @@ -1,19 +1,19 @@ -package slice; - -class A { - - Object f; - Object g; - - Object foo() { - return new Integer(3); - } - - public Object getF() { - return f; - } - - public void setF(Object f) { - this.f = f; - } -} +package slice; + +class A { + + Object f; + Object g; + + Object foo() { + return new Integer(3); + } + + public Object getF() { + return f; + } + + public void setF(Object f) { + this.f = f; + } +} diff --git a/com.ibm.wala.core.testdata/src/slice/B.java b/com.ibm.wala.core.testdata/src/slice/B.java index 5aa1d852b..396082202 100644 --- a/com.ibm.wala.core.testdata/src/slice/B.java +++ b/com.ibm.wala.core.testdata/src/slice/B.java @@ -1,7 +1,7 @@ -package slice; - -class B extends A { - Object foo() { - return new Float(4); - } -} +package slice; + +class B extends A { + Object foo() { + return new Float(4); + } +} diff --git a/com.ibm.wala.core.testdata/src/slice/Slice1.java b/com.ibm.wala.core.testdata/src/slice/Slice1.java index a70b6a99d..b58602553 100644 --- a/com.ibm.wala.core.testdata/src/slice/Slice1.java +++ b/com.ibm.wala.core.testdata/src/slice/Slice1.java @@ -1,31 +1,31 @@ -/******************************************************************************* - * 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 slice; - -public class Slice1 { - /** - * @param args - */ - public static void main(String[] args) { - int x = foo(1); - int y = bar(2); - System.out.println(x + y); - } - - static int foo(int x) { - return x + 2; - } - - static int bar(int x) { - return x + 3; - } - -} +/******************************************************************************* + * 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 slice; + +public class Slice1 { + /** + * @param args + */ + public static void main(String[] args) { + int x = foo(1); + int y = bar(2); + System.out.println(x + y); + } + + static int foo(int x) { + return x + 2; + } + + static int bar(int x) { + return x + 3; + } + +} diff --git a/com.ibm.wala.core.testdata/src/slice/Slice2.java b/com.ibm.wala.core.testdata/src/slice/Slice2.java index 666f5cab2..78d67d6f3 100644 --- a/com.ibm.wala.core.testdata/src/slice/Slice2.java +++ b/com.ibm.wala.core.testdata/src/slice/Slice2.java @@ -1,33 +1,33 @@ -/******************************************************************************* - * 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 slice; - -public class Slice2 { - - public static void main(String[] args) { - int x = foo(1); - int y = bar(2); - baz(x+y); - } - - public static void baz(int z) { - System.out.println(z); - } - - static int foo(int x) { - return x + 2; - } - - static int bar(int x) { - return x + 3; - } - -} +/******************************************************************************* + * 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 slice; + +public class Slice2 { + + public static void main(String[] args) { + int x = foo(1); + int y = bar(2); + baz(x+y); + } + + public static void baz(int z) { + System.out.println(z); + } + + static int foo(int x) { + return x + 2; + } + + static int bar(int x) { + return x + 3; + } + +} diff --git a/com.ibm.wala.core.testdata/src/slice/Slice3.java b/com.ibm.wala.core.testdata/src/slice/Slice3.java index 52144c6bc..a56c169d5 100644 --- a/com.ibm.wala.core.testdata/src/slice/Slice3.java +++ b/com.ibm.wala.core.testdata/src/slice/Slice3.java @@ -1,32 +1,32 @@ -/******************************************************************************* - * 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 slice; - -public class Slice3 { - static void doNothing(Object o) { - } - - /** - * @param args - */ - public static void main(String[] args) { - Object o1 = new Object(); - Object o2 = new Object(); - Object o3 = foo(o1, o2); - doNothing(o3); - } - - static Object foo(Object x, Object y) { - return x; - } - - -} +/******************************************************************************* + * 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 slice; + +public class Slice3 { + static void doNothing(Object o) { + } + + /** + * @param args + */ + public static void main(String[] args) { + Object o1 = new Object(); + Object o2 = new Object(); + Object o3 = foo(o1, o2); + doNothing(o3); + } + + static Object foo(Object x, Object y) { + return x; + } + + +} diff --git a/com.ibm.wala.core.testdata/src/slice/Slice4.java b/com.ibm.wala.core.testdata/src/slice/Slice4.java index 3f0549e67..ff9753139 100644 --- a/com.ibm.wala.core.testdata/src/slice/Slice4.java +++ b/com.ibm.wala.core.testdata/src/slice/Slice4.java @@ -1,30 +1,30 @@ -/******************************************************************************* - * 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 slice; - -public class Slice4 { - /** - * @param args - */ - public static void main(String[] args) { - int x = foo(1); - bar(x); - } - - static int foo(int x) { - return x + 2; - } - - static void bar(int x) { - return; - } - -} +/******************************************************************************* + * 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 slice; + +public class Slice4 { + /** + * @param args + */ + public static void main(String[] args) { + int x = foo(1); + bar(x); + } + + static int foo(int x) { + return x + 2; + } + + static void bar(int x) { + return; + } + +} diff --git a/com.ibm.wala.core.testdata/src/slice/Slice5.java b/com.ibm.wala.core.testdata/src/slice/Slice5.java index 1756c4cb6..5c678f0e0 100644 --- a/com.ibm.wala.core.testdata/src/slice/Slice5.java +++ b/com.ibm.wala.core.testdata/src/slice/Slice5.java @@ -1,31 +1,31 @@ -/******************************************************************************* - * 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 slice; - -public class Slice5 { - - public static void main(String[] args) { - int x = baz(); - bar(x); - } - - static int baz() { - return foo(1); - } - - static int foo(int x) { - return x + 2; - } - - static void bar(int x) { - return; - } -} +/******************************************************************************* + * 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 slice; + +public class Slice5 { + + public static void main(String[] args) { + int x = baz(); + bar(x); + } + + static int baz() { + return foo(1); + } + + static int foo(int x) { + return x + 2; + } + + static void bar(int x) { + return; + } +} diff --git a/com.ibm.wala.core.testdata/src/slice/Slice6.java b/com.ibm.wala.core.testdata/src/slice/Slice6.java index 206c78d63..da021d6a5 100644 --- a/com.ibm.wala.core.testdata/src/slice/Slice6.java +++ b/com.ibm.wala.core.testdata/src/slice/Slice6.java @@ -1,31 +1,31 @@ -/******************************************************************************* - * Copyright (c) 2007 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 slice; - -import java.util.Vector; - -public class Slice6 { - public static Vector messages; - - public static void main(String[] args) { - - messages = new Vector(); - messages.add(5); - - int message = (Integer) messages.elementAt(0); - - sendMessage(message); - } - - public static void sendMessage(int message) { - // do nothing - } -} +/******************************************************************************* + * Copyright (c) 2007 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 slice; + +import java.util.Vector; + +public class Slice6 { + public static Vector messages; + + public static void main(String[] args) { + + messages = new Vector(); + messages.add(5); + + int message = (Integer) messages.elementAt(0); + + sendMessage(message); + } + + public static void sendMessage(int message) { + // do nothing + } +} diff --git a/com.ibm.wala.core.testdata/src/slice/Slice7.java b/com.ibm.wala.core.testdata/src/slice/Slice7.java index 4b899e487..980b08fb4 100644 --- a/com.ibm.wala.core.testdata/src/slice/Slice7.java +++ b/com.ibm.wala.core.testdata/src/slice/Slice7.java @@ -1,20 +1,20 @@ -/******************************************************************************* - * Copyright (c) 2007 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 slice; - -import java.util.Hashtable; - -public class Slice7 { - public static void main(String args[]) { - @SuppressWarnings("unused") - Hashtable abc = new Hashtable(3, 0.75f); - } -} +/******************************************************************************* + * Copyright (c) 2007 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 slice; + +import java.util.Hashtable; + +public class Slice7 { + public static void main(String args[]) { + @SuppressWarnings("unused") + Hashtable abc = new Hashtable(3, 0.75f); + } +} diff --git a/com.ibm.wala.core.testdata/src/slice/TestArrays.java b/com.ibm.wala.core.testdata/src/slice/TestArrays.java index 5ee4c1aed..c9ef103e9 100644 --- a/com.ibm.wala.core.testdata/src/slice/TestArrays.java +++ b/com.ibm.wala.core.testdata/src/slice/TestArrays.java @@ -1,31 +1,31 @@ -/******************************************************************************* - * 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 slice; - -public class TestArrays { - - static void doNothing(Object o) {} - /** - * slice should include statements involving arr2 and i, - * exclude statements with arr1 and j - * @param args - */ - public static void main(String[] args) { - Object[] arr1 = new Object[10], arr2 = new Object[10]; - int i = 3; - int j = 4; - arr2[i] = new Object(); - arr1[j] = new Object(); - Object x = arr2[i]; - doNothing(x); - } - -} +/******************************************************************************* + * 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 slice; + +public class TestArrays { + + static void doNothing(Object o) {} + /** + * slice should include statements involving arr2 and i, + * exclude statements with arr1 and j + * @param args + */ + public static void main(String[] args) { + Object[] arr1 = new Object[10], arr2 = new Object[10]; + int i = 3; + int j = 4; + arr2[i] = new Object(); + arr1[j] = new Object(); + Object x = arr2[i]; + doNothing(x); + } + +} diff --git a/com.ibm.wala.core.testdata/src/slice/TestCD1.java b/com.ibm.wala.core.testdata/src/slice/TestCD1.java index 98e6dbc01..366096c7d 100644 --- a/com.ibm.wala.core.testdata/src/slice/TestCD1.java +++ b/com.ibm.wala.core.testdata/src/slice/TestCD1.java @@ -1,34 +1,34 @@ -/******************************************************************************* - * 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 slice; - -public class TestCD1 { - - static void doNothing(Object o) { - } - - /** - * - * @param args - */ - public static void main(String[] args) { - Integer I = (Integer) new A().foo(); - int i = I.intValue(); - if (i > 0) { - System.out.println("X"); - if (i > 1) { - System.out.println("Y"); - doNothing(I); - } - } - } - -} +/******************************************************************************* + * 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 slice; + +public class TestCD1 { + + static void doNothing(Object o) { + } + + /** + * + * @param args + */ + public static void main(String[] args) { + Integer I = (Integer) new A().foo(); + int i = I.intValue(); + if (i > 0) { + System.out.println("X"); + if (i > 1) { + System.out.println("Y"); + doNothing(I); + } + } + } + +} diff --git a/com.ibm.wala.core.testdata/src/slice/TestCD2.java b/com.ibm.wala.core.testdata/src/slice/TestCD2.java index a74f8b070..fa1f3497f 100644 --- a/com.ibm.wala.core.testdata/src/slice/TestCD2.java +++ b/com.ibm.wala.core.testdata/src/slice/TestCD2.java @@ -1,34 +1,34 @@ -/******************************************************************************* - * 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 slice; - -public class TestCD2 { - - static void doNothing(Object o) { - } - - /** - * - * @param args - */ - public static void main(String[] args) { - Integer I = (Integer) new A().foo(); - int i = I.intValue(); - if (i > 0) { - System.out.println("X"); - doNothing(I); - if (i > 1) { - System.out.println("Y"); - } - } - } - -} +/******************************************************************************* + * 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 slice; + +public class TestCD2 { + + static void doNothing(Object o) { + } + + /** + * + * @param args + */ + public static void main(String[] args) { + Integer I = (Integer) new A().foo(); + int i = I.intValue(); + if (i > 0) { + System.out.println("X"); + doNothing(I); + if (i > 1) { + System.out.println("Y"); + } + } + } + +} diff --git a/com.ibm.wala.core.testdata/src/slice/TestCD3.java b/com.ibm.wala.core.testdata/src/slice/TestCD3.java index 95b834ba5..323d99344 100644 --- a/com.ibm.wala.core.testdata/src/slice/TestCD3.java +++ b/com.ibm.wala.core.testdata/src/slice/TestCD3.java @@ -1,36 +1,36 @@ -/******************************************************************************* - * 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 slice; - -public class TestCD3 { - - static void doNothing(Object o) { - } - - /** - * - * @param args - */ - public static void main(String[] args) { - Integer I = (Integer) new A().foo(); - int i = I.intValue(); - try { - if (i > 0) { - System.out.println("X"); - if (i > 1) { - System.out.println("Y"); - } - } - } catch (Throwable e) { - } - doNothing(I); - } -} +/******************************************************************************* + * 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 slice; + +public class TestCD3 { + + static void doNothing(Object o) { + } + + /** + * + * @param args + */ + public static void main(String[] args) { + Integer I = (Integer) new A().foo(); + int i = I.intValue(); + try { + if (i > 0) { + System.out.println("X"); + if (i > 1) { + System.out.println("Y"); + } + } + } catch (Throwable e) { + } + doNothing(I); + } +} diff --git a/com.ibm.wala.core.testdata/src/slice/TestCD4.java b/com.ibm.wala.core.testdata/src/slice/TestCD4.java index 98a3300ea..84d8d9601 100644 --- a/com.ibm.wala.core.testdata/src/slice/TestCD4.java +++ b/com.ibm.wala.core.testdata/src/slice/TestCD4.java @@ -1,43 +1,43 @@ -/******************************************************************************* - * 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 slice; - -public class TestCD4 { - - static void doNothing(int i) { - - } - - /** - * - * @param args - */ - public static void main(String[] args) { - int i = 3; - int j = 4; - int k = foo(i,j); - - doNothing(k); - } - - static int foo(int i, int j){ - int k = 0; - if (i == 3){ - k = 9; - if (j != 4){ - k = k+1; - } - k = 8; - } - return k; - } - -} +/******************************************************************************* + * 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 slice; + +public class TestCD4 { + + static void doNothing(int i) { + + } + + /** + * + * @param args + */ + public static void main(String[] args) { + int i = 3; + int j = 4; + int k = foo(i,j); + + doNothing(k); + } + + static int foo(int i, int j){ + int k = 0; + if (i == 3){ + k = 9; + if (j != 4){ + k = k+1; + } + k = 8; + } + return k; + } + +} diff --git a/com.ibm.wala.core.testdata/src/slice/TestCD5.java b/com.ibm.wala.core.testdata/src/slice/TestCD5.java index c0cc54655..2ba93a30d 100644 --- a/com.ibm.wala.core.testdata/src/slice/TestCD5.java +++ b/com.ibm.wala.core.testdata/src/slice/TestCD5.java @@ -1,33 +1,33 @@ -/******************************************************************************* - * 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 slice; - -public class TestCD5 { - - /** - * - * @param args - */ - public static void main(String[] args) { - int i = 0; - while (someBool()) { - ++i; - if (i >= 3) { - return; - } - } - } - - - public static boolean someBool() { - return false; - } -} +/******************************************************************************* + * 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 slice; + +public class TestCD5 { + + /** + * + * @param args + */ + public static void main(String[] args) { + int i = 0; + while (someBool()) { + ++i; + if (i >= 3) { + return; + } + } + } + + + public static boolean someBool() { + return false; + } +} diff --git a/com.ibm.wala.core.testdata/src/slice/TestCD6.java b/com.ibm.wala.core.testdata/src/slice/TestCD6.java index 2b6f64eab..249d97c6e 100644 --- a/com.ibm.wala.core.testdata/src/slice/TestCD6.java +++ b/com.ibm.wala.core.testdata/src/slice/TestCD6.java @@ -1,35 +1,35 @@ -/******************************************************************************* - * 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 slice; - -public class TestCD6 { - - /** - * - * @param args - */ - public static void main(String[] args) { - int i = 0; - if (someBool()) { - i = 3; - } else { - i = 4; - } - doNothing(i); - } - - public static void doNothing(int i) { - } - - public static boolean someBool() { - return false; - } -} +/******************************************************************************* + * 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 slice; + +public class TestCD6 { + + /** + * + * @param args + */ + public static void main(String[] args) { + int i = 0; + if (someBool()) { + i = 3; + } else { + i = 4; + } + doNothing(i); + } + + public static void doNothing(int i) { + } + + public static boolean someBool() { + return false; + } +} diff --git a/com.ibm.wala.core.testdata/src/slice/TestFields.java b/com.ibm.wala.core.testdata/src/slice/TestFields.java index 72278212e..47c943e4c 100644 --- a/com.ibm.wala.core.testdata/src/slice/TestFields.java +++ b/com.ibm.wala.core.testdata/src/slice/TestFields.java @@ -1,33 +1,33 @@ -/******************************************************************************* - * 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 slice; - -public class TestFields { - - private static void doNothing(Object o) {} - - /** - * slice should include a1 and o1, exclude - * a2 and o2 - * @param args - */ - public static void main(String[] args) { - Object o1 = new Object(); - Object o2 = new Object(); - A a1 = new A(); - A a2 = new A(); - a1.f = o1; - a2.f = o2; - Object o3 = a1.f; - doNothing(o3); - } - -} +/******************************************************************************* + * 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 slice; + +public class TestFields { + + private static void doNothing(Object o) {} + + /** + * slice should include a1 and o1, exclude + * a2 and o2 + * @param args + */ + public static void main(String[] args) { + Object o1 = new Object(); + Object o2 = new Object(); + A a1 = new A(); + A a2 = new A(); + a1.f = o1; + a2.f = o2; + Object o3 = a1.f; + doNothing(o3); + } + +} diff --git a/com.ibm.wala.core.testdata/src/slice/TestGlobal.java b/com.ibm.wala.core.testdata/src/slice/TestGlobal.java index 1b1c2698f..460af1df6 100644 --- a/com.ibm.wala.core.testdata/src/slice/TestGlobal.java +++ b/com.ibm.wala.core.testdata/src/slice/TestGlobal.java @@ -1,37 +1,37 @@ -/******************************************************************************* - * 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 slice; - -public class TestGlobal { - - static Object global1; - - static Object global2; - - static void copyGlobals() { - global2 = global1; - } - - static void doNothing(Object o) { - } - - /** - * make sure global variables are being properly handled - * @param args - */ - public static void main(String[] args) { - global1 = new Object(); - copyGlobals(); - Object x = global2; - doNothing(x); - } - -} +/******************************************************************************* + * 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 slice; + +public class TestGlobal { + + static Object global1; + + static Object global2; + + static void copyGlobals() { + global2 = global1; + } + + static void doNothing(Object o) { + } + + /** + * make sure global variables are being properly handled + * @param args + */ + public static void main(String[] args) { + global1 = new Object(); + copyGlobals(); + Object x = global2; + doNothing(x); + } + +} diff --git a/com.ibm.wala.core.testdata/src/slice/TestId.java b/com.ibm.wala.core.testdata/src/slice/TestId.java index a11cb1cda..2937b98d1 100644 --- a/com.ibm.wala.core.testdata/src/slice/TestId.java +++ b/com.ibm.wala.core.testdata/src/slice/TestId.java @@ -1,35 +1,35 @@ -/******************************************************************************* - * 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 slice; - -public class TestId { - - static Object id(Object x) { - return x; - } - - static void doNothing(Object o) { - } - - /** - * check for context-sensitive handling of the identity function. - * o2 should be excluded - * - * @param args - */ - public static void main(String[] args) { - Object o1 = new Object(), o2 = new Object(); - Object o3 = id(o1); - id(o2); - doNothing(o3); - } - -} +/******************************************************************************* + * 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 slice; + +public class TestId { + + static Object id(Object x) { + return x; + } + + static void doNothing(Object o) { + } + + /** + * check for context-sensitive handling of the identity function. + * o2 should be excluded + * + * @param args + */ + public static void main(String[] args) { + Object o1 = new Object(), o2 = new Object(); + Object o3 = id(o1); + id(o2); + doNothing(o3); + } + +} diff --git a/com.ibm.wala.core.testdata/src/slice/TestMessageFormat.java b/com.ibm.wala.core.testdata/src/slice/TestMessageFormat.java index 44c328f9a..3f4fa2cd1 100644 --- a/com.ibm.wala.core.testdata/src/slice/TestMessageFormat.java +++ b/com.ibm.wala.core.testdata/src/slice/TestMessageFormat.java @@ -1,20 +1,20 @@ -/******************************************************************************* - * Copyright (c) 2007 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 slice; - -import java.text.MessageFormat; - -public class TestMessageFormat { - - public static void main(String args[]) { - MessageFormat.format(null, (Object[])null); - } -} +/******************************************************************************* + * Copyright (c) 2007 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 slice; + +import java.text.MessageFormat; + +public class TestMessageFormat { + + public static void main(String args[]) { + MessageFormat.format(null, (Object[])null); + } +} diff --git a/com.ibm.wala.core.testdata/src/slice/TestMultiTarget.java b/com.ibm.wala.core.testdata/src/slice/TestMultiTarget.java index 9b30cab06..bf7055c31 100644 --- a/com.ibm.wala.core.testdata/src/slice/TestMultiTarget.java +++ b/com.ibm.wala.core.testdata/src/slice/TestMultiTarget.java @@ -1,35 +1,35 @@ -/******************************************************************************* - * 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 slice; - -public class TestMultiTarget { - - static void doNothing(Object o) { - } - - /** - * test a virtual call with multiple targets. slice should include statements - * assigning to a - * - * @param args - */ - public static void main(String[] args) { - A a = null; - if (args[0] == null) { - a = new A(); - } else { - a = new B(); - } - Object x = a.foo(); - doNothing(x); - } - -} +/******************************************************************************* + * 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 slice; + +public class TestMultiTarget { + + static void doNothing(Object o) { + } + + /** + * test a virtual call with multiple targets. slice should include statements + * assigning to a + * + * @param args + */ + public static void main(String[] args) { + A a = null; + if (args[0] == null) { + a = new A(); + } else { + a = new B(); + } + Object x = a.foo(); + doNothing(x); + } + +} diff --git a/com.ibm.wala.core.testdata/src/slice/TestPrimGetterSetter.java b/com.ibm.wala.core.testdata/src/slice/TestPrimGetterSetter.java index de66349e9..5cd080ef5 100644 --- a/com.ibm.wala.core.testdata/src/slice/TestPrimGetterSetter.java +++ b/com.ibm.wala.core.testdata/src/slice/TestPrimGetterSetter.java @@ -1,40 +1,40 @@ -/******************************************************************************* - * 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 slice; - -public class TestPrimGetterSetter { - - static class IntWrapper { - int i; - - int getI() { return i; } - - void setI(int i) { - this.i = i; - } - } - - public static void doNothing(int i) {} - /** - * @param args - */ - public static void main(String[] args) { - IntWrapper w = new IntWrapper(); - test(w); - } - - public static void test(IntWrapper w) { - int x = 3; - w.setI(x); - int y = w.getI(); - doNothing(y); // slice on y - } -} +/******************************************************************************* + * 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 slice; + +public class TestPrimGetterSetter { + + static class IntWrapper { + int i; + + int getI() { return i; } + + void setI(int i) { + this.i = i; + } + } + + public static void doNothing(int i) {} + /** + * @param args + */ + public static void main(String[] args) { + IntWrapper w = new IntWrapper(); + test(w); + } + + public static void test(IntWrapper w) { + int x = 3; + w.setI(x); + int y = w.getI(); + doNothing(y); // slice on y + } +} diff --git a/com.ibm.wala.core.testdata/src/slice/TestRecursion.java b/com.ibm.wala.core.testdata/src/slice/TestRecursion.java index 658782d88..a62f998e1 100644 --- a/com.ibm.wala.core.testdata/src/slice/TestRecursion.java +++ b/com.ibm.wala.core.testdata/src/slice/TestRecursion.java @@ -1,40 +1,40 @@ -/******************************************************************************* - * 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 slice; - -public class TestRecursion { - - static Object find(A a, Object o) { - if (o == null) { - return a; - } else { - return find((A) a.f, o); - } - } - - static void doNothing(Object o) { - } - - /** - * test of recursion. Everything for a1, a2, and a3 should - * be included - * @param args - */ - public static void main(String[] args) { - A a1 = new A(), a2 = new A(), a3 = new A(); - a1.f = a2; - a2.f = a3; - Object x = find(a1, args[0]); - doNothing(x); - - } - -} +/******************************************************************************* + * 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 slice; + +public class TestRecursion { + + static Object find(A a, Object o) { + if (o == null) { + return a; + } else { + return find((A) a.f, o); + } + } + + static void doNothing(Object o) { + } + + /** + * test of recursion. Everything for a1, a2, and a3 should + * be included + * @param args + */ + public static void main(String[] args) { + A a1 = new A(), a2 = new A(), a3 = new A(); + a1.f = a2; + a2.f = a3; + Object x = find(a1, args[0]); + doNothing(x); + + } + +} diff --git a/com.ibm.wala.core.testdata/src/slice/TestThin1.java b/com.ibm.wala.core.testdata/src/slice/TestThin1.java index 24d2f648a..6fdc76af4 100644 --- a/com.ibm.wala.core.testdata/src/slice/TestThin1.java +++ b/com.ibm.wala.core.testdata/src/slice/TestThin1.java @@ -1,32 +1,32 @@ -/******************************************************************************* - * 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 slice; - -public class TestThin1 { - - private static void doNothing(Object o) {} - - /** - * slice should not include any statements relating to - * base pointers - */ - public static void main(String[] args) { - Object o1 = new Object(); - A a1 = new A(); - A a2 = new A(); - a1.f = a2; - a2.g = o1; - A a3 = (A)a1.f; - Object o3 = a3.g; - doNothing(o3); - } - -} +/******************************************************************************* + * 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 slice; + +public class TestThin1 { + + private static void doNothing(Object o) {} + + /** + * slice should not include any statements relating to + * base pointers + */ + public static void main(String[] args) { + Object o1 = new Object(); + A a1 = new A(); + A a2 = new A(); + a1.f = a2; + a2.g = o1; + A a3 = (A)a1.f; + Object o3 = a3.g; + doNothing(o3); + } + +} diff --git a/com.ibm.wala.core.testdata/src/typeInference/TI.java b/com.ibm.wala.core.testdata/src/typeInference/TI.java index 71cf98fa1..eeeb9dc17 100644 --- a/com.ibm.wala.core.testdata/src/typeInference/TI.java +++ b/com.ibm.wala.core.testdata/src/typeInference/TI.java @@ -1,41 +1,41 @@ -/******************************************************************************* - * Copyright (c) 2007 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 typeInference; - -public class TI { - public static void foo() { - int[] x = new int[0]; - System.out.println(x[0]); - } - - public void bar(int x) { - if (x > Integer.MIN_VALUE) { - Integer.toString(x); - throw new Error(); - } - } - - public void inferInt() { - if (time() < time()) { - throw new Error(); - } - } - - private static long time() { - return System.currentTimeMillis(); - } - - public void useCast(Object o) { - String s = (String)o; - System.out.println(s); - } - -} +/******************************************************************************* + * Copyright (c) 2007 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 typeInference; + +public class TI { + public static void foo() { + int[] x = new int[0]; + System.out.println(x[0]); + } + + public void bar(int x) { + if (x > Integer.MIN_VALUE) { + Integer.toString(x); + throw new Error(); + } + } + + public void inferInt() { + if (time() < time()) { + throw new Error(); + } + } + + private static long time() { + return System.currentTimeMillis(); + } + + public void useCast(Object o) { + String s = (String)o; + System.out.println(s); + } + +} diff --git a/com.ibm.wala.core.tests/src/com/ibm/wala/core/tests/basic/GraphDataflowTest.java b/com.ibm.wala.core.tests/src/com/ibm/wala/core/tests/basic/GraphDataflowTest.java index 5ca2d575c..a3425ac98 100644 --- a/com.ibm.wala.core.tests/src/com/ibm/wala/core/tests/basic/GraphDataflowTest.java +++ b/com.ibm.wala.core.tests/src/com/ibm/wala/core/tests/basic/GraphDataflowTest.java @@ -1,210 +1,210 @@ -/******************************************************************************* - * 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.core.tests.basic; - -import org.junit.Assert; -import org.junit.Test; - -import com.ibm.wala.core.tests.util.WalaTestCase; -import com.ibm.wala.dataflow.graph.AbstractMeetOperator; -import com.ibm.wala.dataflow.graph.BitVectorFilter; -import com.ibm.wala.dataflow.graph.BitVectorFramework; -import com.ibm.wala.dataflow.graph.BitVectorIdentity; -import com.ibm.wala.dataflow.graph.BitVectorSolver; -import com.ibm.wala.dataflow.graph.BitVectorUnion; -import com.ibm.wala.dataflow.graph.BitVectorUnionConstant; -import com.ibm.wala.dataflow.graph.ITransferFunctionProvider; -import com.ibm.wala.fixpoint.BitVectorVariable; -import com.ibm.wala.fixpoint.UnaryOperator; -import com.ibm.wala.util.CancelException; -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.intset.BitVector; -import com.ibm.wala.util.intset.MutableMapping; -import com.ibm.wala.util.intset.OrdinalSetMapping; - -/** - * Simple Regression test for a graph-based dataflow problem - */ -public class GraphDataflowTest extends WalaTestCase { - - public static final String nodeNames = "ABCDEFGH"; - protected final static String[] nodes = new String[nodeNames.length()]; - - private static BitVector zero() { - BitVector b = new BitVector(); - b.set(0); - return b; - } - - private static BitVector one() { - BitVector b = new BitVector(); - b.set(1); - return b; - } - - /** - * A simple test of the GraphBitVectorDataflow system - * @throws CancelException - */ - @Test public void testSolverNodeEdge() throws CancelException { - Graph G = buildGraph(); - String result = solveNodeEdge(G); - System.err.println(result); - if (!result.equals(expectedStringNodeEdge())) { - System.err.println("Uh oh."); - System.err.println(expectedStringNodeEdge()); - } - Assert.assertEquals(expectedStringNodeEdge(), result); - } - - @Test public void testSolverNodeOnly() throws CancelException { - Graph G = buildGraph(); - String result = solveNodeOnly(G); - System.err.println(result); - Assert.assertEquals(expectedStringNodeOnly(), result); - } - - /** - * @return the expected dataflow result as a String - */ - public static String expectedStringNodeOnly() { - StringBuffer result = new StringBuffer("------\n"); - result.append("Node A(0) = { 0 }\n"); - result.append("Node B(1) = { 0 1 }\n"); - result.append("Node C(2) = { 0 1 2 }\n"); - result.append("Node D(3) = { 0 1 3 }\n"); - result.append("Node E(4) = { 0 1 2 3 4 }\n"); - result.append("Node F(5) = { 0 1 2 3 4 5 }\n"); - result.append("Node G(6) = { 6 }\n"); - result.append("Node H(7) = { 7 }\n"); - return result.toString(); - } - - public static String expectedStringNodeEdge() { - StringBuffer result = new StringBuffer("------\n"); - result.append("Node A(0) = { 0 }\n"); - result.append("Node B(1) = { 0 1 }\n"); - result.append("Node C(2) = { 0 2 }\n"); - result.append("Node D(3) = { 1 3 }\n"); - result.append("Node E(4) = { 0 1 2 3 4 }\n"); - result.append("Node F(5) = { 0 1 2 3 4 5 }\n"); - result.append("Node G(6) = { 6 }\n"); - result.append("Node H(7) = { 7 }\n"); - return result.toString(); - } - - /** - * @return a graph with the expected structure - */ - private static Graph buildGraph() { - Graph G = SlowSparseNumberedGraph.make(); - for (int i = 0; i < nodeNames.length(); i++) { - String n = nodeNames.substring(i, i + 1); - G.addNode(n); - nodes[i] = n; - } - G.addEdge(nodes[0], nodes[1]); - G.addEdge(nodes[1], nodes[2]); - G.addEdge(nodes[1], nodes[3]); - G.addEdge(nodes[2], nodes[4]); - G.addEdge(nodes[3], nodes[4]); - G.addEdge(nodes[4], nodes[5]); - return G; - } - - /** - * Solve the dataflow system and return the result as a string - * @throws CancelException - */ - private static String solveNodeOnly(Graph G) throws CancelException { - final OrdinalSetMapping values = new MutableMapping(nodes); - ITransferFunctionProvider functions = new ITransferFunctionProvider() { - - public UnaryOperator getNodeTransferFunction(String node) { - return new BitVectorUnionConstant(values.getMappedIndex(node)); - } - - public boolean hasNodeTransferFunctions() { - return true; - } - - public UnaryOperator getEdgeTransferFunction(String from, String to) { - Assertions.UNREACHABLE(); - return null; - } - - public boolean hasEdgeTransferFunctions() { - return false; - } - - public AbstractMeetOperator getMeetOperator() { - return BitVectorUnion.instance(); - } - - }; - - BitVectorFramework F = new BitVectorFramework(G, functions, values); - BitVectorSolver s = new BitVectorSolver(F); - s.solve(null); - return result2String(s); - } - - private static String solveNodeEdge(Graph G) throws CancelException { - final OrdinalSetMapping values = new MutableMapping(nodes); - ITransferFunctionProvider functions = new ITransferFunctionProvider() { - - public UnaryOperator getNodeTransferFunction(String node) { - return new BitVectorUnionConstant(values.getMappedIndex(node)); - } - - public boolean hasNodeTransferFunctions() { - return true; - } - - public UnaryOperator getEdgeTransferFunction(String from, String to) { - if (from == nodes[1] && to == nodes[3]) - return new BitVectorFilter(zero()); - else if (from == nodes[1] && to == nodes[2]) - return new BitVectorFilter(one()); - else { - return BitVectorIdentity.instance(); - } - } - - public boolean hasEdgeTransferFunctions() { - return true; - } - - public AbstractMeetOperator getMeetOperator() { - return BitVectorUnion.instance(); - } - - }; - - BitVectorFramework F = new BitVectorFramework(G, functions, values); - BitVectorSolver s = new BitVectorSolver(F); - s.solve(null); - return result2String(s); - } - - public static String result2String(BitVectorSolver solver) { - StringBuffer result = new StringBuffer("------\n"); - for (int i = 0; i < nodes.length; i++) { - String n = nodes[i]; - BitVectorVariable varI = (BitVectorVariable) solver.getOut(n); - String s = varI.toString(); - result.append("Node " + n + "(" + i + ") = " + s + "\n"); - } - return result.toString(); - } +/******************************************************************************* + * 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.core.tests.basic; + +import org.junit.Assert; +import org.junit.Test; + +import com.ibm.wala.core.tests.util.WalaTestCase; +import com.ibm.wala.dataflow.graph.AbstractMeetOperator; +import com.ibm.wala.dataflow.graph.BitVectorFilter; +import com.ibm.wala.dataflow.graph.BitVectorFramework; +import com.ibm.wala.dataflow.graph.BitVectorIdentity; +import com.ibm.wala.dataflow.graph.BitVectorSolver; +import com.ibm.wala.dataflow.graph.BitVectorUnion; +import com.ibm.wala.dataflow.graph.BitVectorUnionConstant; +import com.ibm.wala.dataflow.graph.ITransferFunctionProvider; +import com.ibm.wala.fixpoint.BitVectorVariable; +import com.ibm.wala.fixpoint.UnaryOperator; +import com.ibm.wala.util.CancelException; +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.intset.BitVector; +import com.ibm.wala.util.intset.MutableMapping; +import com.ibm.wala.util.intset.OrdinalSetMapping; + +/** + * Simple Regression test for a graph-based dataflow problem + */ +public class GraphDataflowTest extends WalaTestCase { + + public static final String nodeNames = "ABCDEFGH"; + protected final static String[] nodes = new String[nodeNames.length()]; + + private static BitVector zero() { + BitVector b = new BitVector(); + b.set(0); + return b; + } + + private static BitVector one() { + BitVector b = new BitVector(); + b.set(1); + return b; + } + + /** + * A simple test of the GraphBitVectorDataflow system + * @throws CancelException + */ + @Test public void testSolverNodeEdge() throws CancelException { + Graph G = buildGraph(); + String result = solveNodeEdge(G); + System.err.println(result); + if (!result.equals(expectedStringNodeEdge())) { + System.err.println("Uh oh."); + System.err.println(expectedStringNodeEdge()); + } + Assert.assertEquals(expectedStringNodeEdge(), result); + } + + @Test public void testSolverNodeOnly() throws CancelException { + Graph G = buildGraph(); + String result = solveNodeOnly(G); + System.err.println(result); + Assert.assertEquals(expectedStringNodeOnly(), result); + } + + /** + * @return the expected dataflow result as a String + */ + public static String expectedStringNodeOnly() { + StringBuffer result = new StringBuffer("------\n"); + result.append("Node A(0) = { 0 }\n"); + result.append("Node B(1) = { 0 1 }\n"); + result.append("Node C(2) = { 0 1 2 }\n"); + result.append("Node D(3) = { 0 1 3 }\n"); + result.append("Node E(4) = { 0 1 2 3 4 }\n"); + result.append("Node F(5) = { 0 1 2 3 4 5 }\n"); + result.append("Node G(6) = { 6 }\n"); + result.append("Node H(7) = { 7 }\n"); + return result.toString(); + } + + public static String expectedStringNodeEdge() { + StringBuffer result = new StringBuffer("------\n"); + result.append("Node A(0) = { 0 }\n"); + result.append("Node B(1) = { 0 1 }\n"); + result.append("Node C(2) = { 0 2 }\n"); + result.append("Node D(3) = { 1 3 }\n"); + result.append("Node E(4) = { 0 1 2 3 4 }\n"); + result.append("Node F(5) = { 0 1 2 3 4 5 }\n"); + result.append("Node G(6) = { 6 }\n"); + result.append("Node H(7) = { 7 }\n"); + return result.toString(); + } + + /** + * @return a graph with the expected structure + */ + private static Graph buildGraph() { + Graph G = SlowSparseNumberedGraph.make(); + for (int i = 0; i < nodeNames.length(); i++) { + String n = nodeNames.substring(i, i + 1); + G.addNode(n); + nodes[i] = n; + } + G.addEdge(nodes[0], nodes[1]); + G.addEdge(nodes[1], nodes[2]); + G.addEdge(nodes[1], nodes[3]); + G.addEdge(nodes[2], nodes[4]); + G.addEdge(nodes[3], nodes[4]); + G.addEdge(nodes[4], nodes[5]); + return G; + } + + /** + * Solve the dataflow system and return the result as a string + * @throws CancelException + */ + private static String solveNodeOnly(Graph G) throws CancelException { + final OrdinalSetMapping values = new MutableMapping(nodes); + ITransferFunctionProvider functions = new ITransferFunctionProvider() { + + public UnaryOperator getNodeTransferFunction(String node) { + return new BitVectorUnionConstant(values.getMappedIndex(node)); + } + + public boolean hasNodeTransferFunctions() { + return true; + } + + public UnaryOperator getEdgeTransferFunction(String from, String to) { + Assertions.UNREACHABLE(); + return null; + } + + public boolean hasEdgeTransferFunctions() { + return false; + } + + public AbstractMeetOperator getMeetOperator() { + return BitVectorUnion.instance(); + } + + }; + + BitVectorFramework F = new BitVectorFramework(G, functions, values); + BitVectorSolver s = new BitVectorSolver(F); + s.solve(null); + return result2String(s); + } + + private static String solveNodeEdge(Graph G) throws CancelException { + final OrdinalSetMapping values = new MutableMapping(nodes); + ITransferFunctionProvider functions = new ITransferFunctionProvider() { + + public UnaryOperator getNodeTransferFunction(String node) { + return new BitVectorUnionConstant(values.getMappedIndex(node)); + } + + public boolean hasNodeTransferFunctions() { + return true; + } + + public UnaryOperator getEdgeTransferFunction(String from, String to) { + if (from == nodes[1] && to == nodes[3]) + return new BitVectorFilter(zero()); + else if (from == nodes[1] && to == nodes[2]) + return new BitVectorFilter(one()); + else { + return BitVectorIdentity.instance(); + } + } + + public boolean hasEdgeTransferFunctions() { + return true; + } + + public AbstractMeetOperator getMeetOperator() { + return BitVectorUnion.instance(); + } + + }; + + BitVectorFramework F = new BitVectorFramework(G, functions, values); + BitVectorSolver s = new BitVectorSolver(F); + s.solve(null); + return result2String(s); + } + + public static String result2String(BitVectorSolver solver) { + StringBuffer result = new StringBuffer("------\n"); + for (int i = 0; i < nodes.length; i++) { + String n = nodes[i]; + BitVectorVariable varI = (BitVectorVariable) solver.getOut(n); + String s = varI.toString(); + result.append("Node " + n + "(" + i + ") = " + s + "\n"); + } + return result.toString(); + } } \ No newline at end of file diff --git a/com.ibm.wala.core.tests/src/com/ibm/wala/core/tests/basic/OrdinalSetTest.java b/com.ibm.wala.core.tests/src/com/ibm/wala/core/tests/basic/OrdinalSetTest.java index 38e4b158d..d39f5354a 100644 --- a/com.ibm.wala.core.tests/src/com/ibm/wala/core/tests/basic/OrdinalSetTest.java +++ b/com.ibm.wala.core.tests/src/com/ibm/wala/core/tests/basic/OrdinalSetTest.java @@ -1,26 +1,26 @@ -/******************************************************************************* - * Copyright (c) 2008 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.core.tests.basic; - -import org.junit.Test; - -import com.ibm.wala.core.tests.util.WalaTestCase; -import com.ibm.wala.util.intset.OrdinalSet; - -/** - * JUnit tests for some {@link OrdinalSet} operations. - */ -public class OrdinalSetTest extends WalaTestCase { - - @Test public void test1() { - OrdinalSet.unify(OrdinalSet.empty(), OrdinalSet.empty()); - } -} +/******************************************************************************* + * Copyright (c) 2008 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.core.tests.basic; + +import org.junit.Test; + +import com.ibm.wala.core.tests.util.WalaTestCase; +import com.ibm.wala.util.intset.OrdinalSet; + +/** + * JUnit tests for some {@link OrdinalSet} operations. + */ +public class OrdinalSetTest extends WalaTestCase { + + @Test public void test1() { + OrdinalSet.unify(OrdinalSet.empty(), OrdinalSet.empty()); + } +} diff --git a/com.ibm.wala.core.tests/src/com/ibm/wala/core/tests/basic/PrimitivesTest.java b/com.ibm.wala.core.tests/src/com/ibm/wala/core/tests/basic/PrimitivesTest.java index 586b7a876..c796323d4 100644 --- a/com.ibm.wala.core.tests/src/com/ibm/wala/core/tests/basic/PrimitivesTest.java +++ b/com.ibm.wala.core.tests/src/com/ibm/wala/core/tests/basic/PrimitivesTest.java @@ -1,1341 +1,1341 @@ -/******************************************************************************* - * 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.core.tests.basic; - -import java.util.Collection; -import java.util.HashSet; -import java.util.Iterator; -import java.util.List; -import java.util.Map; - -import org.junit.Assert; -import org.junit.Test; - -import com.ibm.wala.core.tests.util.WalaTestCase; -import com.ibm.wala.util.collections.BimodalMap; -import com.ibm.wala.util.collections.HashSetFactory; -import com.ibm.wala.util.collections.Iterator2Collection; -import com.ibm.wala.util.collections.SmallMap; -import com.ibm.wala.util.graph.Graph; -import com.ibm.wala.util.graph.NumberedGraph; -import com.ibm.wala.util.graph.dominators.Dominators; -import com.ibm.wala.util.graph.impl.SlowSparseNumberedGraph; -import com.ibm.wala.util.graph.traverse.BFSPathFinder; -import com.ibm.wala.util.graph.traverse.BoundedBFSIterator; -import com.ibm.wala.util.intset.BasicNaturalRelation; -import com.ibm.wala.util.intset.BimodalMutableIntSetFactory; -import com.ibm.wala.util.intset.BitVector; -import com.ibm.wala.util.intset.BitVectorBase; -import com.ibm.wala.util.intset.BitVectorIntSetFactory; -import com.ibm.wala.util.intset.IBinaryNaturalRelation; -import com.ibm.wala.util.intset.IntPair; -import com.ibm.wala.util.intset.IntSet; -import com.ibm.wala.util.intset.IntSetUtil; -import com.ibm.wala.util.intset.IntegerUnionFind; -import com.ibm.wala.util.intset.LongSet; -import com.ibm.wala.util.intset.LongSetUtil; -import com.ibm.wala.util.intset.MutableIntSet; -import com.ibm.wala.util.intset.MutableIntSetFactory; -import com.ibm.wala.util.intset.MutableLongSet; -import com.ibm.wala.util.intset.MutableLongSetFactory; -import com.ibm.wala.util.intset.MutableSharedBitVectorIntSetFactory; -import com.ibm.wala.util.intset.MutableSparseIntSetFactory; -import com.ibm.wala.util.intset.MutableSparseLongSetFactory; -import com.ibm.wala.util.intset.OffsetBitVector; -import com.ibm.wala.util.intset.SemiSparseMutableIntSet; -import com.ibm.wala.util.intset.SemiSparseMutableIntSetFactory; -import com.ibm.wala.util.intset.SparseIntSet; -import com.ibm.wala.util.intset.SparseLongSet; - -/** - * JUnit tests for some primitive operations. - */ -public class PrimitivesTest extends WalaTestCase { - - - /** - * Test the MutableSparseIntSet implementation - */ - private void doMutableIntSet(MutableIntSetFactory factory) { - MutableIntSet v = factory.parse("{9,17}"); - MutableIntSet w = factory.make(new int[] {}); - MutableIntSet x = factory.make(new int[] { 7, 4, 2, 4, 2, 2 }); - MutableIntSet y = factory.make(new int[] { 7, 7, 7, 2, 7, 1 }); - MutableIntSet z = factory.parse("{ 9 }"); - - System.err.println(w); // { } - System.err.println(x); // { 2 4 7 } - System.err.println(y); // { 1 2 7 } - System.err.println(z); // { 9 } - - MutableIntSet temp = factory.makeCopy(x); - temp.intersectWith(y); - System.err.println(temp); // { 2 7 } - temp.copySet(x); - temp.addAll(y); - System.err.println(temp); // { 1 2 4 7 } - temp.copySet(x); - System.err.println(IntSetUtil.diff(x, y, factory)); // { 4 } - System.err.println(IntSetUtil.diff(v, z, factory)); // { 17 } - System.err.println(IntSetUtil.diff(z, v, factory)); // { } - - // Assert.assertTrue(x.union(z).intersection(y.union(z)).equals(x.intersection(y).union(z))); - MutableIntSet temp1 = factory.makeCopy(x); - MutableIntSet temp2 = factory.makeCopy(x); - MutableIntSet tempY = factory.makeCopy(y); - temp1.addAll(z); - tempY.addAll(z); - temp1.intersectWith(tempY); - temp2.intersectWith(y); - temp2.addAll(z); - Assert.assertTrue(temp1.sameValue(temp2)); - - // Assert.assertTrue(x.union(z).diff(z).equals(x)); - Assert.assertTrue(w.isEmpty()); - Assert.assertTrue(IntSetUtil.diff(x, x, factory).isEmpty()); - Assert.assertTrue(IntSetUtil.diff(z, v, factory).isEmpty()); - Assert.assertTrue(IntSetUtil.diff(v, z, factory).sameValue(SparseIntSet.singleton(17))); - Assert.assertTrue(IntSetUtil.diff(z, v, factory).isEmpty()); - Assert.assertTrue(z.isSubset(v)); - temp = factory.make(); - temp.add(4); - System.err.println(temp); // { 4 } - temp.add(7); - System.err.println(temp); // { 4 7 } - temp.add(2); - System.err.println(temp); // { 2 4 7 } - System.err.println(x); // { 2 4 7 } - Assert.assertTrue(temp.sameValue(x)); - - MutableIntSet a = factory.parse("{1,3,5,7,9,11,13,15,17,19,21,23,25,27,29,31,33,35,37,39,41,43,45,47,49,51,53,55,57,59}"); - System.err.println(a); // { 1 3 5 7 9 11 13 15 17 19 21 23 25 27 29 31 33 - // 35 - // 37 39 41 43 45 47 49 51 53 55 57 59 } - Assert.assertTrue(a.sameValue(a)); - IntSet i = a.intersection(temp); - Assert.assertTrue(i.sameValue(SparseIntSet.singleton(7))); - a.add(100); - Assert.assertTrue(a.sameValue(a)); - - MutableIntSet b = factory.parse("{1,3,5,7,9,11,13,15,17,19,21,23,25,27,29,31,33,35,37,39,41,43,45,47,49,51,53,55,57,59,100}"); - Assert.assertTrue(a.sameValue(b)); - Assert.assertTrue(a.isSubset(b)); - - IntSet f = IntSetUtil.diff(b, factory.parse("{7,8,9}"), factory); - System.err.println(f); - Assert.assertFalse(f.contains(7)); - Assert.assertFalse(f.contains(8)); - Assert.assertFalse(f.contains(9)); - Assert.assertFalse(f.sameValue(b)); - Assert.assertTrue(f.isSubset(b)); - - IntSet tmp = factory.parse("{2,4,6,8,10,12,14,16,18,20,22,24,26,28,30,32,34,36,38,40,42,44,46,48,50,51,53,55,57,59,61,63}"); - f = IntSetUtil.diff(b, tmp, factory); - System.err.println(f); - Assert.assertFalse(f.sameValue(b)); - Assert.assertTrue(f.isSubset(b)); - Assert.assertFalse(f.contains(51)); - Assert.assertFalse(f.contains(53)); - Assert.assertFalse(f.contains(55)); - Assert.assertFalse(f.contains(57)); - Assert.assertFalse(f.contains(59)); - Assert.assertTrue(f.contains(100)); - - tmp = factory.parse("{2,4,6,8,10,12,14,16,18,20,22,24,26,28,30,32,34,36,38,40,42,44,46,48,50,51,53,55,57,59,61,63,100}"); - f = IntSetUtil.diff(b, tmp, factory); - System.err.println(f); - Assert.assertFalse(f.sameValue(b)); - Assert.assertTrue(f.isSubset(b)); - Assert.assertFalse(f.contains(51)); - Assert.assertFalse(f.contains(53)); - Assert.assertFalse(f.contains(55)); - Assert.assertFalse(f.contains(57)); - Assert.assertFalse(f.contains(59)); - Assert.assertFalse(f.contains(100)); - - b = factory.makeCopy(a); - Assert.assertTrue(a.sameValue(b)); - b.remove(1); - b.add(0); - Assert.assertTrue(!a.sameValue(b)); - - a = factory.parse("{1}"); - Assert.assertFalse(a.isSubset(b)); - b.remove(0); - Assert.assertFalse(a.isSubset(b)); - a.remove(1); - Assert.assertTrue(a.isEmpty()); - i = a.intersection(temp); - Assert.assertTrue(a.isEmpty()); - - temp2 = factory.make(); - Assert.assertTrue(temp2.sameValue(a)); - - a = factory.parse("{2,4,6,8,10,12,14,16,18,20,22,24,26,28,30,32,34,36,38,40,42,44,46,48,50,51,53,55,57,59,61,63}"); - b = factory.parse("{2,4,6,8,10,12,14,16,18,20,22,24,26,28,30,32,34,36,38,40,42,44,46,48,50,52,54,56,58,60,62}"); - MutableIntSet c = factory.parse("{2,4,6,8,10,12,14,16,18,20,22,24,26,28,30,32,34,36,38,40,42,44,46,48,50}"); - MutableIntSet d = factory.parse("{2,4,6,8,10,12,14,16,18,20,22,24,26,28,30,32,34,36,38,40,42,44,46,48,50}"); - MutableIntSet e = factory.parse("{2,4,6,8,10,12,14,16,18,20,22,24,26,28,30,32,34}"); - - Assert.assertTrue(e.isSubset(d)); - e.addAll(d); - Assert.assertTrue(e.isSubset(d)); - e.remove(12); - Assert.assertTrue(e.isSubset(d)); - e.add(105); - Assert.assertFalse(e.isSubset(d)); - - Assert.assertFalse(b.isSubset(a)); - - b.add(53); - Assert.assertFalse(b.isSubset(a)); - - a.add(52); - a.remove(52); - Assert.assertFalse(b.isSubset(a)); - - c.add(55); - Assert.assertFalse(c.isSubset(b)); - - d.add(53); - Assert.assertTrue(d.isSubset(b)); - - d = factory.make(); - d.copySet(c); - Assert.assertFalse(d.isSubset(b)); - - a = factory.parse("{2,4,6,8,10,12,14,16,18,20,22,24,26,28,30,32,34,36,38,40,42,44,46,48,50}"); - b = factory.parse("{2,4,6,8,10,12,14,16,18,20,22,24,26,28,30,32,34,36,38,40,42,44,46,48}"); - Assert.assertFalse(a.sameValue(b)); - b.add(50); - Assert.assertTrue(a.sameValue(b)); - a.add(11); - b.add(11); - Assert.assertTrue(a.sameValue(b)); - - a = factory.parse("{2,4,6,8,10,12,14,16,18,20,50}"); - b = factory.parse("{24,26,28,30,32,34,36,38,40,42,44,46,48}"); - c = factory.parse("{2,4,6,8,10,12,14,16,18,20,22,24,26,28,30,32,34,36,38,40,42,44,46,48,50}"); - a.addAll(b); - a.add(22); - Assert.assertTrue(a.sameValue(c)); - - a = factory.parse("{2,4,6,8,10,12,14,16,18,20,50}"); - b = factory.parse("{24,26,28,30,32,34,36,38,40,42,44,46,48}"); - c = factory.parse("{2,4,6,8,10,12,14,16,18,20,22,24,26,28,30,32,34,36,38,40,42,44,46,48,50}"); - b.addAll(factory.parse("{22}")); - a.addAll(b); - Assert.assertTrue(a.sameValue(c)); - - a = factory.parse("{2,4,6,8,10,12,14,16,18,20}"); - b = factory.parse("{22,24,26,28,30,32,34,36,38,40,42,44,46,48}"); - c = factory.parse("{2,4,6,8,10,12,14,16,18,20,22,24,26,28,30,32,34,36,38,40,42,44,46,48,50}"); - c.remove(22); - a.addAll(b); - Assert.assertFalse(a.sameValue(c)); - - a = factory.parse("{1,3,5,7,9,11,13,15,17,19,21,23,25,27,29,31,33,35,37,39,41,43,45,47,49,51,53,55,57,59}"); - System.err.println(a); // { 1 3 5 7 9 11 13 15 17 19 21 23 25 27 29 31 33 - // 35 - // 37 39 41 43 45 47 49 51 53 55 57 59 } - Assert.assertTrue(a.sameValue(a)); - i = a.intersection(temp); - Assert.assertTrue(i.sameValue(SparseIntSet.singleton(7))); - a.add(100); - Assert.assertTrue(a.sameValue(a)); - - b = factory.parse("{1,3,5,7,9,11,13,15,17,19,21,23,25,27,29,31,33,35,37,39,41,43,45,47,49,51,53,55,57,59,100}"); - Assert.assertTrue(a.sameValue(b)); - Assert.assertTrue(a.isSubset(b)); - - b = factory.makeCopy(a); - Assert.assertTrue(a.sameValue(b)); - b.remove(1); - b.add(0); - Assert.assertTrue(!a.sameValue(b)); - - a.clear(); - Assert.assertTrue(a.isEmpty()); - - a = factory.parse("{1}"); - Assert.assertFalse(a.isSubset(b)); - b.remove(0); - Assert.assertFalse(a.isSubset(b)); - a.remove(1); - Assert.assertTrue(a.isEmpty()); - i = a.intersection(temp); - Assert.assertTrue(a.isEmpty()); - - temp2 = factory.make(); - Assert.assertTrue(temp2.sameValue(a)); - - for (int idx = 500; idx < 550;) { - for (int xx = 0; xx < 50; xx++, idx++) { - temp2.add(idx); - } - System.err.println(temp2); - } - - for (int idx = 3000; idx < 3200;) { - for (int xx = 0; xx < 50; xx++, idx++) { - temp2.add(idx); - } - System.err.println(temp2); - } - - temp2.clear(); - Assert.assertTrue(temp2.isEmpty()); - - temp2 = factory.make(); - Assert.assertTrue(temp2.sameValue(a)); - - for (int idx = 500; idx < 550;) { - for (int xx = 0; xx < 50; xx++, idx++) { - temp2.add(idx); - } - System.err.println(temp2); - } - - for (int idx = 0; idx < 25; idx++) { - temp2.add(idx); - System.err.println(temp2); - } - - temp2.clear(); - Assert.assertTrue(temp2.isEmpty()); - } - - /** - * Test the MutableSharedBitVectorIntSet implementation - */ - @Test public void testMutableSharedBitVectorIntSet() { - doMutableIntSet(new MutableSharedBitVectorIntSetFactory()); - } - - /** - * Test the MutableSparseIntSet implementation - */ - @Test public void testMutableSparseIntSet() { - doMutableIntSet(new MutableSparseIntSetFactory()); - } - - /** - * Test the BimodalMutableSparseIntSet implementation - */ - @Test public void testBimodalMutableSparseIntSet() { - doMutableIntSet(new BimodalMutableIntSetFactory()); - } - - /** - * Test the BitVectorIntSet implementation - */ - @Test public void testBitVectorIntSet() { - doMutableIntSet(new BitVectorIntSetFactory()); - } - - /** - * Test the SemiSparseMutableIntSet implementation - */ - @Test public void testSemiSparseMutableIntSet() { - doMutableIntSet(new SemiSparseMutableIntSetFactory()); - } - - /** - * Test the MutableSparseIntSet implementation - */ - private void doMutableLongSet(MutableLongSetFactory factory) { - MutableLongSet v = factory.parse("{9,17}"); - MutableLongSet w = factory.make(new long[] {}); - MutableLongSet x = factory.make(new long[] { 7, 4, 2, 4, 2, 2 }); - MutableLongSet y = factory.make(new long[] { 7, 7, 7, 2, 7, 1 }); - MutableLongSet z = factory.parse("{ 9 }"); - - System.err.println(w); // { } - System.err.println(x); // { 2 4 7 } - System.err.println(y); // { 1 2 7 } - System.err.println(z); // { 9 } - - MutableLongSet temp = factory.makeCopy(x); - temp.intersectWith(y); - System.err.println(temp); // { 2 7 } - temp.copySet(x); - temp.addAll(y); - System.err.println(temp); // { 1 2 4 7 } - temp.copySet(x); - System.err.println(LongSetUtil.diff(x, y, factory)); // { 4 } - System.err.println(LongSetUtil.diff(v, z, factory)); // { 17 } - System.err.println(LongSetUtil.diff(z, v, factory)); // { } - - // Assert.assertTrue(x.union(z).intersection(y.union(z)).equals(x.intersection(y).union(z))); - MutableLongSet temp1 = factory.makeCopy(x); - MutableLongSet temp2 = factory.makeCopy(x); - MutableLongSet tempY = factory.makeCopy(y); - temp1.addAll(z); - tempY.addAll(z); - temp1.intersectWith(tempY); - temp2.intersectWith(y); - temp2.addAll(z); - Assert.assertTrue(temp1.sameValue(temp2)); - - // Assert.assertTrue(x.union(z).diff(z).equals(x)); - Assert.assertTrue(w.isEmpty()); - Assert.assertTrue(LongSetUtil.diff(x, x, factory).isEmpty()); - Assert.assertTrue(LongSetUtil.diff(z, v, factory).isEmpty()); - Assert.assertTrue(LongSetUtil.diff(v, z, factory).sameValue(SparseLongSet.singleton(17))); - Assert.assertTrue(LongSetUtil.diff(z, v, factory).isEmpty()); - Assert.assertTrue(z.isSubset(v)); - temp = factory.make(); - temp.add(4); - System.err.println(temp); // { 4 } - temp.add(7); - System.err.println(temp); // { 4 7 } - temp.add(2); - System.err.println(temp); // { 2 4 7 } - System.err.println(x); // { 2 4 7 } - Assert.assertTrue(temp.sameValue(x)); - - MutableLongSet a = factory.parse("{1,3,5,7,9,11,13,15,17,19,21,23,25,27,29,31,33,35,37,39,41,43,45,47,49,51,53,55,57,59}"); - System.err.println(a); // { 1 3 5 7 9 11 13 15 17 19 21 23 25 27 29 31 33 - // 35 - // 37 39 41 43 45 47 49 51 53 55 57 59 } - Assert.assertTrue(a.sameValue(a)); - LongSet i = a.intersection(temp); - Assert.assertTrue(i.sameValue(SparseLongSet.singleton(7))); - a.add(100); - Assert.assertTrue(a.sameValue(a)); - - MutableLongSet b = factory.parse("{1,3,5,7,9,11,13,15,17,19,21,23,25,27,29,31,33,35,37,39,41,43,45,47,49,51,53,55,57,59,100}"); - Assert.assertTrue(a.sameValue(b)); - Assert.assertTrue(a.isSubset(b)); - - LongSet f = LongSetUtil.diff(b, factory.parse("{7,8,9}"), factory); - System.err.println(f); - Assert.assertFalse(f.contains(7)); - Assert.assertFalse(f.contains(8)); - Assert.assertFalse(f.contains(9)); - Assert.assertFalse(f.sameValue(b)); - Assert.assertTrue(f.isSubset(b)); - - LongSet tmp = factory.parse("{2,4,6,8,10,12,14,16,18,20,22,24,26,28,30,32,34,36,38,40,42,44,46,48,50,51,53,55,57,59,61,63}"); - f = LongSetUtil.diff(b, tmp, factory); - System.err.println(f); - Assert.assertFalse(f.sameValue(b)); - Assert.assertTrue(f.isSubset(b)); - Assert.assertFalse(f.contains(51)); - Assert.assertFalse(f.contains(53)); - Assert.assertFalse(f.contains(55)); - Assert.assertFalse(f.contains(57)); - Assert.assertFalse(f.contains(59)); - Assert.assertTrue(f.contains(100)); - - tmp = factory.parse("{2,4,6,8,10,12,14,16,18,20,22,24,26,28,30,32,34,36,38,40,42,44,46,48,50,51,53,55,57,59,61,63,100}"); - f = LongSetUtil.diff(b, tmp, factory); - System.err.println(f); - Assert.assertFalse(f.sameValue(b)); - Assert.assertTrue(f.isSubset(b)); - Assert.assertFalse(f.contains(51)); - Assert.assertFalse(f.contains(53)); - Assert.assertFalse(f.contains(55)); - Assert.assertFalse(f.contains(57)); - Assert.assertFalse(f.contains(59)); - Assert.assertFalse(f.contains(100)); - - b = factory.makeCopy(a); - Assert.assertTrue(a.sameValue(b)); - b.remove(1); - b.add(0); - Assert.assertTrue(!a.sameValue(b)); - - a = factory.parse("{1}"); - Assert.assertFalse(a.isSubset(b)); - b.remove(0); - Assert.assertFalse(a.isSubset(b)); - a.remove(1); - Assert.assertTrue(a.isEmpty()); - i = a.intersection(temp); - Assert.assertTrue(a.isEmpty()); - - temp2 = factory.make(); - Assert.assertTrue(temp2.sameValue(a)); - - a = factory.parse("{2,4,6,8,10,12,14,16,18,20,22,24,26,28,30,32,34,36,38,40,42,44,46,48,50,51,53,55,57,59,61,63}"); - b = factory.parse("{2,4,6,8,10,12,14,16,18,20,22,24,26,28,30,32,34,36,38,40,42,44,46,48,50,52,54,56,58,60,62}"); - MutableLongSet c = factory.parse("{2,4,6,8,10,12,14,16,18,20,22,24,26,28,30,32,34,36,38,40,42,44,46,48,50}"); - MutableLongSet d = factory.parse("{2,4,6,8,10,12,14,16,18,20,22,24,26,28,30,32,34,36,38,40,42,44,46,48,50}"); - MutableLongSet e = factory.parse("{2,4,6,8,10,12,14,16,18,20,22,24,26,28,30,32,34}"); - - Assert.assertTrue(e.isSubset(d)); - e.addAll(d); - Assert.assertTrue(e.isSubset(d)); - e.remove(12); - Assert.assertTrue(e.isSubset(d)); - e.add(105); - Assert.assertFalse(e.isSubset(d)); - - Assert.assertFalse(b.isSubset(a)); - - b.add(53); - Assert.assertFalse(b.isSubset(a)); - - a.add(52); - a.remove(52); - Assert.assertFalse(b.isSubset(a)); - - c.add(55); - Assert.assertFalse(c.isSubset(b)); - - d.add(53); - Assert.assertTrue(d.isSubset(b)); - - d = factory.make(); - d.copySet(c); - Assert.assertFalse(d.isSubset(b)); - - a = factory.parse("{2,4,6,8,10,12,14,16,18,20,22,24,26,28,30,32,34,36,38,40,42,44,46,48,50}"); - b = factory.parse("{2,4,6,8,10,12,14,16,18,20,22,24,26,28,30,32,34,36,38,40,42,44,46,48}"); - Assert.assertFalse(a.sameValue(b)); - b.add(50); - Assert.assertTrue(a.sameValue(b)); - a.add(11); - b.add(11); - Assert.assertTrue(a.sameValue(b)); - - a = factory.parse("{2,4,6,8,10,12,14,16,18,20,50}"); - b = factory.parse("{24,26,28,30,32,34,36,38,40,42,44,46,48}"); - c = factory.parse("{2,4,6,8,10,12,14,16,18,20,22,24,26,28,30,32,34,36,38,40,42,44,46,48,50}"); - a.addAll(b); - a.add(22); - Assert.assertTrue(a.sameValue(c)); - - a = factory.parse("{2,4,6,8,10,12,14,16,18,20,50}"); - b = factory.parse("{24,26,28,30,32,34,36,38,40,42,44,46,48}"); - c = factory.parse("{2,4,6,8,10,12,14,16,18,20,22,24,26,28,30,32,34,36,38,40,42,44,46,48,50}"); - b.addAll(factory.parse("{22}")); - a.addAll(b); - Assert.assertTrue(a.sameValue(c)); - - a = factory.parse("{2,4,6,8,10,12,14,16,18,20}"); - b = factory.parse("{22,24,26,28,30,32,34,36,38,40,42,44,46,48}"); - c = factory.parse("{2,4,6,8,10,12,14,16,18,20,22,24,26,28,30,32,34,36,38,40,42,44,46,48,50}"); - c.remove(22); - a.addAll(b); - Assert.assertFalse(a.sameValue(c)); - - a = factory.parse("{1,3,5,7,9,11,13,15,17,19,21,23,25,27,29,31,33,35,37,39,41,43,45,47,49,51,53,55,57,59}"); - System.err.println(a); // { 1 3 5 7 9 11 13 15 17 19 21 23 25 27 29 31 33 - // 35 - // 37 39 41 43 45 47 49 51 53 55 57 59 } - Assert.assertTrue(a.sameValue(a)); - i = a.intersection(temp); - Assert.assertTrue(i.sameValue(SparseLongSet.singleton(7))); - a.add(100); - Assert.assertTrue(a.sameValue(a)); - - b = factory.parse("{1,3,5,7,9,11,13,15,17,19,21,23,25,27,29,31,33,35,37,39,41,43,45,47,49,51,53,55,57,59,100}"); - Assert.assertTrue(a.sameValue(b)); - Assert.assertTrue(a.isSubset(b)); - - b = factory.makeCopy(a); - Assert.assertTrue(a.sameValue(b)); - b.remove(1); - b.add(0); - Assert.assertTrue(!a.sameValue(b)); - - a = factory.parse("{1}"); - Assert.assertFalse(a.isSubset(b)); - b.remove(0); - Assert.assertFalse(a.isSubset(b)); - a.remove(1); - Assert.assertTrue(a.isEmpty()); - i = a.intersection(temp); - Assert.assertTrue(a.isEmpty()); - - temp2 = factory.make(); - Assert.assertTrue(temp2.sameValue(a)); - - for (int idx = 500; idx < 550;) { - for (int xx = 0; xx < 50; xx++, idx++) { - temp2.add(idx); - } - System.err.println(temp2); - } - - for (int idx = 3000; idx < 3200;) { - for (int xx = 0; xx < 50; xx++, idx++) { - temp2.add(idx); - } - System.err.println(temp2); - } - - temp2 = factory.make(); - Assert.assertTrue(temp2.sameValue(a)); - - for (int idx = 500; idx < 550;) { - for (int xx = 0; xx < 50; xx++, idx++) { - temp2.add(idx); - } - System.err.println(temp2); - } - - for (int idx = 0; idx < 25; idx++) { - temp2.add(idx); - System.err.println(temp2); - } - - } - - /** - * Test the MutableSparseLongSet implementation - */ - @Test public void testMutableSparseLongSet() { - doMutableLongSet(new MutableSparseLongSetFactory()); - } - - @Test public void testSmallMap() { - SmallMap M = new SmallMap(); - Integer I1 = new Integer(1); - Integer I2 = new Integer(2); - Integer I3 = new Integer(3); - M.put(I1, I1); - M.put(I2, I2); - M.put(I3, I3); - - Integer I = (Integer) M.get(new Integer(2)); - Assert.assertTrue(I != null); - Assert.assertTrue(I.equals(I2)); - - I = (Integer) M.get(new Integer(4)); - Assert.assertTrue(I == null); - - I = (Integer) M.put(new Integer(2), new Integer(3)); - Assert.assertTrue(I.equals(I2)); - I = (Integer) M.get(I2); - Assert.assertTrue(I.equals(I3)); - } - - @Test public void testBimodalMap() { - Map M = new BimodalMap(3); - Integer I1 = new Integer(1); - Integer I2 = new Integer(2); - Integer I3 = new Integer(3); - Integer I4 = new Integer(4); - Integer I5 = new Integer(5); - Integer I6 = new Integer(6); - M.put(I1, I1); - M.put(I2, I2); - M.put(I3, I3); - - Integer I = M.get(new Integer(2)); - Assert.assertTrue(I != null); - Assert.assertTrue(I.equals(I2)); - - I = M.get(new Integer(4)); - Assert.assertTrue(I == null); - - I = M.put(new Integer(2), new Integer(3)); - Assert.assertTrue(I.equals(I2)); - I = M.get(I2); - Assert.assertTrue(I.equals(I3)); - - M.put(I4, I4); - M.put(I5, I5); - M.put(I6, I6); - I = M.get(new Integer(4)); - Assert.assertTrue(I != null); - Assert.assertTrue(I.equals(I4)); - - I = M.get(new Integer(7)); - Assert.assertTrue(I == null); - - I = M.put(new Integer(2), new Integer(6)); - Assert.assertTrue(I.equals(I3)); - I = M.get(I2); - Assert.assertTrue(I.equals(I6)); - } - - @Test public void testBFSPathFinder() { - NumberedGraph G = makeBFSTestGraph(); - - // path from 0 to 8 - BFSPathFinder pf = new BFSPathFinder(G, G.getNode(0), G.getNode(8)); - List p = pf.find(); - - // path should be 8, 6, 4, 2, 0 - System.err.println("Path is " + p); - for (int i = 0; i < p.size(); i++) { - Assert.assertTrue((p.get(i)).intValue() == new int[] { 8, 6, 4, 2, 0 }[i]); - } - } - - @Test public void testBoundedBFS() { - NumberedGraph G = makeBFSTestGraph(); - - BoundedBFSIterator bfs = new BoundedBFSIterator(G, G.getNode(0), 0); - Collection c = Iterator2Collection.toSet(bfs); - Assert.assertTrue(c.size() == 1); - - bfs = new BoundedBFSIterator(G, G.getNode(0), 1); - c = Iterator2Collection.toSet(bfs); - Assert.assertTrue(c.size() == 3); - - bfs = new BoundedBFSIterator(G, G.getNode(0), 2); - c = Iterator2Collection.toSet(bfs); - Assert.assertTrue(c.size() == 5); - - bfs = new BoundedBFSIterator(G, G.getNode(0), 3); - c = Iterator2Collection.toSet(bfs); - Assert.assertTrue(c.size() == 7); - - bfs = new BoundedBFSIterator(G, G.getNode(0), 4); - c = Iterator2Collection.toSet(bfs); - Assert.assertTrue(c.size() == 9); - - bfs = new BoundedBFSIterator(G, G.getNode(0), 5); - c = Iterator2Collection.toSet(bfs); - Assert.assertTrue(c.size() == 10); - - bfs = new BoundedBFSIterator(G, G.getNode(0), 500); - c = Iterator2Collection.toSet(bfs); - Assert.assertTrue(c.size() == 10); - } - - private NumberedGraph makeBFSTestGraph() { - // test graph - NumberedGraph G = SlowSparseNumberedGraph.make(); - - // add 10 nodes - Integer[] nodes = new Integer[10]; - for (int i = 0; i < nodes.length; i++) - G.addNode(nodes[i] = new Integer(i)); - - // edges to i-1, i+1, i+2 - for (int i = 0; i < nodes.length; i++) { - if (i > 0) { - G.addEdge(nodes[i], nodes[i - 1]); - } - if (i < nodes.length - 1) { - G.addEdge(nodes[i], nodes[i + 1]); - if (i < nodes.length - 2) { - G.addEdge(nodes[i], nodes[i + 2]); - } - } - } - return G; - } - - @Test public void testDominatorsA() { - // test graph - Graph G = SlowSparseNumberedGraph.make(); - - // add nodes - Object[] nodes = new Object[11]; - for (int i = 0; i < nodes.length; i++) - G.addNode(nodes[i] = new Integer(i)); - - // add edges - G.addEdge(nodes[10], nodes[0]); - G.addEdge(nodes[10], nodes[1]); - G.addEdge(nodes[0], nodes[2]); - G.addEdge(nodes[1], nodes[3]); - G.addEdge(nodes[2], nodes[5]); - G.addEdge(nodes[3], nodes[5]); - G.addEdge(nodes[4], nodes[2]); - G.addEdge(nodes[5], nodes[8]); - G.addEdge(nodes[6], nodes[3]); - G.addEdge(nodes[7], nodes[4]); - G.addEdge(nodes[8], nodes[7]); - G.addEdge(nodes[8], nodes[9]); - G.addEdge(nodes[9], nodes[6]); - - // compute dominators - Dominators D = Dominators.make(G, nodes[10]); - - // Assert.assertions - int i = 0; - Object[] desired4 = new Object[] { nodes[4], nodes[7], nodes[8], nodes[5], nodes[10] }; - for (Iterator d4 = D.dominators(nodes[4]); d4.hasNext();) - Assert.assertTrue(d4.next() == desired4[i++]); - - int j = 0; - Object[] desired5 = new Object[] { nodes[8] }; - for (Iterator t4 = D.dominatorTree().getSuccNodes(nodes[5]); t4.hasNext();) { - Object o4 = t4.next(); - Object d = desired5[j++]; - boolean ok = (o4.equals(d)); - if (!ok) { - System.err.println("O4: " + o4); - System.err.println("desired " + d); - Assert.assertTrue(o4.equals(d)); - } - - } - - Assert.assertTrue(D.dominatorTree().getSuccNodeCount(nodes[10]) == 5); - } - - @Test public void testBinaryIntegerRelation() { - byte[] impl = new byte[] { BasicNaturalRelation.SIMPLE, BasicNaturalRelation.TWO_LEVEL, BasicNaturalRelation.SIMPLE }; - IBinaryNaturalRelation R = new BasicNaturalRelation(impl, BasicNaturalRelation.TWO_LEVEL); - R.add(3, 5); - R.add(3, 7); - R.add(3, 9); - R.add(3, 11); - R.add(5, 1); - int count = 0; - for (Iterator it = R.iterator(); it.hasNext();) { - System.err.println(it.next()); - count++; - } - Assert.assertTrue(count == 5); - - IntSet x = R.getRelated(3); - Assert.assertTrue(x.size() == 4); - - x = R.getRelated(5); - Assert.assertTrue(x.size() == 1); - - R.remove(5, 1); - x = R.getRelated(5); - Assert.assertTrue(x == null); - - R.add(2, 1); - R.add(2, 2); - R.remove(2, 1); - x = R.getRelated(2); - Assert.assertTrue(x.size() == 1); - - R.removeAll(3); - x = R.getRelated(3); - Assert.assertTrue(x == null); - - x = R.getRelated(0); - Assert.assertTrue(x == null); - - for (int i = 0; i < 100; i++) { - R.add(1, i); - } - Assert.assertTrue(R.getRelated(1).size() == 100); - R.remove(1, 1); - Assert.assertTrue(R.getRelated(1).size() == 99); - } - - @Test public void testUnionFind() { - int SIZE = 10000; - IntegerUnionFind uf = new IntegerUnionFind(SIZE); - int count = countEquivalenceClasses(uf); - Assert.assertTrue("Got count " + count, count == SIZE); - - uf.union(3, 7); - Assert.assertTrue(uf.find(3) == uf.find(7)); - Assert.assertTrue("Got uf.find(3)=" + uf.find(3), uf.find(3) == 3 || uf.find(3) == 7); - - uf.union(7, SIZE - 1); - Assert.assertTrue(uf.find(3) == uf.find(SIZE - 1)); - Assert.assertTrue("Got uf.find(3)=" + uf.find(3), uf.find(3) == 3 || uf.find(3) == 7 || uf.find(3) == SIZE - 1); - - for (int i = 0; i < SIZE - 1; i++) { - uf.union(i, i + 1); - } - count = countEquivalenceClasses(uf); - Assert.assertTrue("Got count " + count, count == 1); - - uf = new IntegerUnionFind(SIZE); - for (int i = 0; i < SIZE; i++) { - if ((i % 2) == 0) { - uf.union(i, 0); - } else { - uf.union(i, 1); - } - } - count = countEquivalenceClasses(uf); - Assert.assertTrue("Got count " + count, count == 2); - } - - private int countEquivalenceClasses(IntegerUnionFind uf) { - HashSet s = HashSetFactory.make(); - for (int i = 0; i < uf.size(); i++) { - s.add(new Integer(uf.find(i))); - } - return s.size(); - } - - @Test public void testBitVector() { - testSingleBitVector(new BitVector()); - } - - @Test public void testOffsetBitVector0_10() { - testSingleBitVector(new OffsetBitVector(0, 10)); - } - - @Test public void testOffsetBitVector10_10() { - testSingleBitVector(new OffsetBitVector(10, 10)); - } - - @Test public void testOffsetBitVector50_10() { - testSingleBitVector(new OffsetBitVector(50, 10)); - } - - @Test public void testOffsetBitVector50_50() { - testSingleBitVector(new OffsetBitVector(50, 50)); - } - - @Test public void testOffsetBitVector100_10() { - testSingleBitVector(new OffsetBitVector(100, 10)); - } - - @SuppressWarnings("unchecked") - private void testSingleBitVector(BitVectorBase bv) { - // does the following not automatically scale the bitvector to - // a reasonable size? - bv.set(55); - - Assert.assertTrue("bv.max() is " + bv.max(), bv.max() == 55); - Assert.assertTrue(bv.get(55)); - - bv.set(59); - Assert.assertTrue(bv.max() == 59); - Assert.assertTrue(bv.get(55)); - Assert.assertTrue(bv.get(59)); - - { - boolean[] gets = new boolean[] { false, true, true }; - int[] bits = new int[] { 0, 55, 59 }; - for (int i = 0, j = 0; i != -1; i = bv.nextSetBit(i + 1), j++) { - Assert.assertTrue(i == bits[j]); - Assert.assertTrue(bv.get(i) == gets[j]); - } - } - - bv.set(77); - - Assert.assertTrue("bv.max() is " + bv.max(), bv.max() == 77); - { - boolean[] gets = new boolean[] { false, true, true, true }; - int[] bits = new int[] { 0, 55, 59, 77 }; - for (int i = 0, j = 0; i != -1; i = bv.nextSetBit(i + 1), j++) { - Assert.assertTrue(i == bits[j]); - Assert.assertTrue(bv.get(i) == gets[j]); - } - } - - bv.set(3); - Assert.assertTrue("bv.max() is " + bv.max(), bv.max() == 77); - { - boolean[] gets = new boolean[] { false, true, true, true, true }; - int[] bits = new int[] { 0, 3, 55, 59, 77 }; - for (int i = 0, j = 0; i != -1; i = bv.nextSetBit(i + 1), j++) { - Assert.assertTrue(i == bits[j]); - Assert.assertTrue(bv.get(i) == gets[j]); - } - } - - System.err.println(bv); - } - - @Test public void testBitVectors() { - testBitVectors(new BitVector(), new BitVector()); - } - - @Test public void testOffsetBitVectors150_10() { - testBitVectors(new OffsetBitVector(150, 10), new OffsetBitVector(150, 10)); - } - - @Test public void testOffsetBitVectors100_200_10() { - testBitVectors(new OffsetBitVector(100, 10), new OffsetBitVector(200, 10)); - } - - @Test public void testOffsetBitVectors100_25_10() { - testBitVectors(new OffsetBitVector(100, 10), new OffsetBitVector(25, 10)); - } - - @Test public void testOffsetBitVectors35_25_20_10() { - testBitVectors(new OffsetBitVector(35, 20), new OffsetBitVector(25, 10)); - } - - @SuppressWarnings("unchecked") - private void testBitVectors(T v1, T v2) { - v1.set(100); - v1.set(101); - v1.set(102); - Assert.assertTrue("v1.max() is " + v1.max(), v1.max() == 102); - - v2.set(200); - v2.set(201); - v2.set(202); - Assert.assertTrue("v2.max() is " + v2.max(), v2.max() == 202); - - Assert.assertTrue(v1.intersectionEmpty(v2)); - Assert.assertTrue(v2.intersectionEmpty(v1)); - - v1.or(v2); - - System.err.println("v1 = " + v1 + ", v2 = " + v2); - Assert.assertFalse("v1 = " + v1 + ", v2 = " + v2, v1.intersectionEmpty(v2)); - Assert.assertFalse("v1 = " + v1 + ", v2 = " + v2, v2.intersectionEmpty(v1)); - Assert.assertTrue("v1.max() is " + v1.max(), v1.max() == 202); - - { - boolean[] gets = new boolean[] { false, true, true, true, true, true, true }; - int[] bits = new int[] { 0, 100, 101, 102, 200, 201, 202 }; - for (int i = 0, j = 0; i != -1; i = v1.nextSetBit(i + 1), j++) { - Assert.assertTrue(i == bits[j]); - Assert.assertTrue(v1.get(i) == gets[j]); - } - } - - v1.clearAll(); - v2.clearAll(); - - v1.set(100); - v1.set(101); - v1.set(102); - v1.set(103); - v1.set(104); - v1.set(105); - Assert.assertTrue("v1.max() is " + v1.max(), v1.max() == 105); - - v2.set(103); - v2.set(104); - v2.set(200); - v2.set(201); - Assert.assertTrue("v2.max() is " + v2.max(), v2.max() == 201); - - v1.and(v2); - Assert.assertTrue("v1.max() is " + v1.max(), v1.max() == 104); - - { - boolean[] gets = new boolean[] { false, true, true }; - int[] bits = new int[] { 0, 103, 104 }; - for (int i = 0, j = 0; i != -1; i = v1.nextSetBit(i + 1), j++) { - Assert.assertTrue(i == bits[j]); - Assert.assertTrue(v1.get(i) == gets[j]); - } - } - - v1.set(100); - v1.set(101); - v1.set(102); - v1.set(105); - Assert.assertTrue("v1.max() is " + v1.max(), v1.max() == 105); - - { - boolean[] gets = new boolean[] { false, true, true, true, true, true, true }; - int[] bits = new int[] { 0, 100, 101, 102, 103, 104, 105 }; - for (int i = 0, j = 0; i != -1; i = v1.nextSetBit(i + 1), j++) { - Assert.assertTrue(i == bits[j]); - Assert.assertTrue(v1.get(i) == gets[j]); - } - } - - v2.clear(103); - v2.clear(104); - v1.andNot(v2); - - { - boolean[] gets = new boolean[] { false, true, true, true, true, true, true }; - int[] bits = new int[] { 0, 100, 101, 102, 103, 104, 105 }; - for (int i = 0, j = 0; i != -1; i = v1.nextSetBit(i + 1), j++) { - Assert.assertTrue(i == bits[j]); - Assert.assertTrue(v1.get(i) == gets[j]); - } - } - - v2.set(101); - v2.set(102); - - System.err.println("v1 = " + v1 + ", v2 = " + v2); - v1.andNot(v2); - - { - boolean[] gets = new boolean[] { false, true, true, true, true }; - int[] bits = new int[] { 0, 100, 103, 104, 105 }; - for (int i = 0, j = 0; i != -1; i = v1.nextSetBit(i + 1), j++) { - Assert.assertTrue(i == bits[j]); - Assert.assertTrue(v1.get(i) == gets[j]); - } - } - - v1.clearAll(); - v2.clearAll(); - - v1.set(35); - v1.set(101); - v1.set(102); - v1.set(103); - v1.set(104); - v1.set(105); - - v2.set(101); - v2.set(102); - v2.set(104); - v2.set(206); - - System.err.println("v1 = " + v1 + ", v2 = " + v2); - v1.xor(v2); - - { - boolean[] gets = new boolean[] { false, true, true, true, true }; - int[] bits = new int[] { 0, 35, 103, 105, 206 }; - for (int i = 0, j = 0; i != -1; i = v1.nextSetBit(i + 1), j++) { - Assert.assertTrue(i == bits[j]); - Assert.assertTrue(v1.get(i) == gets[j]); - } - } - - v2.set(35); - v2.set(103); - v2.set(105); - - System.err.println("v1 = " + v1 + ", v2 = " + v2); - Assert.assertTrue(v1.isSubset(v2)); - - v2.clearAll(); - v2.set(111); - v2.or(v1); - Assert.assertTrue(v1.isSubset(v2)); - - v2.and(v1); - - Assert.assertTrue(v1.sameBits(v2)); - - v1.clearAll(); - } - - private static OffsetBitVector makeBigTestOffsetVector() { - OffsetBitVector v1 = new OffsetBitVector(50000096, 1024); - v1.set(50000101); - v1.set(50000103); - v1.set(50000112); - v1.set(50000114); - v1.set(50000116); - v1.set(50000126); - v1.set(50000128); - v1.set(50000129); - v1.set(50000135); - v1.set(50000137); - v1.set(50000143); - v1.set(50000148); - v1.set(50000151); - v1.set(50000158); - v1.set(50000163); - v1.set(50000167); - v1.set(50000170); - v1.set(50000173); - v1.set(50000180); - v1.set(50000182); - v1.set(50000185); - v1.set(50000187); - v1.set(50000190); - v1.set(50000194); - v1.set(50000199); - v1.set(50000201); - v1.set(50000204); - v1.set(50000206); - v1.set(50000209); - v1.set(50000210); - v1.set(50000218); - v1.set(50000221); - v1.set(50000223); - v1.set(50000227); - v1.set(50000232); - v1.set(50000234); - v1.set(50000243); - v1.set(50000246); - v1.set(50000250); - v1.set(50000257); - v1.set(50000263); - v1.set(50000268); - v1.set(50000273); - v1.set(50000275); - v1.set(50000278); - v1.set(50000282); - v1.set(50000285); - v1.set(50000290); - v1.set(50000293); - v1.set(50000298); - v1.set(50000300); - v1.set(50000303); - v1.set(50000306); - v1.set(50000308); - v1.set(50000310); - v1.set(50000315); - v1.set(50000325); - v1.set(50000327); - v1.set(50000335); - v1.set(50000337); - v1.set(50000342); - v1.set(50000345); - v1.set(50000349); - v1.set(50000360); - v1.set(50000362); - v1.set(50000369); - v1.set(50000374); - v1.set(50000375); - v1.set(50000378); - v1.set(50000380); - v1.set(50000383); - v1.set(50000384); - v1.set(50000388); - v1.set(50000391); - v1.set(50000400); - v1.set(50000405); - v1.set(50000409); - v1.set(50000414); - v1.set(50000417); - v1.set(50000421); - v1.set(50000426); - v1.set(50000431); - v1.set(50000435); - v1.set(50000437); - v1.set(50000439); - v1.set(50000442); - v1.set(50000446); - v1.set(50000450); - v1.set(50000455); - v1.set(50000459); - v1.set(50000460); - v1.set(50000463); - v1.set(50000470); - v1.set(50000471); - v1.set(50000480); - v1.set(50000497); - v1.set(50000498); - v1.set(50000500); - v1.set(50000505); - v1.set(50000508); - v1.set(50000511); - v1.set(50000513); - v1.set(50000520); - v1.set(50000526); - v1.set(50000529); - v1.set(50000536); - v1.set(50000539); - v1.set(50000551); - v1.set(50000555); - v1.set(50000559); - v1.set(50000563); - v1.set(50000564); - v1.set(50000566); - v1.set(50000568); - v1.set(50000570); - v1.set(50000576); - v1.set(50000587); - v1.set(50000590); - v1.set(50000594); - v1.set(50000601); - v1.set(50000605); - v1.set(50000608); - v1.set(50000610); - v1.set(50000619); - v1.set(50000628); - v1.set(50000630); - v1.set(50000634); - v1.set(50000644); - v1.set(50000647); - v1.set(50000654); - v1.set(50000658); - v1.set(50000661); - v1.set(50000663); - v1.set(50000669); - v1.set(50000671); - v1.set(50000673); - v1.set(50000676); - v1.set(50000677); - v1.set(50000680); - v1.set(50000689); - v1.set(50000692); - v1.set(50000695); - v1.set(50000705); - v1.set(50000707); - v1.set(50000708); - v1.set(50000714); - v1.set(50000716); - v1.set(50000721); - v1.set(50000727); - v1.set(50000732); - v1.set(50000736); - v1.set(50000739); - v1.set(50000741); - v1.set(50000750); - v1.set(50000753); - v1.set(50000755); - v1.set(50000765); - v1.set(50000769); - v1.set(50000773); - v1.set(50000779); - v1.set(50000782); - v1.set(50000784); - v1.set(50000787); - v1.set(50000791); - v1.set(50000792); - v1.set(50000793); - v1.set(50000795); - v1.set(50000801); - v1.set(50000806); - v1.set(50000809); - return v1; - } - - @Test public void testSpecificBugsInOffsetBitVectors() { - OffsetBitVector v1 = makeBigTestOffsetVector(); - System.err.println(v1); - - OffsetBitVector v2 = new OffsetBitVector(50000128, 512); - v2.set(50000137); - v2.set(50000204); - v2.set(50000278); - v2.set(50000315); - v2.set(50000362); - v2.set(50000450); - v2.set(50000455); - v2.set(50000471); - System.err.println(v2); - - v1.andNot(v2); - System.err.println(v1); - Assert.assertTrue(v1.intersectionEmpty(v2)); - - v1 = makeBigTestOffsetVector(); - v1.and(v2); - System.err.println(v1); - Assert.assertTrue(v1.sameBits(v2)); - Assert.assertTrue(v1.isSubset(v2)); - Assert.assertTrue(v2.isSubset(v1)); - } - - @Test public void testSpecificBugsInSemiSparseMutableIntSets() { - SemiSparseMutableIntSet v1 = new SemiSparseMutableIntSet(); - v1.add(54); - v1.add(58); - v1.add(59); - v1.add(64); - v1.add(67); - v1.add(73); - v1.add(83); - v1.add(105); - v1.add(110); - v1.add(126); - v1.add(136); - v1.add(143); - v1.add(150); - v1.add(155); - v1.add(156); - v1.add(162); - v1.add(168); - v1.add(183); - v1.add(191); - v1.add(265); - v1.add(294); - v1.add(324); - v1.add(344); - v1.add(397); - } -} +/******************************************************************************* + * 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.core.tests.basic; + +import java.util.Collection; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Map; + +import org.junit.Assert; +import org.junit.Test; + +import com.ibm.wala.core.tests.util.WalaTestCase; +import com.ibm.wala.util.collections.BimodalMap; +import com.ibm.wala.util.collections.HashSetFactory; +import com.ibm.wala.util.collections.Iterator2Collection; +import com.ibm.wala.util.collections.SmallMap; +import com.ibm.wala.util.graph.Graph; +import com.ibm.wala.util.graph.NumberedGraph; +import com.ibm.wala.util.graph.dominators.Dominators; +import com.ibm.wala.util.graph.impl.SlowSparseNumberedGraph; +import com.ibm.wala.util.graph.traverse.BFSPathFinder; +import com.ibm.wala.util.graph.traverse.BoundedBFSIterator; +import com.ibm.wala.util.intset.BasicNaturalRelation; +import com.ibm.wala.util.intset.BimodalMutableIntSetFactory; +import com.ibm.wala.util.intset.BitVector; +import com.ibm.wala.util.intset.BitVectorBase; +import com.ibm.wala.util.intset.BitVectorIntSetFactory; +import com.ibm.wala.util.intset.IBinaryNaturalRelation; +import com.ibm.wala.util.intset.IntPair; +import com.ibm.wala.util.intset.IntSet; +import com.ibm.wala.util.intset.IntSetUtil; +import com.ibm.wala.util.intset.IntegerUnionFind; +import com.ibm.wala.util.intset.LongSet; +import com.ibm.wala.util.intset.LongSetUtil; +import com.ibm.wala.util.intset.MutableIntSet; +import com.ibm.wala.util.intset.MutableIntSetFactory; +import com.ibm.wala.util.intset.MutableLongSet; +import com.ibm.wala.util.intset.MutableLongSetFactory; +import com.ibm.wala.util.intset.MutableSharedBitVectorIntSetFactory; +import com.ibm.wala.util.intset.MutableSparseIntSetFactory; +import com.ibm.wala.util.intset.MutableSparseLongSetFactory; +import com.ibm.wala.util.intset.OffsetBitVector; +import com.ibm.wala.util.intset.SemiSparseMutableIntSet; +import com.ibm.wala.util.intset.SemiSparseMutableIntSetFactory; +import com.ibm.wala.util.intset.SparseIntSet; +import com.ibm.wala.util.intset.SparseLongSet; + +/** + * JUnit tests for some primitive operations. + */ +public class PrimitivesTest extends WalaTestCase { + + + /** + * Test the MutableSparseIntSet implementation + */ + private void doMutableIntSet(MutableIntSetFactory factory) { + MutableIntSet v = factory.parse("{9,17}"); + MutableIntSet w = factory.make(new int[] {}); + MutableIntSet x = factory.make(new int[] { 7, 4, 2, 4, 2, 2 }); + MutableIntSet y = factory.make(new int[] { 7, 7, 7, 2, 7, 1 }); + MutableIntSet z = factory.parse("{ 9 }"); + + System.err.println(w); // { } + System.err.println(x); // { 2 4 7 } + System.err.println(y); // { 1 2 7 } + System.err.println(z); // { 9 } + + MutableIntSet temp = factory.makeCopy(x); + temp.intersectWith(y); + System.err.println(temp); // { 2 7 } + temp.copySet(x); + temp.addAll(y); + System.err.println(temp); // { 1 2 4 7 } + temp.copySet(x); + System.err.println(IntSetUtil.diff(x, y, factory)); // { 4 } + System.err.println(IntSetUtil.diff(v, z, factory)); // { 17 } + System.err.println(IntSetUtil.diff(z, v, factory)); // { } + + // Assert.assertTrue(x.union(z).intersection(y.union(z)).equals(x.intersection(y).union(z))); + MutableIntSet temp1 = factory.makeCopy(x); + MutableIntSet temp2 = factory.makeCopy(x); + MutableIntSet tempY = factory.makeCopy(y); + temp1.addAll(z); + tempY.addAll(z); + temp1.intersectWith(tempY); + temp2.intersectWith(y); + temp2.addAll(z); + Assert.assertTrue(temp1.sameValue(temp2)); + + // Assert.assertTrue(x.union(z).diff(z).equals(x)); + Assert.assertTrue(w.isEmpty()); + Assert.assertTrue(IntSetUtil.diff(x, x, factory).isEmpty()); + Assert.assertTrue(IntSetUtil.diff(z, v, factory).isEmpty()); + Assert.assertTrue(IntSetUtil.diff(v, z, factory).sameValue(SparseIntSet.singleton(17))); + Assert.assertTrue(IntSetUtil.diff(z, v, factory).isEmpty()); + Assert.assertTrue(z.isSubset(v)); + temp = factory.make(); + temp.add(4); + System.err.println(temp); // { 4 } + temp.add(7); + System.err.println(temp); // { 4 7 } + temp.add(2); + System.err.println(temp); // { 2 4 7 } + System.err.println(x); // { 2 4 7 } + Assert.assertTrue(temp.sameValue(x)); + + MutableIntSet a = factory.parse("{1,3,5,7,9,11,13,15,17,19,21,23,25,27,29,31,33,35,37,39,41,43,45,47,49,51,53,55,57,59}"); + System.err.println(a); // { 1 3 5 7 9 11 13 15 17 19 21 23 25 27 29 31 33 + // 35 + // 37 39 41 43 45 47 49 51 53 55 57 59 } + Assert.assertTrue(a.sameValue(a)); + IntSet i = a.intersection(temp); + Assert.assertTrue(i.sameValue(SparseIntSet.singleton(7))); + a.add(100); + Assert.assertTrue(a.sameValue(a)); + + MutableIntSet b = factory.parse("{1,3,5,7,9,11,13,15,17,19,21,23,25,27,29,31,33,35,37,39,41,43,45,47,49,51,53,55,57,59,100}"); + Assert.assertTrue(a.sameValue(b)); + Assert.assertTrue(a.isSubset(b)); + + IntSet f = IntSetUtil.diff(b, factory.parse("{7,8,9}"), factory); + System.err.println(f); + Assert.assertFalse(f.contains(7)); + Assert.assertFalse(f.contains(8)); + Assert.assertFalse(f.contains(9)); + Assert.assertFalse(f.sameValue(b)); + Assert.assertTrue(f.isSubset(b)); + + IntSet tmp = factory.parse("{2,4,6,8,10,12,14,16,18,20,22,24,26,28,30,32,34,36,38,40,42,44,46,48,50,51,53,55,57,59,61,63}"); + f = IntSetUtil.diff(b, tmp, factory); + System.err.println(f); + Assert.assertFalse(f.sameValue(b)); + Assert.assertTrue(f.isSubset(b)); + Assert.assertFalse(f.contains(51)); + Assert.assertFalse(f.contains(53)); + Assert.assertFalse(f.contains(55)); + Assert.assertFalse(f.contains(57)); + Assert.assertFalse(f.contains(59)); + Assert.assertTrue(f.contains(100)); + + tmp = factory.parse("{2,4,6,8,10,12,14,16,18,20,22,24,26,28,30,32,34,36,38,40,42,44,46,48,50,51,53,55,57,59,61,63,100}"); + f = IntSetUtil.diff(b, tmp, factory); + System.err.println(f); + Assert.assertFalse(f.sameValue(b)); + Assert.assertTrue(f.isSubset(b)); + Assert.assertFalse(f.contains(51)); + Assert.assertFalse(f.contains(53)); + Assert.assertFalse(f.contains(55)); + Assert.assertFalse(f.contains(57)); + Assert.assertFalse(f.contains(59)); + Assert.assertFalse(f.contains(100)); + + b = factory.makeCopy(a); + Assert.assertTrue(a.sameValue(b)); + b.remove(1); + b.add(0); + Assert.assertTrue(!a.sameValue(b)); + + a = factory.parse("{1}"); + Assert.assertFalse(a.isSubset(b)); + b.remove(0); + Assert.assertFalse(a.isSubset(b)); + a.remove(1); + Assert.assertTrue(a.isEmpty()); + i = a.intersection(temp); + Assert.assertTrue(a.isEmpty()); + + temp2 = factory.make(); + Assert.assertTrue(temp2.sameValue(a)); + + a = factory.parse("{2,4,6,8,10,12,14,16,18,20,22,24,26,28,30,32,34,36,38,40,42,44,46,48,50,51,53,55,57,59,61,63}"); + b = factory.parse("{2,4,6,8,10,12,14,16,18,20,22,24,26,28,30,32,34,36,38,40,42,44,46,48,50,52,54,56,58,60,62}"); + MutableIntSet c = factory.parse("{2,4,6,8,10,12,14,16,18,20,22,24,26,28,30,32,34,36,38,40,42,44,46,48,50}"); + MutableIntSet d = factory.parse("{2,4,6,8,10,12,14,16,18,20,22,24,26,28,30,32,34,36,38,40,42,44,46,48,50}"); + MutableIntSet e = factory.parse("{2,4,6,8,10,12,14,16,18,20,22,24,26,28,30,32,34}"); + + Assert.assertTrue(e.isSubset(d)); + e.addAll(d); + Assert.assertTrue(e.isSubset(d)); + e.remove(12); + Assert.assertTrue(e.isSubset(d)); + e.add(105); + Assert.assertFalse(e.isSubset(d)); + + Assert.assertFalse(b.isSubset(a)); + + b.add(53); + Assert.assertFalse(b.isSubset(a)); + + a.add(52); + a.remove(52); + Assert.assertFalse(b.isSubset(a)); + + c.add(55); + Assert.assertFalse(c.isSubset(b)); + + d.add(53); + Assert.assertTrue(d.isSubset(b)); + + d = factory.make(); + d.copySet(c); + Assert.assertFalse(d.isSubset(b)); + + a = factory.parse("{2,4,6,8,10,12,14,16,18,20,22,24,26,28,30,32,34,36,38,40,42,44,46,48,50}"); + b = factory.parse("{2,4,6,8,10,12,14,16,18,20,22,24,26,28,30,32,34,36,38,40,42,44,46,48}"); + Assert.assertFalse(a.sameValue(b)); + b.add(50); + Assert.assertTrue(a.sameValue(b)); + a.add(11); + b.add(11); + Assert.assertTrue(a.sameValue(b)); + + a = factory.parse("{2,4,6,8,10,12,14,16,18,20,50}"); + b = factory.parse("{24,26,28,30,32,34,36,38,40,42,44,46,48}"); + c = factory.parse("{2,4,6,8,10,12,14,16,18,20,22,24,26,28,30,32,34,36,38,40,42,44,46,48,50}"); + a.addAll(b); + a.add(22); + Assert.assertTrue(a.sameValue(c)); + + a = factory.parse("{2,4,6,8,10,12,14,16,18,20,50}"); + b = factory.parse("{24,26,28,30,32,34,36,38,40,42,44,46,48}"); + c = factory.parse("{2,4,6,8,10,12,14,16,18,20,22,24,26,28,30,32,34,36,38,40,42,44,46,48,50}"); + b.addAll(factory.parse("{22}")); + a.addAll(b); + Assert.assertTrue(a.sameValue(c)); + + a = factory.parse("{2,4,6,8,10,12,14,16,18,20}"); + b = factory.parse("{22,24,26,28,30,32,34,36,38,40,42,44,46,48}"); + c = factory.parse("{2,4,6,8,10,12,14,16,18,20,22,24,26,28,30,32,34,36,38,40,42,44,46,48,50}"); + c.remove(22); + a.addAll(b); + Assert.assertFalse(a.sameValue(c)); + + a = factory.parse("{1,3,5,7,9,11,13,15,17,19,21,23,25,27,29,31,33,35,37,39,41,43,45,47,49,51,53,55,57,59}"); + System.err.println(a); // { 1 3 5 7 9 11 13 15 17 19 21 23 25 27 29 31 33 + // 35 + // 37 39 41 43 45 47 49 51 53 55 57 59 } + Assert.assertTrue(a.sameValue(a)); + i = a.intersection(temp); + Assert.assertTrue(i.sameValue(SparseIntSet.singleton(7))); + a.add(100); + Assert.assertTrue(a.sameValue(a)); + + b = factory.parse("{1,3,5,7,9,11,13,15,17,19,21,23,25,27,29,31,33,35,37,39,41,43,45,47,49,51,53,55,57,59,100}"); + Assert.assertTrue(a.sameValue(b)); + Assert.assertTrue(a.isSubset(b)); + + b = factory.makeCopy(a); + Assert.assertTrue(a.sameValue(b)); + b.remove(1); + b.add(0); + Assert.assertTrue(!a.sameValue(b)); + + a.clear(); + Assert.assertTrue(a.isEmpty()); + + a = factory.parse("{1}"); + Assert.assertFalse(a.isSubset(b)); + b.remove(0); + Assert.assertFalse(a.isSubset(b)); + a.remove(1); + Assert.assertTrue(a.isEmpty()); + i = a.intersection(temp); + Assert.assertTrue(a.isEmpty()); + + temp2 = factory.make(); + Assert.assertTrue(temp2.sameValue(a)); + + for (int idx = 500; idx < 550;) { + for (int xx = 0; xx < 50; xx++, idx++) { + temp2.add(idx); + } + System.err.println(temp2); + } + + for (int idx = 3000; idx < 3200;) { + for (int xx = 0; xx < 50; xx++, idx++) { + temp2.add(idx); + } + System.err.println(temp2); + } + + temp2.clear(); + Assert.assertTrue(temp2.isEmpty()); + + temp2 = factory.make(); + Assert.assertTrue(temp2.sameValue(a)); + + for (int idx = 500; idx < 550;) { + for (int xx = 0; xx < 50; xx++, idx++) { + temp2.add(idx); + } + System.err.println(temp2); + } + + for (int idx = 0; idx < 25; idx++) { + temp2.add(idx); + System.err.println(temp2); + } + + temp2.clear(); + Assert.assertTrue(temp2.isEmpty()); + } + + /** + * Test the MutableSharedBitVectorIntSet implementation + */ + @Test public void testMutableSharedBitVectorIntSet() { + doMutableIntSet(new MutableSharedBitVectorIntSetFactory()); + } + + /** + * Test the MutableSparseIntSet implementation + */ + @Test public void testMutableSparseIntSet() { + doMutableIntSet(new MutableSparseIntSetFactory()); + } + + /** + * Test the BimodalMutableSparseIntSet implementation + */ + @Test public void testBimodalMutableSparseIntSet() { + doMutableIntSet(new BimodalMutableIntSetFactory()); + } + + /** + * Test the BitVectorIntSet implementation + */ + @Test public void testBitVectorIntSet() { + doMutableIntSet(new BitVectorIntSetFactory()); + } + + /** + * Test the SemiSparseMutableIntSet implementation + */ + @Test public void testSemiSparseMutableIntSet() { + doMutableIntSet(new SemiSparseMutableIntSetFactory()); + } + + /** + * Test the MutableSparseIntSet implementation + */ + private void doMutableLongSet(MutableLongSetFactory factory) { + MutableLongSet v = factory.parse("{9,17}"); + MutableLongSet w = factory.make(new long[] {}); + MutableLongSet x = factory.make(new long[] { 7, 4, 2, 4, 2, 2 }); + MutableLongSet y = factory.make(new long[] { 7, 7, 7, 2, 7, 1 }); + MutableLongSet z = factory.parse("{ 9 }"); + + System.err.println(w); // { } + System.err.println(x); // { 2 4 7 } + System.err.println(y); // { 1 2 7 } + System.err.println(z); // { 9 } + + MutableLongSet temp = factory.makeCopy(x); + temp.intersectWith(y); + System.err.println(temp); // { 2 7 } + temp.copySet(x); + temp.addAll(y); + System.err.println(temp); // { 1 2 4 7 } + temp.copySet(x); + System.err.println(LongSetUtil.diff(x, y, factory)); // { 4 } + System.err.println(LongSetUtil.diff(v, z, factory)); // { 17 } + System.err.println(LongSetUtil.diff(z, v, factory)); // { } + + // Assert.assertTrue(x.union(z).intersection(y.union(z)).equals(x.intersection(y).union(z))); + MutableLongSet temp1 = factory.makeCopy(x); + MutableLongSet temp2 = factory.makeCopy(x); + MutableLongSet tempY = factory.makeCopy(y); + temp1.addAll(z); + tempY.addAll(z); + temp1.intersectWith(tempY); + temp2.intersectWith(y); + temp2.addAll(z); + Assert.assertTrue(temp1.sameValue(temp2)); + + // Assert.assertTrue(x.union(z).diff(z).equals(x)); + Assert.assertTrue(w.isEmpty()); + Assert.assertTrue(LongSetUtil.diff(x, x, factory).isEmpty()); + Assert.assertTrue(LongSetUtil.diff(z, v, factory).isEmpty()); + Assert.assertTrue(LongSetUtil.diff(v, z, factory).sameValue(SparseLongSet.singleton(17))); + Assert.assertTrue(LongSetUtil.diff(z, v, factory).isEmpty()); + Assert.assertTrue(z.isSubset(v)); + temp = factory.make(); + temp.add(4); + System.err.println(temp); // { 4 } + temp.add(7); + System.err.println(temp); // { 4 7 } + temp.add(2); + System.err.println(temp); // { 2 4 7 } + System.err.println(x); // { 2 4 7 } + Assert.assertTrue(temp.sameValue(x)); + + MutableLongSet a = factory.parse("{1,3,5,7,9,11,13,15,17,19,21,23,25,27,29,31,33,35,37,39,41,43,45,47,49,51,53,55,57,59}"); + System.err.println(a); // { 1 3 5 7 9 11 13 15 17 19 21 23 25 27 29 31 33 + // 35 + // 37 39 41 43 45 47 49 51 53 55 57 59 } + Assert.assertTrue(a.sameValue(a)); + LongSet i = a.intersection(temp); + Assert.assertTrue(i.sameValue(SparseLongSet.singleton(7))); + a.add(100); + Assert.assertTrue(a.sameValue(a)); + + MutableLongSet b = factory.parse("{1,3,5,7,9,11,13,15,17,19,21,23,25,27,29,31,33,35,37,39,41,43,45,47,49,51,53,55,57,59,100}"); + Assert.assertTrue(a.sameValue(b)); + Assert.assertTrue(a.isSubset(b)); + + LongSet f = LongSetUtil.diff(b, factory.parse("{7,8,9}"), factory); + System.err.println(f); + Assert.assertFalse(f.contains(7)); + Assert.assertFalse(f.contains(8)); + Assert.assertFalse(f.contains(9)); + Assert.assertFalse(f.sameValue(b)); + Assert.assertTrue(f.isSubset(b)); + + LongSet tmp = factory.parse("{2,4,6,8,10,12,14,16,18,20,22,24,26,28,30,32,34,36,38,40,42,44,46,48,50,51,53,55,57,59,61,63}"); + f = LongSetUtil.diff(b, tmp, factory); + System.err.println(f); + Assert.assertFalse(f.sameValue(b)); + Assert.assertTrue(f.isSubset(b)); + Assert.assertFalse(f.contains(51)); + Assert.assertFalse(f.contains(53)); + Assert.assertFalse(f.contains(55)); + Assert.assertFalse(f.contains(57)); + Assert.assertFalse(f.contains(59)); + Assert.assertTrue(f.contains(100)); + + tmp = factory.parse("{2,4,6,8,10,12,14,16,18,20,22,24,26,28,30,32,34,36,38,40,42,44,46,48,50,51,53,55,57,59,61,63,100}"); + f = LongSetUtil.diff(b, tmp, factory); + System.err.println(f); + Assert.assertFalse(f.sameValue(b)); + Assert.assertTrue(f.isSubset(b)); + Assert.assertFalse(f.contains(51)); + Assert.assertFalse(f.contains(53)); + Assert.assertFalse(f.contains(55)); + Assert.assertFalse(f.contains(57)); + Assert.assertFalse(f.contains(59)); + Assert.assertFalse(f.contains(100)); + + b = factory.makeCopy(a); + Assert.assertTrue(a.sameValue(b)); + b.remove(1); + b.add(0); + Assert.assertTrue(!a.sameValue(b)); + + a = factory.parse("{1}"); + Assert.assertFalse(a.isSubset(b)); + b.remove(0); + Assert.assertFalse(a.isSubset(b)); + a.remove(1); + Assert.assertTrue(a.isEmpty()); + i = a.intersection(temp); + Assert.assertTrue(a.isEmpty()); + + temp2 = factory.make(); + Assert.assertTrue(temp2.sameValue(a)); + + a = factory.parse("{2,4,6,8,10,12,14,16,18,20,22,24,26,28,30,32,34,36,38,40,42,44,46,48,50,51,53,55,57,59,61,63}"); + b = factory.parse("{2,4,6,8,10,12,14,16,18,20,22,24,26,28,30,32,34,36,38,40,42,44,46,48,50,52,54,56,58,60,62}"); + MutableLongSet c = factory.parse("{2,4,6,8,10,12,14,16,18,20,22,24,26,28,30,32,34,36,38,40,42,44,46,48,50}"); + MutableLongSet d = factory.parse("{2,4,6,8,10,12,14,16,18,20,22,24,26,28,30,32,34,36,38,40,42,44,46,48,50}"); + MutableLongSet e = factory.parse("{2,4,6,8,10,12,14,16,18,20,22,24,26,28,30,32,34}"); + + Assert.assertTrue(e.isSubset(d)); + e.addAll(d); + Assert.assertTrue(e.isSubset(d)); + e.remove(12); + Assert.assertTrue(e.isSubset(d)); + e.add(105); + Assert.assertFalse(e.isSubset(d)); + + Assert.assertFalse(b.isSubset(a)); + + b.add(53); + Assert.assertFalse(b.isSubset(a)); + + a.add(52); + a.remove(52); + Assert.assertFalse(b.isSubset(a)); + + c.add(55); + Assert.assertFalse(c.isSubset(b)); + + d.add(53); + Assert.assertTrue(d.isSubset(b)); + + d = factory.make(); + d.copySet(c); + Assert.assertFalse(d.isSubset(b)); + + a = factory.parse("{2,4,6,8,10,12,14,16,18,20,22,24,26,28,30,32,34,36,38,40,42,44,46,48,50}"); + b = factory.parse("{2,4,6,8,10,12,14,16,18,20,22,24,26,28,30,32,34,36,38,40,42,44,46,48}"); + Assert.assertFalse(a.sameValue(b)); + b.add(50); + Assert.assertTrue(a.sameValue(b)); + a.add(11); + b.add(11); + Assert.assertTrue(a.sameValue(b)); + + a = factory.parse("{2,4,6,8,10,12,14,16,18,20,50}"); + b = factory.parse("{24,26,28,30,32,34,36,38,40,42,44,46,48}"); + c = factory.parse("{2,4,6,8,10,12,14,16,18,20,22,24,26,28,30,32,34,36,38,40,42,44,46,48,50}"); + a.addAll(b); + a.add(22); + Assert.assertTrue(a.sameValue(c)); + + a = factory.parse("{2,4,6,8,10,12,14,16,18,20,50}"); + b = factory.parse("{24,26,28,30,32,34,36,38,40,42,44,46,48}"); + c = factory.parse("{2,4,6,8,10,12,14,16,18,20,22,24,26,28,30,32,34,36,38,40,42,44,46,48,50}"); + b.addAll(factory.parse("{22}")); + a.addAll(b); + Assert.assertTrue(a.sameValue(c)); + + a = factory.parse("{2,4,6,8,10,12,14,16,18,20}"); + b = factory.parse("{22,24,26,28,30,32,34,36,38,40,42,44,46,48}"); + c = factory.parse("{2,4,6,8,10,12,14,16,18,20,22,24,26,28,30,32,34,36,38,40,42,44,46,48,50}"); + c.remove(22); + a.addAll(b); + Assert.assertFalse(a.sameValue(c)); + + a = factory.parse("{1,3,5,7,9,11,13,15,17,19,21,23,25,27,29,31,33,35,37,39,41,43,45,47,49,51,53,55,57,59}"); + System.err.println(a); // { 1 3 5 7 9 11 13 15 17 19 21 23 25 27 29 31 33 + // 35 + // 37 39 41 43 45 47 49 51 53 55 57 59 } + Assert.assertTrue(a.sameValue(a)); + i = a.intersection(temp); + Assert.assertTrue(i.sameValue(SparseLongSet.singleton(7))); + a.add(100); + Assert.assertTrue(a.sameValue(a)); + + b = factory.parse("{1,3,5,7,9,11,13,15,17,19,21,23,25,27,29,31,33,35,37,39,41,43,45,47,49,51,53,55,57,59,100}"); + Assert.assertTrue(a.sameValue(b)); + Assert.assertTrue(a.isSubset(b)); + + b = factory.makeCopy(a); + Assert.assertTrue(a.sameValue(b)); + b.remove(1); + b.add(0); + Assert.assertTrue(!a.sameValue(b)); + + a = factory.parse("{1}"); + Assert.assertFalse(a.isSubset(b)); + b.remove(0); + Assert.assertFalse(a.isSubset(b)); + a.remove(1); + Assert.assertTrue(a.isEmpty()); + i = a.intersection(temp); + Assert.assertTrue(a.isEmpty()); + + temp2 = factory.make(); + Assert.assertTrue(temp2.sameValue(a)); + + for (int idx = 500; idx < 550;) { + for (int xx = 0; xx < 50; xx++, idx++) { + temp2.add(idx); + } + System.err.println(temp2); + } + + for (int idx = 3000; idx < 3200;) { + for (int xx = 0; xx < 50; xx++, idx++) { + temp2.add(idx); + } + System.err.println(temp2); + } + + temp2 = factory.make(); + Assert.assertTrue(temp2.sameValue(a)); + + for (int idx = 500; idx < 550;) { + for (int xx = 0; xx < 50; xx++, idx++) { + temp2.add(idx); + } + System.err.println(temp2); + } + + for (int idx = 0; idx < 25; idx++) { + temp2.add(idx); + System.err.println(temp2); + } + + } + + /** + * Test the MutableSparseLongSet implementation + */ + @Test public void testMutableSparseLongSet() { + doMutableLongSet(new MutableSparseLongSetFactory()); + } + + @Test public void testSmallMap() { + SmallMap M = new SmallMap(); + Integer I1 = new Integer(1); + Integer I2 = new Integer(2); + Integer I3 = new Integer(3); + M.put(I1, I1); + M.put(I2, I2); + M.put(I3, I3); + + Integer I = (Integer) M.get(new Integer(2)); + Assert.assertTrue(I != null); + Assert.assertTrue(I.equals(I2)); + + I = (Integer) M.get(new Integer(4)); + Assert.assertTrue(I == null); + + I = (Integer) M.put(new Integer(2), new Integer(3)); + Assert.assertTrue(I.equals(I2)); + I = (Integer) M.get(I2); + Assert.assertTrue(I.equals(I3)); + } + + @Test public void testBimodalMap() { + Map M = new BimodalMap(3); + Integer I1 = new Integer(1); + Integer I2 = new Integer(2); + Integer I3 = new Integer(3); + Integer I4 = new Integer(4); + Integer I5 = new Integer(5); + Integer I6 = new Integer(6); + M.put(I1, I1); + M.put(I2, I2); + M.put(I3, I3); + + Integer I = M.get(new Integer(2)); + Assert.assertTrue(I != null); + Assert.assertTrue(I.equals(I2)); + + I = M.get(new Integer(4)); + Assert.assertTrue(I == null); + + I = M.put(new Integer(2), new Integer(3)); + Assert.assertTrue(I.equals(I2)); + I = M.get(I2); + Assert.assertTrue(I.equals(I3)); + + M.put(I4, I4); + M.put(I5, I5); + M.put(I6, I6); + I = M.get(new Integer(4)); + Assert.assertTrue(I != null); + Assert.assertTrue(I.equals(I4)); + + I = M.get(new Integer(7)); + Assert.assertTrue(I == null); + + I = M.put(new Integer(2), new Integer(6)); + Assert.assertTrue(I.equals(I3)); + I = M.get(I2); + Assert.assertTrue(I.equals(I6)); + } + + @Test public void testBFSPathFinder() { + NumberedGraph G = makeBFSTestGraph(); + + // path from 0 to 8 + BFSPathFinder pf = new BFSPathFinder(G, G.getNode(0), G.getNode(8)); + List p = pf.find(); + + // path should be 8, 6, 4, 2, 0 + System.err.println("Path is " + p); + for (int i = 0; i < p.size(); i++) { + Assert.assertTrue((p.get(i)).intValue() == new int[] { 8, 6, 4, 2, 0 }[i]); + } + } + + @Test public void testBoundedBFS() { + NumberedGraph G = makeBFSTestGraph(); + + BoundedBFSIterator bfs = new BoundedBFSIterator(G, G.getNode(0), 0); + Collection c = Iterator2Collection.toSet(bfs); + Assert.assertTrue(c.size() == 1); + + bfs = new BoundedBFSIterator(G, G.getNode(0), 1); + c = Iterator2Collection.toSet(bfs); + Assert.assertTrue(c.size() == 3); + + bfs = new BoundedBFSIterator(G, G.getNode(0), 2); + c = Iterator2Collection.toSet(bfs); + Assert.assertTrue(c.size() == 5); + + bfs = new BoundedBFSIterator(G, G.getNode(0), 3); + c = Iterator2Collection.toSet(bfs); + Assert.assertTrue(c.size() == 7); + + bfs = new BoundedBFSIterator(G, G.getNode(0), 4); + c = Iterator2Collection.toSet(bfs); + Assert.assertTrue(c.size() == 9); + + bfs = new BoundedBFSIterator(G, G.getNode(0), 5); + c = Iterator2Collection.toSet(bfs); + Assert.assertTrue(c.size() == 10); + + bfs = new BoundedBFSIterator(G, G.getNode(0), 500); + c = Iterator2Collection.toSet(bfs); + Assert.assertTrue(c.size() == 10); + } + + private NumberedGraph makeBFSTestGraph() { + // test graph + NumberedGraph G = SlowSparseNumberedGraph.make(); + + // add 10 nodes + Integer[] nodes = new Integer[10]; + for (int i = 0; i < nodes.length; i++) + G.addNode(nodes[i] = new Integer(i)); + + // edges to i-1, i+1, i+2 + for (int i = 0; i < nodes.length; i++) { + if (i > 0) { + G.addEdge(nodes[i], nodes[i - 1]); + } + if (i < nodes.length - 1) { + G.addEdge(nodes[i], nodes[i + 1]); + if (i < nodes.length - 2) { + G.addEdge(nodes[i], nodes[i + 2]); + } + } + } + return G; + } + + @Test public void testDominatorsA() { + // test graph + Graph G = SlowSparseNumberedGraph.make(); + + // add nodes + Object[] nodes = new Object[11]; + for (int i = 0; i < nodes.length; i++) + G.addNode(nodes[i] = new Integer(i)); + + // add edges + G.addEdge(nodes[10], nodes[0]); + G.addEdge(nodes[10], nodes[1]); + G.addEdge(nodes[0], nodes[2]); + G.addEdge(nodes[1], nodes[3]); + G.addEdge(nodes[2], nodes[5]); + G.addEdge(nodes[3], nodes[5]); + G.addEdge(nodes[4], nodes[2]); + G.addEdge(nodes[5], nodes[8]); + G.addEdge(nodes[6], nodes[3]); + G.addEdge(nodes[7], nodes[4]); + G.addEdge(nodes[8], nodes[7]); + G.addEdge(nodes[8], nodes[9]); + G.addEdge(nodes[9], nodes[6]); + + // compute dominators + Dominators D = Dominators.make(G, nodes[10]); + + // Assert.assertions + int i = 0; + Object[] desired4 = new Object[] { nodes[4], nodes[7], nodes[8], nodes[5], nodes[10] }; + for (Iterator d4 = D.dominators(nodes[4]); d4.hasNext();) + Assert.assertTrue(d4.next() == desired4[i++]); + + int j = 0; + Object[] desired5 = new Object[] { nodes[8] }; + for (Iterator t4 = D.dominatorTree().getSuccNodes(nodes[5]); t4.hasNext();) { + Object o4 = t4.next(); + Object d = desired5[j++]; + boolean ok = (o4.equals(d)); + if (!ok) { + System.err.println("O4: " + o4); + System.err.println("desired " + d); + Assert.assertTrue(o4.equals(d)); + } + + } + + Assert.assertTrue(D.dominatorTree().getSuccNodeCount(nodes[10]) == 5); + } + + @Test public void testBinaryIntegerRelation() { + byte[] impl = new byte[] { BasicNaturalRelation.SIMPLE, BasicNaturalRelation.TWO_LEVEL, BasicNaturalRelation.SIMPLE }; + IBinaryNaturalRelation R = new BasicNaturalRelation(impl, BasicNaturalRelation.TWO_LEVEL); + R.add(3, 5); + R.add(3, 7); + R.add(3, 9); + R.add(3, 11); + R.add(5, 1); + int count = 0; + for (Iterator it = R.iterator(); it.hasNext();) { + System.err.println(it.next()); + count++; + } + Assert.assertTrue(count == 5); + + IntSet x = R.getRelated(3); + Assert.assertTrue(x.size() == 4); + + x = R.getRelated(5); + Assert.assertTrue(x.size() == 1); + + R.remove(5, 1); + x = R.getRelated(5); + Assert.assertTrue(x == null); + + R.add(2, 1); + R.add(2, 2); + R.remove(2, 1); + x = R.getRelated(2); + Assert.assertTrue(x.size() == 1); + + R.removeAll(3); + x = R.getRelated(3); + Assert.assertTrue(x == null); + + x = R.getRelated(0); + Assert.assertTrue(x == null); + + for (int i = 0; i < 100; i++) { + R.add(1, i); + } + Assert.assertTrue(R.getRelated(1).size() == 100); + R.remove(1, 1); + Assert.assertTrue(R.getRelated(1).size() == 99); + } + + @Test public void testUnionFind() { + int SIZE = 10000; + IntegerUnionFind uf = new IntegerUnionFind(SIZE); + int count = countEquivalenceClasses(uf); + Assert.assertTrue("Got count " + count, count == SIZE); + + uf.union(3, 7); + Assert.assertTrue(uf.find(3) == uf.find(7)); + Assert.assertTrue("Got uf.find(3)=" + uf.find(3), uf.find(3) == 3 || uf.find(3) == 7); + + uf.union(7, SIZE - 1); + Assert.assertTrue(uf.find(3) == uf.find(SIZE - 1)); + Assert.assertTrue("Got uf.find(3)=" + uf.find(3), uf.find(3) == 3 || uf.find(3) == 7 || uf.find(3) == SIZE - 1); + + for (int i = 0; i < SIZE - 1; i++) { + uf.union(i, i + 1); + } + count = countEquivalenceClasses(uf); + Assert.assertTrue("Got count " + count, count == 1); + + uf = new IntegerUnionFind(SIZE); + for (int i = 0; i < SIZE; i++) { + if ((i % 2) == 0) { + uf.union(i, 0); + } else { + uf.union(i, 1); + } + } + count = countEquivalenceClasses(uf); + Assert.assertTrue("Got count " + count, count == 2); + } + + private int countEquivalenceClasses(IntegerUnionFind uf) { + HashSet s = HashSetFactory.make(); + for (int i = 0; i < uf.size(); i++) { + s.add(new Integer(uf.find(i))); + } + return s.size(); + } + + @Test public void testBitVector() { + testSingleBitVector(new BitVector()); + } + + @Test public void testOffsetBitVector0_10() { + testSingleBitVector(new OffsetBitVector(0, 10)); + } + + @Test public void testOffsetBitVector10_10() { + testSingleBitVector(new OffsetBitVector(10, 10)); + } + + @Test public void testOffsetBitVector50_10() { + testSingleBitVector(new OffsetBitVector(50, 10)); + } + + @Test public void testOffsetBitVector50_50() { + testSingleBitVector(new OffsetBitVector(50, 50)); + } + + @Test public void testOffsetBitVector100_10() { + testSingleBitVector(new OffsetBitVector(100, 10)); + } + + @SuppressWarnings("unchecked") + private void testSingleBitVector(BitVectorBase bv) { + // does the following not automatically scale the bitvector to + // a reasonable size? + bv.set(55); + + Assert.assertTrue("bv.max() is " + bv.max(), bv.max() == 55); + Assert.assertTrue(bv.get(55)); + + bv.set(59); + Assert.assertTrue(bv.max() == 59); + Assert.assertTrue(bv.get(55)); + Assert.assertTrue(bv.get(59)); + + { + boolean[] gets = new boolean[] { false, true, true }; + int[] bits = new int[] { 0, 55, 59 }; + for (int i = 0, j = 0; i != -1; i = bv.nextSetBit(i + 1), j++) { + Assert.assertTrue(i == bits[j]); + Assert.assertTrue(bv.get(i) == gets[j]); + } + } + + bv.set(77); + + Assert.assertTrue("bv.max() is " + bv.max(), bv.max() == 77); + { + boolean[] gets = new boolean[] { false, true, true, true }; + int[] bits = new int[] { 0, 55, 59, 77 }; + for (int i = 0, j = 0; i != -1; i = bv.nextSetBit(i + 1), j++) { + Assert.assertTrue(i == bits[j]); + Assert.assertTrue(bv.get(i) == gets[j]); + } + } + + bv.set(3); + Assert.assertTrue("bv.max() is " + bv.max(), bv.max() == 77); + { + boolean[] gets = new boolean[] { false, true, true, true, true }; + int[] bits = new int[] { 0, 3, 55, 59, 77 }; + for (int i = 0, j = 0; i != -1; i = bv.nextSetBit(i + 1), j++) { + Assert.assertTrue(i == bits[j]); + Assert.assertTrue(bv.get(i) == gets[j]); + } + } + + System.err.println(bv); + } + + @Test public void testBitVectors() { + testBitVectors(new BitVector(), new BitVector()); + } + + @Test public void testOffsetBitVectors150_10() { + testBitVectors(new OffsetBitVector(150, 10), new OffsetBitVector(150, 10)); + } + + @Test public void testOffsetBitVectors100_200_10() { + testBitVectors(new OffsetBitVector(100, 10), new OffsetBitVector(200, 10)); + } + + @Test public void testOffsetBitVectors100_25_10() { + testBitVectors(new OffsetBitVector(100, 10), new OffsetBitVector(25, 10)); + } + + @Test public void testOffsetBitVectors35_25_20_10() { + testBitVectors(new OffsetBitVector(35, 20), new OffsetBitVector(25, 10)); + } + + @SuppressWarnings("unchecked") + private void testBitVectors(T v1, T v2) { + v1.set(100); + v1.set(101); + v1.set(102); + Assert.assertTrue("v1.max() is " + v1.max(), v1.max() == 102); + + v2.set(200); + v2.set(201); + v2.set(202); + Assert.assertTrue("v2.max() is " + v2.max(), v2.max() == 202); + + Assert.assertTrue(v1.intersectionEmpty(v2)); + Assert.assertTrue(v2.intersectionEmpty(v1)); + + v1.or(v2); + + System.err.println("v1 = " + v1 + ", v2 = " + v2); + Assert.assertFalse("v1 = " + v1 + ", v2 = " + v2, v1.intersectionEmpty(v2)); + Assert.assertFalse("v1 = " + v1 + ", v2 = " + v2, v2.intersectionEmpty(v1)); + Assert.assertTrue("v1.max() is " + v1.max(), v1.max() == 202); + + { + boolean[] gets = new boolean[] { false, true, true, true, true, true, true }; + int[] bits = new int[] { 0, 100, 101, 102, 200, 201, 202 }; + for (int i = 0, j = 0; i != -1; i = v1.nextSetBit(i + 1), j++) { + Assert.assertTrue(i == bits[j]); + Assert.assertTrue(v1.get(i) == gets[j]); + } + } + + v1.clearAll(); + v2.clearAll(); + + v1.set(100); + v1.set(101); + v1.set(102); + v1.set(103); + v1.set(104); + v1.set(105); + Assert.assertTrue("v1.max() is " + v1.max(), v1.max() == 105); + + v2.set(103); + v2.set(104); + v2.set(200); + v2.set(201); + Assert.assertTrue("v2.max() is " + v2.max(), v2.max() == 201); + + v1.and(v2); + Assert.assertTrue("v1.max() is " + v1.max(), v1.max() == 104); + + { + boolean[] gets = new boolean[] { false, true, true }; + int[] bits = new int[] { 0, 103, 104 }; + for (int i = 0, j = 0; i != -1; i = v1.nextSetBit(i + 1), j++) { + Assert.assertTrue(i == bits[j]); + Assert.assertTrue(v1.get(i) == gets[j]); + } + } + + v1.set(100); + v1.set(101); + v1.set(102); + v1.set(105); + Assert.assertTrue("v1.max() is " + v1.max(), v1.max() == 105); + + { + boolean[] gets = new boolean[] { false, true, true, true, true, true, true }; + int[] bits = new int[] { 0, 100, 101, 102, 103, 104, 105 }; + for (int i = 0, j = 0; i != -1; i = v1.nextSetBit(i + 1), j++) { + Assert.assertTrue(i == bits[j]); + Assert.assertTrue(v1.get(i) == gets[j]); + } + } + + v2.clear(103); + v2.clear(104); + v1.andNot(v2); + + { + boolean[] gets = new boolean[] { false, true, true, true, true, true, true }; + int[] bits = new int[] { 0, 100, 101, 102, 103, 104, 105 }; + for (int i = 0, j = 0; i != -1; i = v1.nextSetBit(i + 1), j++) { + Assert.assertTrue(i == bits[j]); + Assert.assertTrue(v1.get(i) == gets[j]); + } + } + + v2.set(101); + v2.set(102); + + System.err.println("v1 = " + v1 + ", v2 = " + v2); + v1.andNot(v2); + + { + boolean[] gets = new boolean[] { false, true, true, true, true }; + int[] bits = new int[] { 0, 100, 103, 104, 105 }; + for (int i = 0, j = 0; i != -1; i = v1.nextSetBit(i + 1), j++) { + Assert.assertTrue(i == bits[j]); + Assert.assertTrue(v1.get(i) == gets[j]); + } + } + + v1.clearAll(); + v2.clearAll(); + + v1.set(35); + v1.set(101); + v1.set(102); + v1.set(103); + v1.set(104); + v1.set(105); + + v2.set(101); + v2.set(102); + v2.set(104); + v2.set(206); + + System.err.println("v1 = " + v1 + ", v2 = " + v2); + v1.xor(v2); + + { + boolean[] gets = new boolean[] { false, true, true, true, true }; + int[] bits = new int[] { 0, 35, 103, 105, 206 }; + for (int i = 0, j = 0; i != -1; i = v1.nextSetBit(i + 1), j++) { + Assert.assertTrue(i == bits[j]); + Assert.assertTrue(v1.get(i) == gets[j]); + } + } + + v2.set(35); + v2.set(103); + v2.set(105); + + System.err.println("v1 = " + v1 + ", v2 = " + v2); + Assert.assertTrue(v1.isSubset(v2)); + + v2.clearAll(); + v2.set(111); + v2.or(v1); + Assert.assertTrue(v1.isSubset(v2)); + + v2.and(v1); + + Assert.assertTrue(v1.sameBits(v2)); + + v1.clearAll(); + } + + private static OffsetBitVector makeBigTestOffsetVector() { + OffsetBitVector v1 = new OffsetBitVector(50000096, 1024); + v1.set(50000101); + v1.set(50000103); + v1.set(50000112); + v1.set(50000114); + v1.set(50000116); + v1.set(50000126); + v1.set(50000128); + v1.set(50000129); + v1.set(50000135); + v1.set(50000137); + v1.set(50000143); + v1.set(50000148); + v1.set(50000151); + v1.set(50000158); + v1.set(50000163); + v1.set(50000167); + v1.set(50000170); + v1.set(50000173); + v1.set(50000180); + v1.set(50000182); + v1.set(50000185); + v1.set(50000187); + v1.set(50000190); + v1.set(50000194); + v1.set(50000199); + v1.set(50000201); + v1.set(50000204); + v1.set(50000206); + v1.set(50000209); + v1.set(50000210); + v1.set(50000218); + v1.set(50000221); + v1.set(50000223); + v1.set(50000227); + v1.set(50000232); + v1.set(50000234); + v1.set(50000243); + v1.set(50000246); + v1.set(50000250); + v1.set(50000257); + v1.set(50000263); + v1.set(50000268); + v1.set(50000273); + v1.set(50000275); + v1.set(50000278); + v1.set(50000282); + v1.set(50000285); + v1.set(50000290); + v1.set(50000293); + v1.set(50000298); + v1.set(50000300); + v1.set(50000303); + v1.set(50000306); + v1.set(50000308); + v1.set(50000310); + v1.set(50000315); + v1.set(50000325); + v1.set(50000327); + v1.set(50000335); + v1.set(50000337); + v1.set(50000342); + v1.set(50000345); + v1.set(50000349); + v1.set(50000360); + v1.set(50000362); + v1.set(50000369); + v1.set(50000374); + v1.set(50000375); + v1.set(50000378); + v1.set(50000380); + v1.set(50000383); + v1.set(50000384); + v1.set(50000388); + v1.set(50000391); + v1.set(50000400); + v1.set(50000405); + v1.set(50000409); + v1.set(50000414); + v1.set(50000417); + v1.set(50000421); + v1.set(50000426); + v1.set(50000431); + v1.set(50000435); + v1.set(50000437); + v1.set(50000439); + v1.set(50000442); + v1.set(50000446); + v1.set(50000450); + v1.set(50000455); + v1.set(50000459); + v1.set(50000460); + v1.set(50000463); + v1.set(50000470); + v1.set(50000471); + v1.set(50000480); + v1.set(50000497); + v1.set(50000498); + v1.set(50000500); + v1.set(50000505); + v1.set(50000508); + v1.set(50000511); + v1.set(50000513); + v1.set(50000520); + v1.set(50000526); + v1.set(50000529); + v1.set(50000536); + v1.set(50000539); + v1.set(50000551); + v1.set(50000555); + v1.set(50000559); + v1.set(50000563); + v1.set(50000564); + v1.set(50000566); + v1.set(50000568); + v1.set(50000570); + v1.set(50000576); + v1.set(50000587); + v1.set(50000590); + v1.set(50000594); + v1.set(50000601); + v1.set(50000605); + v1.set(50000608); + v1.set(50000610); + v1.set(50000619); + v1.set(50000628); + v1.set(50000630); + v1.set(50000634); + v1.set(50000644); + v1.set(50000647); + v1.set(50000654); + v1.set(50000658); + v1.set(50000661); + v1.set(50000663); + v1.set(50000669); + v1.set(50000671); + v1.set(50000673); + v1.set(50000676); + v1.set(50000677); + v1.set(50000680); + v1.set(50000689); + v1.set(50000692); + v1.set(50000695); + v1.set(50000705); + v1.set(50000707); + v1.set(50000708); + v1.set(50000714); + v1.set(50000716); + v1.set(50000721); + v1.set(50000727); + v1.set(50000732); + v1.set(50000736); + v1.set(50000739); + v1.set(50000741); + v1.set(50000750); + v1.set(50000753); + v1.set(50000755); + v1.set(50000765); + v1.set(50000769); + v1.set(50000773); + v1.set(50000779); + v1.set(50000782); + v1.set(50000784); + v1.set(50000787); + v1.set(50000791); + v1.set(50000792); + v1.set(50000793); + v1.set(50000795); + v1.set(50000801); + v1.set(50000806); + v1.set(50000809); + return v1; + } + + @Test public void testSpecificBugsInOffsetBitVectors() { + OffsetBitVector v1 = makeBigTestOffsetVector(); + System.err.println(v1); + + OffsetBitVector v2 = new OffsetBitVector(50000128, 512); + v2.set(50000137); + v2.set(50000204); + v2.set(50000278); + v2.set(50000315); + v2.set(50000362); + v2.set(50000450); + v2.set(50000455); + v2.set(50000471); + System.err.println(v2); + + v1.andNot(v2); + System.err.println(v1); + Assert.assertTrue(v1.intersectionEmpty(v2)); + + v1 = makeBigTestOffsetVector(); + v1.and(v2); + System.err.println(v1); + Assert.assertTrue(v1.sameBits(v2)); + Assert.assertTrue(v1.isSubset(v2)); + Assert.assertTrue(v2.isSubset(v1)); + } + + @Test public void testSpecificBugsInSemiSparseMutableIntSets() { + SemiSparseMutableIntSet v1 = new SemiSparseMutableIntSet(); + v1.add(54); + v1.add(58); + v1.add(59); + v1.add(64); + v1.add(67); + v1.add(73); + v1.add(83); + v1.add(105); + v1.add(110); + v1.add(126); + v1.add(136); + v1.add(143); + v1.add(150); + v1.add(155); + v1.add(156); + v1.add(162); + v1.add(168); + v1.add(183); + v1.add(191); + v1.add(265); + v1.add(294); + v1.add(324); + v1.add(344); + v1.add(397); + } +} diff --git a/com.ibm.wala.core.tests/src/com/ibm/wala/core/tests/callGraph/CallGraphTest.java b/com.ibm.wala.core.tests/src/com/ibm/wala/core/tests/callGraph/CallGraphTest.java index fd7852e6e..0970dbe23 100644 --- a/com.ibm.wala.core.tests/src/com/ibm/wala/core/tests/callGraph/CallGraphTest.java +++ b/com.ibm.wala.core.tests/src/com/ibm/wala/core/tests/callGraph/CallGraphTest.java @@ -1,562 +1,562 @@ -/******************************************************************************* - * 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 com.ibm.wala.core.tests.callGraph; - -import java.io.IOException; -import java.util.HashSet; -import java.util.Iterator; -import java.util.Set; - -import org.junit.Assert; -import org.junit.Test; - -import com.ibm.wala.classLoader.IClass; -import com.ibm.wala.classLoader.IMethod; -import com.ibm.wala.core.tests.util.TestConstants; -import com.ibm.wala.core.tests.util.WalaTestCase; -import com.ibm.wala.ipa.callgraph.AnalysisCache; -import com.ibm.wala.ipa.callgraph.AnalysisOptions; -import com.ibm.wala.ipa.callgraph.AnalysisScope; -import com.ibm.wala.ipa.callgraph.CGNode; -import com.ibm.wala.ipa.callgraph.CallGraph; -import com.ibm.wala.ipa.callgraph.CallGraphStats; -import com.ibm.wala.ipa.callgraph.Entrypoint; -import com.ibm.wala.ipa.callgraph.impl.AllApplicationEntrypoints; -import com.ibm.wala.ipa.callgraph.impl.DefaultEntrypoint; -import com.ibm.wala.ipa.callgraph.impl.Util; -import com.ibm.wala.ipa.callgraph.propagation.SSAPropagationCallGraphBuilder; -import com.ibm.wala.ipa.cfg.BasicBlockInContext; -import com.ibm.wala.ipa.cfg.InterproceduralCFG; -import com.ibm.wala.ipa.cha.ClassHierarchy; -import com.ibm.wala.ipa.cha.ClassHierarchyException; -import com.ibm.wala.ipa.cha.IClassHierarchy; -import com.ibm.wala.ssa.ISSABasicBlock; -import com.ibm.wala.types.Descriptor; -import com.ibm.wala.types.MethodReference; -import com.ibm.wala.util.CancelException; -import com.ibm.wala.util.collections.HashSetFactory; -import com.ibm.wala.util.collections.Iterator2Iterable; -import com.ibm.wala.util.debug.Assertions; -import com.ibm.wala.util.graph.Graph; -import com.ibm.wala.util.graph.GraphIntegrity; -import com.ibm.wala.util.graph.GraphIntegrity.UnsoundGraphException; -import com.ibm.wala.util.strings.Atom; -import com.ibm.wala.util.warnings.Warnings; - -/** - * Tests for Call Graph construction - */ - -public class CallGraphTest extends WalaTestCase { - - public static void main(String[] args) { - justThisTest(CallGraphTest.class); - } - - - @Test public void testJava_cup() throws ClassHierarchyException, IllegalArgumentException, CancelException, IOException { - AnalysisScope scope = CallGraphTestUtil.makeJ2SEAnalysisScope(TestConstants.JAVA_CUP, CallGraphTestUtil.REGRESSION_EXCLUSIONS); - ClassHierarchy cha = ClassHierarchy.make(scope); - Iterable entrypoints = com.ibm.wala.ipa.callgraph.impl.Util.makeMainEntrypoints(scope, cha, - TestConstants.JAVA_CUP_MAIN); - AnalysisOptions options = CallGraphTestUtil.makeAnalysisOptions(scope, entrypoints); - - doCallGraphs(options, new AnalysisCache(), cha, scope, useShortProfile()); - } - - @Test public void testBcelVerifier() throws ClassHierarchyException, IllegalArgumentException, CancelException, IOException { - AnalysisScope scope = CallGraphTestUtil.makeJ2SEAnalysisScope(TestConstants.BCEL, CallGraphTestUtil.REGRESSION_EXCLUSIONS); - ClassHierarchy cha = ClassHierarchy.make(scope); - Iterable entrypoints = com.ibm.wala.ipa.callgraph.impl.Util.makeMainEntrypoints(scope, cha, - TestConstants.BCEL_VERIFIER_MAIN); - AnalysisOptions options = CallGraphTestUtil.makeAnalysisOptions(scope, entrypoints); - - doCallGraphs(options, new AnalysisCache(), cha, scope); - } - - @Test public void testJLex() throws ClassHierarchyException, IllegalArgumentException, CancelException, IOException { - AnalysisScope scope = CallGraphTestUtil.makeJ2SEAnalysisScope(TestConstants.JLEX, CallGraphTestUtil.REGRESSION_EXCLUSIONS); - ClassHierarchy cha = ClassHierarchy.make(scope); - Iterable entrypoints = com.ibm.wala.ipa.callgraph.impl.Util - .makeMainEntrypoints(scope, cha, TestConstants.JLEX_MAIN); - AnalysisOptions options = CallGraphTestUtil.makeAnalysisOptions(scope, entrypoints); - - doCallGraphs(options, new AnalysisCache(), cha, scope); - } - - @Test public void testCornerCases() throws ClassHierarchyException, IllegalArgumentException, CancelException, IOException { - AnalysisScope scope = CallGraphTestUtil.makeJ2SEAnalysisScope(TestConstants.WALA_TESTDATA, - CallGraphTestUtil.REGRESSION_EXCLUSIONS); - ClassHierarchy cha = ClassHierarchy.make(scope); - Iterable entrypoints = new AllApplicationEntrypoints(scope, cha); - AnalysisOptions options = CallGraphTestUtil.makeAnalysisOptions(scope, entrypoints); - - doCallGraphs(options, new AnalysisCache(), cha, scope); - - // we expect a warning or two about class Abstract1, which has no concrete - // subclasses - String ws = Warnings.asString(); - Assert.assertTrue("failed to report a warning about Abstract1", ws.indexOf("cornerCases/Abstract1") > -1); - - // we do not expect a warning about class Abstract2, which has a concrete - // subclasses - Assert.assertTrue("reported a warning about Abstract2", ws.indexOf("cornerCases/Abstract2") == -1); - } - - @Test public void testHello() throws ClassHierarchyException, IllegalArgumentException, CancelException, IOException { - AnalysisScope scope = CallGraphTestUtil.makeJ2SEAnalysisScope(TestConstants.HELLO, CallGraphTestUtil.REGRESSION_EXCLUSIONS); - ClassHierarchy cha = ClassHierarchy.make(scope); - Iterable entrypoints = com.ibm.wala.ipa.callgraph.impl.Util.makeMainEntrypoints(scope, cha, - TestConstants.HELLO_MAIN); - AnalysisOptions options = CallGraphTestUtil.makeAnalysisOptions(scope, entrypoints); - - doCallGraphs(options, new AnalysisCache(), cha, scope); - } - - @Test public void testStaticInit() throws ClassHierarchyException, IllegalArgumentException, CancelException, IOException { - AnalysisScope scope = CallGraphTestUtil.makeJ2SEAnalysisScope(TestConstants.WALA_TESTDATA, - CallGraphTestUtil.REGRESSION_EXCLUSIONS); - ClassHierarchy cha = ClassHierarchy.make(scope); - Iterable entrypoints = com.ibm.wala.ipa.callgraph.impl.Util.makeMainEntrypoints(scope, cha, - "LstaticInit/TestStaticInit"); - AnalysisOptions options = CallGraphTestUtil.makeAnalysisOptions(scope, entrypoints); - CallGraph cg = CallGraphTestUtil.buildZeroCFA(options, new AnalysisCache(), cha, scope, false); - boolean foundDoNothing = false; - for (CGNode n : cg) { - if (n.toString().contains("doNothing")) { - foundDoNothing = true; - break; - } - } - Assert.assertTrue(foundDoNothing); - options.setHandleStaticInit(false); - cg = CallGraphTestUtil.buildZeroCFA(options, new AnalysisCache(), cha, scope, false); - for (CGNode n : cg) { - Assert.assertTrue(!n.toString().contains("doNothing")); - } - } - - @Test public void testSystemProperties() throws ClassHierarchyException, IllegalArgumentException, CancelException, IOException { - AnalysisScope scope = CallGraphTestUtil.makeJ2SEAnalysisScope(TestConstants.WALA_TESTDATA, - CallGraphTestUtil.REGRESSION_EXCLUSIONS); - ClassHierarchy cha = ClassHierarchy.make(scope); - Iterable entrypoints = com.ibm.wala.ipa.callgraph.impl.Util.makeMainEntrypoints(scope, cha, - "LstaticInit/TestSystemProperties"); - AnalysisOptions options = CallGraphTestUtil.makeAnalysisOptions(scope, entrypoints); - SSAPropagationCallGraphBuilder builder = Util.makeZeroCFABuilder(options, new AnalysisCache(), cha, scope); - CallGraph cg = builder.makeCallGraph(options); - for (CGNode n : cg) { - if (n.toString().equals("Node: < Application, LstaticInit/TestSystemProperties, main([Ljava/lang/String;)V > Context: Everywhere")) { - boolean foundToCharArray = false; - for (CGNode callee : Iterator2Iterable.make(cg.getSuccNodes(n))) { - if (callee.getMethod().getName().toString().equals("toCharArray")) { - foundToCharArray = true; - break; - } - } - Assert.assertTrue(foundToCharArray); - break; - } - } - } - - @Test public void testRecursion() throws ClassHierarchyException, IllegalArgumentException, CancelException, IOException { - AnalysisScope scope = CallGraphTestUtil.makeJ2SEAnalysisScope(TestConstants.WALA_TESTDATA, - CallGraphTestUtil.REGRESSION_EXCLUSIONS); - ClassHierarchy cha = ClassHierarchy.make(scope); - Iterable entrypoints = com.ibm.wala.ipa.callgraph.impl.Util.makeMainEntrypoints(scope, cha, - TestConstants.RECURSE_MAIN); - AnalysisOptions options = CallGraphTestUtil.makeAnalysisOptions(scope, entrypoints); - - doCallGraphs(options, new AnalysisCache(), cha, scope); - } - - @Test public void testHelloAllEntrypoints() throws ClassHierarchyException, IllegalArgumentException, CancelException, IOException { - AnalysisScope scope = CallGraphTestUtil.makeJ2SEAnalysisScope(TestConstants.HELLO, CallGraphTestUtil.REGRESSION_EXCLUSIONS); - ClassHierarchy cha = ClassHierarchy.make(scope); - Iterable entrypoints = new AllApplicationEntrypoints(scope, cha); - AnalysisOptions options = CallGraphTestUtil.makeAnalysisOptions(scope, entrypoints); - - doCallGraphs(options, new AnalysisCache(), cha, scope); - } - - @Test public void testIO() throws ClassHierarchyException, IllegalArgumentException, CancelException, IOException { - AnalysisScope scope = CallGraphTestUtil.makeJ2SEAnalysisScope("primordial.txt", CallGraphTestUtil.REGRESSION_EXCLUSIONS); - ClassHierarchy cha = ClassHierarchy.make(scope); - Iterable entrypoints = makePrimordialPublicEntrypoints(scope, cha, "java/io"); - AnalysisOptions options = CallGraphTestUtil.makeAnalysisOptions(scope, entrypoints); - - CallGraphTestUtil.buildZeroCFA(options, new AnalysisCache(), cha, scope, false); - } - - public static Iterable makePrimordialPublicEntrypoints(AnalysisScope scope, ClassHierarchy cha, String pkg) { - final HashSet result = HashSetFactory.make(); - for (IClass clazz : cha) { - - if (clazz.getName().toString().indexOf(pkg) != -1 && !clazz.isInterface() && !clazz.isAbstract()) { - for (IMethod method : clazz.getDeclaredMethods()) { - if (method.isPublic() && !method.isAbstract()) { - System.out.println("Entry:" + method.getReference()); - result.add(new DefaultEntrypoint(method, cha)); - } - } - } - } - return new Iterable() { - public Iterator iterator() { - return result.iterator(); - } - }; - } - - @Test public void testPrimordial() throws ClassHierarchyException, IllegalArgumentException, CancelException, IOException { - if (useShortProfile()) { - return; - } - - AnalysisScope scope = - CallGraphTestUtil.makeJ2SEAnalysisScope( - "primordial.txt", - (System.getProperty("os.name").equals("Mac OS X"))? - "Java60RegressionExclusions.txt": - "GUIExclusions.txt"); - ClassHierarchy cha = ClassHierarchy.make(scope); - Iterable entrypoints = makePrimordialMainEntrypoints(scope, cha); - AnalysisOptions options = CallGraphTestUtil.makeAnalysisOptions(scope, entrypoints); - - CallGraphTestUtil.buildZeroCFA(options, new AnalysisCache(), cha, scope, false); - } - - /** - * make main entrypoints, even in the primordial loader. - */ - public static Iterable makePrimordialMainEntrypoints(AnalysisScope scope, ClassHierarchy cha) { - final Atom mainMethod = Atom.findOrCreateAsciiAtom("main"); - final HashSet result = HashSetFactory.make(); - for (IClass klass : cha) { - MethodReference mainRef = MethodReference.findOrCreate(klass.getReference(), mainMethod, Descriptor - .findOrCreateUTF8("([Ljava/lang/String;)V")); - IMethod m = klass.getMethod(mainRef.getSelector()); - if (m != null) { - result.add(new DefaultEntrypoint(m, cha)); - } - } - return new Iterable() { - public Iterator iterator() { - return result.iterator(); - } - }; - } - - public static void doCallGraphs(AnalysisOptions options, AnalysisCache cache, IClassHierarchy cha, AnalysisScope scope) - throws IllegalArgumentException, CancelException { - doCallGraphs(options, cache, cha, scope, false); - } - - /** - * TODO: refactor this to avoid excessive code bloat. - * - * @throws CancelException - * @throws IllegalArgumentException - */ - public static void doCallGraphs(AnalysisOptions options, AnalysisCache cache, IClassHierarchy cha, AnalysisScope scope, - boolean testPAToString) throws IllegalArgumentException, CancelException { - - // /////////////// - // // RTA ///// - // /////////////// - CallGraph cg = CallGraphTestUtil.buildRTA(options, cache, cha, scope); - try { - GraphIntegrity.check(cg); - } catch (UnsoundGraphException e1) { - e1.printStackTrace(); - Assert.assertTrue(e1.getMessage(), false); - } - - Set rtaMethods = CallGraphStats.collectMethods(cg); - System.err.println("RTA methods reached: " + rtaMethods.size()); - System.err.println(CallGraphStats.getStats(cg)); - System.err.println("RTA warnings:\n"); - - // /////////////// - // // 0-CFA ///// - // /////////////// - cg = CallGraphTestUtil.buildZeroCFA(options, cache, cha, scope, testPAToString); - - // FIXME: annoying special cases caused by clone2assign mean using - // the rta graph for proper graph subset checking does not work. - // (note that all the other such checks do use proper graph subset) - Graph squashZero = checkCallGraph(cg, null, rtaMethods, "0-CFA"); - - // test Pretransitive 0-CFA - // not currently supported - // warnings = new WarningSet(); - // options.setUsePreTransitiveSolver(true); - // CallGraph cgP = CallGraphTestUtil.buildZeroCFA(options, cha, scope, - // warnings); - // options.setUsePreTransitiveSolver(false); - // Graph squashPT = checkCallGraph(warnings, cgP, squashZero, null, "Pre-T - // 1"); - // checkCallGraph(warnings, cg, squashPT, null, "Pre-T 2"); - - // /////////////// - // // 0-1-CFA /// - // /////////////// - cg = CallGraphTestUtil.buildZeroOneCFA(options, cache, cha, scope, testPAToString); - Graph squashZeroOne = checkCallGraph(cg, squashZero, null, "0-1-CFA"); - - // /////////////////////////////////////////////////// - // // 0-CFA augmented to disambiguate containers /// - // /////////////////////////////////////////////////// - cg = CallGraphTestUtil.buildZeroContainerCFA(options, cache, cha, scope); - Graph squashZeroContainer = checkCallGraph(cg, squashZero, null, "0-Container-CFA"); - - // /////////////////////////////////////////////////// - // // 0-1-CFA augmented to disambiguate containers /// - // /////////////////////////////////////////////////// - cg = CallGraphTestUtil.buildZeroOneContainerCFA(options, cache, cha, scope); - checkCallGraph(cg, squashZeroContainer, null, "0-1-Container-CFA"); - checkCallGraph(cg, squashZeroOne, null, "0-1-Container-CFA"); - - // test ICFG - checkICFG(cg); - return; - // ///////////// - // // 1-CFA /// - // ///////////// - // warnings = new WarningSet(); - // cg = buildOneCFA(); - - } - - /** - * Check properties of the InterproceduralCFG - * - * @param cg - */ - private static void checkICFG(CallGraph cg) { - InterproceduralCFG icfg = new InterproceduralCFG(cg); - - try { - GraphIntegrity.check(icfg); - } catch (UnsoundGraphException e) { - e.printStackTrace(); - Assert.assertTrue(false); - } - - // perform a little icfg exercise - int count = 0; - for (Iterator> it = icfg.iterator(); it.hasNext();) { - BasicBlockInContext bb = it.next(); - if (icfg.hasCall((BasicBlockInContext) bb)) { - count++; - } - } - } - - /** - * Check consistency of a callgraph, and check that this call graph is a subset of a super-graph - * - * @param warnings object to track warnings - * @param cg - * @param superCG - * @param superMethods - * @param thisAlgorithm - * @return a squashed version of cg - */ - private static Graph checkCallGraph(CallGraph cg, Graph superCG, - Set superMethods, String thisAlgorithm) { - try { - GraphIntegrity.check(cg); - } catch (UnsoundGraphException e1) { - Assert.assertTrue(e1.getMessage(), false); - } - Set callGraphMethods = CallGraphStats.collectMethods(cg); - System.err.println(thisAlgorithm + " methods reached: " + callGraphMethods.size()); - System.err.println(CallGraphStats.getStats(cg)); - - Graph thisCG = squashCallGraph(thisAlgorithm, cg); - - if (superCG != null) { - com.ibm.wala.ipa.callgraph.impl.Util.checkGraphSubset(superCG, thisCG); - } else { - // SJF: RTA has rotted a bit since it doesn't handle LoadClass instructions. - // Commenting this out for now. - // if (!superMethods.containsAll(callGraphMethods)) { - // Set temp = HashSetFactory.make(); - // temp.addAll(callGraphMethods); - // temp.removeAll(superMethods); - // System.err.println("Violations"); - // for (MethodReference m : temp) { - // System.err.println(m); - // } - // Assertions.UNREACHABLE(); - // } - } - - return thisCG; - } - - /** - * @param name - * @param cg - * @return a graph whose nodes are MethodReferences, and whose edges represent calls between MethodReferences - * @throws IllegalArgumentException if cg is null - */ - public static Graph squashCallGraph(final String name, final CallGraph cg) { - if (cg == null) { - throw new IllegalArgumentException("cg is null"); - } - final Set nodes = HashSetFactory.make(); - for (Iterator nodesI = cg.iterator(); nodesI.hasNext();) { - nodes.add(((CGNode) nodesI.next()).getMethod().getReference()); - } - - return new Graph() { - @Override - public String toString() { - StringBuffer result = new StringBuffer(); - result.append("squashed " + name + " call graph\n"); - result.append("Original graph:"); - result.append(cg.toString()); - return result.toString(); - } - - /* - * @see com.ibm.wala.util.graph.NodeManager#iterateNodes() - */ - public Iterator iterator() { - return nodes.iterator(); - } - - /* - * @see com.ibm.wala.util.graph.NodeManager#containsNode(java.lang.Object) - */ - public boolean containsNode(MethodReference N) { - return nodes.contains(N); - } - - /* - * @see com.ibm.wala.util.graph.NodeManager#getNumberOfNodes() - */ - public int getNumberOfNodes() { - return nodes.size(); - } - - /* - * @see com.ibm.wala.util.graph.EdgeManager#getPredNodes(java.lang.Object) - */ - public Iterator getPredNodes(MethodReference N) { - Set pred = HashSetFactory.make(10); - MethodReference methodReference = N; - for (Iterator i = cg.getNodes(methodReference).iterator(); i.hasNext();) - for (Iterator ps = cg.getPredNodes(i.next()); ps.hasNext();) - pred.add(((CGNode) ps.next()).getMethod().getReference()); - - return pred.iterator(); - } - - /* - * @see com.ibm.wala.util.graph.EdgeManager#getPredNodeCount(java.lang.Object) - */ - public int getPredNodeCount(MethodReference N) { - int count = 0; - for (Iterator ps = getPredNodes(N); ps.hasNext(); count++, ps.next()) - ; - return count; - } - - /* - * @see com.ibm.wala.util.graph.EdgeManager#getSuccNodes(java.lang.Object) - */ - public Iterator getSuccNodes(MethodReference N) { - Set succ = HashSetFactory.make(10); - MethodReference methodReference = N; - for (Iterator i = cg.getNodes(methodReference).iterator(); i.hasNext();) - for (Iterator ps = cg.getSuccNodes(i.next()); ps.hasNext();) - succ.add(((CGNode) ps.next()).getMethod().getReference()); - - return succ.iterator(); - } - - /* - * @see com.ibm.wala.util.graph.EdgeManager#getSuccNodeCount(java.lang.Object) - */ - public int getSuccNodeCount(MethodReference N) { - int count = 0; - for (Iterator ps = getSuccNodes(N); ps.hasNext(); count++, ps.next()) - ; - return count; - } - - /* - * @see com.ibm.wala.util.graph.NodeManager#addNode(java.lang.Object) - */ - public void addNode(MethodReference n) { - Assertions.UNREACHABLE(); - } - - /* - * @see com.ibm.wala.util.graph.NodeManager#removeNode(java.lang.Object) - */ - public void removeNode(MethodReference n) { - Assertions.UNREACHABLE(); - } - - /* - * @see com.ibm.wala.util.graph.EdgeManager#addEdge(java.lang.Object, java.lang.Object) - */ - public void addEdge(MethodReference src, MethodReference dst) { - Assertions.UNREACHABLE(); - } - - public void removeEdge(MethodReference src, MethodReference dst) { - Assertions.UNREACHABLE(); - } - - /* - * @see com.ibm.wala.util.graph.EdgeManager#removeAllIncidentEdges(java.lang.Object) - */ - public void removeAllIncidentEdges(MethodReference node) { - Assertions.UNREACHABLE(); - } - - /* - * @see com.ibm.wala.util.graph.Graph#removeNodeAndEdges(java.lang.Object) - */ - public void removeNodeAndEdges(MethodReference N) { - Assertions.UNREACHABLE(); - } - - public void removeIncomingEdges(MethodReference node) { - // TODO Auto-generated method stubMethodReference - Assertions.UNREACHABLE(); - - } - - public void removeOutgoingEdges(MethodReference node) { - // TODO Auto-generated method stub - Assertions.UNREACHABLE(); - - } - - public boolean hasEdge(MethodReference src, MethodReference dst) { - for (Iterator succNodes = getSuccNodes(src); succNodes.hasNext();) { - if (dst.equals(succNodes.next())) { - return true; - } - } - return false; - } - }; - } - -} +/******************************************************************************* + * 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 com.ibm.wala.core.tests.callGraph; + +import java.io.IOException; +import java.util.HashSet; +import java.util.Iterator; +import java.util.Set; + +import org.junit.Assert; +import org.junit.Test; + +import com.ibm.wala.classLoader.IClass; +import com.ibm.wala.classLoader.IMethod; +import com.ibm.wala.core.tests.util.TestConstants; +import com.ibm.wala.core.tests.util.WalaTestCase; +import com.ibm.wala.ipa.callgraph.AnalysisCache; +import com.ibm.wala.ipa.callgraph.AnalysisOptions; +import com.ibm.wala.ipa.callgraph.AnalysisScope; +import com.ibm.wala.ipa.callgraph.CGNode; +import com.ibm.wala.ipa.callgraph.CallGraph; +import com.ibm.wala.ipa.callgraph.CallGraphStats; +import com.ibm.wala.ipa.callgraph.Entrypoint; +import com.ibm.wala.ipa.callgraph.impl.AllApplicationEntrypoints; +import com.ibm.wala.ipa.callgraph.impl.DefaultEntrypoint; +import com.ibm.wala.ipa.callgraph.impl.Util; +import com.ibm.wala.ipa.callgraph.propagation.SSAPropagationCallGraphBuilder; +import com.ibm.wala.ipa.cfg.BasicBlockInContext; +import com.ibm.wala.ipa.cfg.InterproceduralCFG; +import com.ibm.wala.ipa.cha.ClassHierarchy; +import com.ibm.wala.ipa.cha.ClassHierarchyException; +import com.ibm.wala.ipa.cha.IClassHierarchy; +import com.ibm.wala.ssa.ISSABasicBlock; +import com.ibm.wala.types.Descriptor; +import com.ibm.wala.types.MethodReference; +import com.ibm.wala.util.CancelException; +import com.ibm.wala.util.collections.HashSetFactory; +import com.ibm.wala.util.collections.Iterator2Iterable; +import com.ibm.wala.util.debug.Assertions; +import com.ibm.wala.util.graph.Graph; +import com.ibm.wala.util.graph.GraphIntegrity; +import com.ibm.wala.util.graph.GraphIntegrity.UnsoundGraphException; +import com.ibm.wala.util.strings.Atom; +import com.ibm.wala.util.warnings.Warnings; + +/** + * Tests for Call Graph construction + */ + +public class CallGraphTest extends WalaTestCase { + + public static void main(String[] args) { + justThisTest(CallGraphTest.class); + } + + + @Test public void testJava_cup() throws ClassHierarchyException, IllegalArgumentException, CancelException, IOException { + AnalysisScope scope = CallGraphTestUtil.makeJ2SEAnalysisScope(TestConstants.JAVA_CUP, CallGraphTestUtil.REGRESSION_EXCLUSIONS); + ClassHierarchy cha = ClassHierarchy.make(scope); + Iterable entrypoints = com.ibm.wala.ipa.callgraph.impl.Util.makeMainEntrypoints(scope, cha, + TestConstants.JAVA_CUP_MAIN); + AnalysisOptions options = CallGraphTestUtil.makeAnalysisOptions(scope, entrypoints); + + doCallGraphs(options, new AnalysisCache(), cha, scope, useShortProfile()); + } + + @Test public void testBcelVerifier() throws ClassHierarchyException, IllegalArgumentException, CancelException, IOException { + AnalysisScope scope = CallGraphTestUtil.makeJ2SEAnalysisScope(TestConstants.BCEL, CallGraphTestUtil.REGRESSION_EXCLUSIONS); + ClassHierarchy cha = ClassHierarchy.make(scope); + Iterable entrypoints = com.ibm.wala.ipa.callgraph.impl.Util.makeMainEntrypoints(scope, cha, + TestConstants.BCEL_VERIFIER_MAIN); + AnalysisOptions options = CallGraphTestUtil.makeAnalysisOptions(scope, entrypoints); + + doCallGraphs(options, new AnalysisCache(), cha, scope); + } + + @Test public void testJLex() throws ClassHierarchyException, IllegalArgumentException, CancelException, IOException { + AnalysisScope scope = CallGraphTestUtil.makeJ2SEAnalysisScope(TestConstants.JLEX, CallGraphTestUtil.REGRESSION_EXCLUSIONS); + ClassHierarchy cha = ClassHierarchy.make(scope); + Iterable entrypoints = com.ibm.wala.ipa.callgraph.impl.Util + .makeMainEntrypoints(scope, cha, TestConstants.JLEX_MAIN); + AnalysisOptions options = CallGraphTestUtil.makeAnalysisOptions(scope, entrypoints); + + doCallGraphs(options, new AnalysisCache(), cha, scope); + } + + @Test public void testCornerCases() throws ClassHierarchyException, IllegalArgumentException, CancelException, IOException { + AnalysisScope scope = CallGraphTestUtil.makeJ2SEAnalysisScope(TestConstants.WALA_TESTDATA, + CallGraphTestUtil.REGRESSION_EXCLUSIONS); + ClassHierarchy cha = ClassHierarchy.make(scope); + Iterable entrypoints = new AllApplicationEntrypoints(scope, cha); + AnalysisOptions options = CallGraphTestUtil.makeAnalysisOptions(scope, entrypoints); + + doCallGraphs(options, new AnalysisCache(), cha, scope); + + // we expect a warning or two about class Abstract1, which has no concrete + // subclasses + String ws = Warnings.asString(); + Assert.assertTrue("failed to report a warning about Abstract1", ws.indexOf("cornerCases/Abstract1") > -1); + + // we do not expect a warning about class Abstract2, which has a concrete + // subclasses + Assert.assertTrue("reported a warning about Abstract2", ws.indexOf("cornerCases/Abstract2") == -1); + } + + @Test public void testHello() throws ClassHierarchyException, IllegalArgumentException, CancelException, IOException { + AnalysisScope scope = CallGraphTestUtil.makeJ2SEAnalysisScope(TestConstants.HELLO, CallGraphTestUtil.REGRESSION_EXCLUSIONS); + ClassHierarchy cha = ClassHierarchy.make(scope); + Iterable entrypoints = com.ibm.wala.ipa.callgraph.impl.Util.makeMainEntrypoints(scope, cha, + TestConstants.HELLO_MAIN); + AnalysisOptions options = CallGraphTestUtil.makeAnalysisOptions(scope, entrypoints); + + doCallGraphs(options, new AnalysisCache(), cha, scope); + } + + @Test public void testStaticInit() throws ClassHierarchyException, IllegalArgumentException, CancelException, IOException { + AnalysisScope scope = CallGraphTestUtil.makeJ2SEAnalysisScope(TestConstants.WALA_TESTDATA, + CallGraphTestUtil.REGRESSION_EXCLUSIONS); + ClassHierarchy cha = ClassHierarchy.make(scope); + Iterable entrypoints = com.ibm.wala.ipa.callgraph.impl.Util.makeMainEntrypoints(scope, cha, + "LstaticInit/TestStaticInit"); + AnalysisOptions options = CallGraphTestUtil.makeAnalysisOptions(scope, entrypoints); + CallGraph cg = CallGraphTestUtil.buildZeroCFA(options, new AnalysisCache(), cha, scope, false); + boolean foundDoNothing = false; + for (CGNode n : cg) { + if (n.toString().contains("doNothing")) { + foundDoNothing = true; + break; + } + } + Assert.assertTrue(foundDoNothing); + options.setHandleStaticInit(false); + cg = CallGraphTestUtil.buildZeroCFA(options, new AnalysisCache(), cha, scope, false); + for (CGNode n : cg) { + Assert.assertTrue(!n.toString().contains("doNothing")); + } + } + + @Test public void testSystemProperties() throws ClassHierarchyException, IllegalArgumentException, CancelException, IOException { + AnalysisScope scope = CallGraphTestUtil.makeJ2SEAnalysisScope(TestConstants.WALA_TESTDATA, + CallGraphTestUtil.REGRESSION_EXCLUSIONS); + ClassHierarchy cha = ClassHierarchy.make(scope); + Iterable entrypoints = com.ibm.wala.ipa.callgraph.impl.Util.makeMainEntrypoints(scope, cha, + "LstaticInit/TestSystemProperties"); + AnalysisOptions options = CallGraphTestUtil.makeAnalysisOptions(scope, entrypoints); + SSAPropagationCallGraphBuilder builder = Util.makeZeroCFABuilder(options, new AnalysisCache(), cha, scope); + CallGraph cg = builder.makeCallGraph(options); + for (CGNode n : cg) { + if (n.toString().equals("Node: < Application, LstaticInit/TestSystemProperties, main([Ljava/lang/String;)V > Context: Everywhere")) { + boolean foundToCharArray = false; + for (CGNode callee : Iterator2Iterable.make(cg.getSuccNodes(n))) { + if (callee.getMethod().getName().toString().equals("toCharArray")) { + foundToCharArray = true; + break; + } + } + Assert.assertTrue(foundToCharArray); + break; + } + } + } + + @Test public void testRecursion() throws ClassHierarchyException, IllegalArgumentException, CancelException, IOException { + AnalysisScope scope = CallGraphTestUtil.makeJ2SEAnalysisScope(TestConstants.WALA_TESTDATA, + CallGraphTestUtil.REGRESSION_EXCLUSIONS); + ClassHierarchy cha = ClassHierarchy.make(scope); + Iterable entrypoints = com.ibm.wala.ipa.callgraph.impl.Util.makeMainEntrypoints(scope, cha, + TestConstants.RECURSE_MAIN); + AnalysisOptions options = CallGraphTestUtil.makeAnalysisOptions(scope, entrypoints); + + doCallGraphs(options, new AnalysisCache(), cha, scope); + } + + @Test public void testHelloAllEntrypoints() throws ClassHierarchyException, IllegalArgumentException, CancelException, IOException { + AnalysisScope scope = CallGraphTestUtil.makeJ2SEAnalysisScope(TestConstants.HELLO, CallGraphTestUtil.REGRESSION_EXCLUSIONS); + ClassHierarchy cha = ClassHierarchy.make(scope); + Iterable entrypoints = new AllApplicationEntrypoints(scope, cha); + AnalysisOptions options = CallGraphTestUtil.makeAnalysisOptions(scope, entrypoints); + + doCallGraphs(options, new AnalysisCache(), cha, scope); + } + + @Test public void testIO() throws ClassHierarchyException, IllegalArgumentException, CancelException, IOException { + AnalysisScope scope = CallGraphTestUtil.makeJ2SEAnalysisScope("primordial.txt", CallGraphTestUtil.REGRESSION_EXCLUSIONS); + ClassHierarchy cha = ClassHierarchy.make(scope); + Iterable entrypoints = makePrimordialPublicEntrypoints(scope, cha, "java/io"); + AnalysisOptions options = CallGraphTestUtil.makeAnalysisOptions(scope, entrypoints); + + CallGraphTestUtil.buildZeroCFA(options, new AnalysisCache(), cha, scope, false); + } + + public static Iterable makePrimordialPublicEntrypoints(AnalysisScope scope, ClassHierarchy cha, String pkg) { + final HashSet result = HashSetFactory.make(); + for (IClass clazz : cha) { + + if (clazz.getName().toString().indexOf(pkg) != -1 && !clazz.isInterface() && !clazz.isAbstract()) { + for (IMethod method : clazz.getDeclaredMethods()) { + if (method.isPublic() && !method.isAbstract()) { + System.out.println("Entry:" + method.getReference()); + result.add(new DefaultEntrypoint(method, cha)); + } + } + } + } + return new Iterable() { + public Iterator iterator() { + return result.iterator(); + } + }; + } + + @Test public void testPrimordial() throws ClassHierarchyException, IllegalArgumentException, CancelException, IOException { + if (useShortProfile()) { + return; + } + + AnalysisScope scope = + CallGraphTestUtil.makeJ2SEAnalysisScope( + "primordial.txt", + (System.getProperty("os.name").equals("Mac OS X"))? + "Java60RegressionExclusions.txt": + "GUIExclusions.txt"); + ClassHierarchy cha = ClassHierarchy.make(scope); + Iterable entrypoints = makePrimordialMainEntrypoints(scope, cha); + AnalysisOptions options = CallGraphTestUtil.makeAnalysisOptions(scope, entrypoints); + + CallGraphTestUtil.buildZeroCFA(options, new AnalysisCache(), cha, scope, false); + } + + /** + * make main entrypoints, even in the primordial loader. + */ + public static Iterable makePrimordialMainEntrypoints(AnalysisScope scope, ClassHierarchy cha) { + final Atom mainMethod = Atom.findOrCreateAsciiAtom("main"); + final HashSet result = HashSetFactory.make(); + for (IClass klass : cha) { + MethodReference mainRef = MethodReference.findOrCreate(klass.getReference(), mainMethod, Descriptor + .findOrCreateUTF8("([Ljava/lang/String;)V")); + IMethod m = klass.getMethod(mainRef.getSelector()); + if (m != null) { + result.add(new DefaultEntrypoint(m, cha)); + } + } + return new Iterable() { + public Iterator iterator() { + return result.iterator(); + } + }; + } + + public static void doCallGraphs(AnalysisOptions options, AnalysisCache cache, IClassHierarchy cha, AnalysisScope scope) + throws IllegalArgumentException, CancelException { + doCallGraphs(options, cache, cha, scope, false); + } + + /** + * TODO: refactor this to avoid excessive code bloat. + * + * @throws CancelException + * @throws IllegalArgumentException + */ + public static void doCallGraphs(AnalysisOptions options, AnalysisCache cache, IClassHierarchy cha, AnalysisScope scope, + boolean testPAToString) throws IllegalArgumentException, CancelException { + + // /////////////// + // // RTA ///// + // /////////////// + CallGraph cg = CallGraphTestUtil.buildRTA(options, cache, cha, scope); + try { + GraphIntegrity.check(cg); + } catch (UnsoundGraphException e1) { + e1.printStackTrace(); + Assert.assertTrue(e1.getMessage(), false); + } + + Set rtaMethods = CallGraphStats.collectMethods(cg); + System.err.println("RTA methods reached: " + rtaMethods.size()); + System.err.println(CallGraphStats.getStats(cg)); + System.err.println("RTA warnings:\n"); + + // /////////////// + // // 0-CFA ///// + // /////////////// + cg = CallGraphTestUtil.buildZeroCFA(options, cache, cha, scope, testPAToString); + + // FIXME: annoying special cases caused by clone2assign mean using + // the rta graph for proper graph subset checking does not work. + // (note that all the other such checks do use proper graph subset) + Graph squashZero = checkCallGraph(cg, null, rtaMethods, "0-CFA"); + + // test Pretransitive 0-CFA + // not currently supported + // warnings = new WarningSet(); + // options.setUsePreTransitiveSolver(true); + // CallGraph cgP = CallGraphTestUtil.buildZeroCFA(options, cha, scope, + // warnings); + // options.setUsePreTransitiveSolver(false); + // Graph squashPT = checkCallGraph(warnings, cgP, squashZero, null, "Pre-T + // 1"); + // checkCallGraph(warnings, cg, squashPT, null, "Pre-T 2"); + + // /////////////// + // // 0-1-CFA /// + // /////////////// + cg = CallGraphTestUtil.buildZeroOneCFA(options, cache, cha, scope, testPAToString); + Graph squashZeroOne = checkCallGraph(cg, squashZero, null, "0-1-CFA"); + + // /////////////////////////////////////////////////// + // // 0-CFA augmented to disambiguate containers /// + // /////////////////////////////////////////////////// + cg = CallGraphTestUtil.buildZeroContainerCFA(options, cache, cha, scope); + Graph squashZeroContainer = checkCallGraph(cg, squashZero, null, "0-Container-CFA"); + + // /////////////////////////////////////////////////// + // // 0-1-CFA augmented to disambiguate containers /// + // /////////////////////////////////////////////////// + cg = CallGraphTestUtil.buildZeroOneContainerCFA(options, cache, cha, scope); + checkCallGraph(cg, squashZeroContainer, null, "0-1-Container-CFA"); + checkCallGraph(cg, squashZeroOne, null, "0-1-Container-CFA"); + + // test ICFG + checkICFG(cg); + return; + // ///////////// + // // 1-CFA /// + // ///////////// + // warnings = new WarningSet(); + // cg = buildOneCFA(); + + } + + /** + * Check properties of the InterproceduralCFG + * + * @param cg + */ + private static void checkICFG(CallGraph cg) { + InterproceduralCFG icfg = new InterproceduralCFG(cg); + + try { + GraphIntegrity.check(icfg); + } catch (UnsoundGraphException e) { + e.printStackTrace(); + Assert.assertTrue(false); + } + + // perform a little icfg exercise + int count = 0; + for (Iterator> it = icfg.iterator(); it.hasNext();) { + BasicBlockInContext bb = it.next(); + if (icfg.hasCall((BasicBlockInContext) bb)) { + count++; + } + } + } + + /** + * Check consistency of a callgraph, and check that this call graph is a subset of a super-graph + * + * @param warnings object to track warnings + * @param cg + * @param superCG + * @param superMethods + * @param thisAlgorithm + * @return a squashed version of cg + */ + private static Graph checkCallGraph(CallGraph cg, Graph superCG, + Set superMethods, String thisAlgorithm) { + try { + GraphIntegrity.check(cg); + } catch (UnsoundGraphException e1) { + Assert.assertTrue(e1.getMessage(), false); + } + Set callGraphMethods = CallGraphStats.collectMethods(cg); + System.err.println(thisAlgorithm + " methods reached: " + callGraphMethods.size()); + System.err.println(CallGraphStats.getStats(cg)); + + Graph thisCG = squashCallGraph(thisAlgorithm, cg); + + if (superCG != null) { + com.ibm.wala.ipa.callgraph.impl.Util.checkGraphSubset(superCG, thisCG); + } else { + // SJF: RTA has rotted a bit since it doesn't handle LoadClass instructions. + // Commenting this out for now. + // if (!superMethods.containsAll(callGraphMethods)) { + // Set temp = HashSetFactory.make(); + // temp.addAll(callGraphMethods); + // temp.removeAll(superMethods); + // System.err.println("Violations"); + // for (MethodReference m : temp) { + // System.err.println(m); + // } + // Assertions.UNREACHABLE(); + // } + } + + return thisCG; + } + + /** + * @param name + * @param cg + * @return a graph whose nodes are MethodReferences, and whose edges represent calls between MethodReferences + * @throws IllegalArgumentException if cg is null + */ + public static Graph squashCallGraph(final String name, final CallGraph cg) { + if (cg == null) { + throw new IllegalArgumentException("cg is null"); + } + final Set nodes = HashSetFactory.make(); + for (Iterator nodesI = cg.iterator(); nodesI.hasNext();) { + nodes.add(((CGNode) nodesI.next()).getMethod().getReference()); + } + + return new Graph() { + @Override + public String toString() { + StringBuffer result = new StringBuffer(); + result.append("squashed " + name + " call graph\n"); + result.append("Original graph:"); + result.append(cg.toString()); + return result.toString(); + } + + /* + * @see com.ibm.wala.util.graph.NodeManager#iterateNodes() + */ + public Iterator iterator() { + return nodes.iterator(); + } + + /* + * @see com.ibm.wala.util.graph.NodeManager#containsNode(java.lang.Object) + */ + public boolean containsNode(MethodReference N) { + return nodes.contains(N); + } + + /* + * @see com.ibm.wala.util.graph.NodeManager#getNumberOfNodes() + */ + public int getNumberOfNodes() { + return nodes.size(); + } + + /* + * @see com.ibm.wala.util.graph.EdgeManager#getPredNodes(java.lang.Object) + */ + public Iterator getPredNodes(MethodReference N) { + Set pred = HashSetFactory.make(10); + MethodReference methodReference = N; + for (Iterator i = cg.getNodes(methodReference).iterator(); i.hasNext();) + for (Iterator ps = cg.getPredNodes(i.next()); ps.hasNext();) + pred.add(((CGNode) ps.next()).getMethod().getReference()); + + return pred.iterator(); + } + + /* + * @see com.ibm.wala.util.graph.EdgeManager#getPredNodeCount(java.lang.Object) + */ + public int getPredNodeCount(MethodReference N) { + int count = 0; + for (Iterator ps = getPredNodes(N); ps.hasNext(); count++, ps.next()) + ; + return count; + } + + /* + * @see com.ibm.wala.util.graph.EdgeManager#getSuccNodes(java.lang.Object) + */ + public Iterator getSuccNodes(MethodReference N) { + Set succ = HashSetFactory.make(10); + MethodReference methodReference = N; + for (Iterator i = cg.getNodes(methodReference).iterator(); i.hasNext();) + for (Iterator ps = cg.getSuccNodes(i.next()); ps.hasNext();) + succ.add(((CGNode) ps.next()).getMethod().getReference()); + + return succ.iterator(); + } + + /* + * @see com.ibm.wala.util.graph.EdgeManager#getSuccNodeCount(java.lang.Object) + */ + public int getSuccNodeCount(MethodReference N) { + int count = 0; + for (Iterator ps = getSuccNodes(N); ps.hasNext(); count++, ps.next()) + ; + return count; + } + + /* + * @see com.ibm.wala.util.graph.NodeManager#addNode(java.lang.Object) + */ + public void addNode(MethodReference n) { + Assertions.UNREACHABLE(); + } + + /* + * @see com.ibm.wala.util.graph.NodeManager#removeNode(java.lang.Object) + */ + public void removeNode(MethodReference n) { + Assertions.UNREACHABLE(); + } + + /* + * @see com.ibm.wala.util.graph.EdgeManager#addEdge(java.lang.Object, java.lang.Object) + */ + public void addEdge(MethodReference src, MethodReference dst) { + Assertions.UNREACHABLE(); + } + + public void removeEdge(MethodReference src, MethodReference dst) { + Assertions.UNREACHABLE(); + } + + /* + * @see com.ibm.wala.util.graph.EdgeManager#removeAllIncidentEdges(java.lang.Object) + */ + public void removeAllIncidentEdges(MethodReference node) { + Assertions.UNREACHABLE(); + } + + /* + * @see com.ibm.wala.util.graph.Graph#removeNodeAndEdges(java.lang.Object) + */ + public void removeNodeAndEdges(MethodReference N) { + Assertions.UNREACHABLE(); + } + + public void removeIncomingEdges(MethodReference node) { + // TODO Auto-generated method stubMethodReference + Assertions.UNREACHABLE(); + + } + + public void removeOutgoingEdges(MethodReference node) { + // TODO Auto-generated method stub + Assertions.UNREACHABLE(); + + } + + public boolean hasEdge(MethodReference src, MethodReference dst) { + for (Iterator succNodes = getSuccNodes(src); succNodes.hasNext();) { + if (dst.equals(succNodes.next())) { + return true; + } + } + return false; + } + }; + } + +} diff --git a/com.ibm.wala.core.tests/src/com/ibm/wala/core/tests/callGraph/CallGraphTestUtil.java b/com.ibm.wala.core.tests/src/com/ibm/wala/core/tests/callGraph/CallGraphTestUtil.java index d2fc631e1..ba51c9417 100644 --- a/com.ibm.wala.core.tests/src/com/ibm/wala/core/tests/callGraph/CallGraphTestUtil.java +++ b/com.ibm.wala.core.tests/src/com/ibm/wala/core/tests/callGraph/CallGraphTestUtil.java @@ -1,166 +1,166 @@ -/******************************************************************************* - * Copyright (c) 2002 - 2006 IBM Corporation. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * IBM Corporation - initial API and implementation - *******************************************************************************/ -package com.ibm.wala.core.tests.callGraph; - -import java.io.IOException; - -import com.ibm.wala.ipa.callgraph.AnalysisCache; -import com.ibm.wala.ipa.callgraph.AnalysisOptions; -import com.ibm.wala.ipa.callgraph.AnalysisScope; -import com.ibm.wala.ipa.callgraph.CallGraph; -import com.ibm.wala.ipa.callgraph.CallGraphBuilder; -import com.ibm.wala.ipa.callgraph.Entrypoint; -import com.ibm.wala.ipa.callgraph.impl.Util; -import com.ibm.wala.ipa.cha.IClassHierarchy; -import com.ibm.wala.util.CancelException; -import com.ibm.wala.util.config.AnalysisScopeReader; -import com.ibm.wala.util.io.FileProvider; -import com.ibm.wala.util.perf.StopwatchGC; - -/** - * Utilities for call graph tests - */ -public class CallGraphTestUtil { - - private static final ClassLoader MY_CLASSLOADER = CallGraphTestUtil.class.getClassLoader(); - - public static AnalysisOptions makeAnalysisOptions(AnalysisScope scope, Iterable entrypoints) { - AnalysisOptions options = new AnalysisOptions(scope, entrypoints); - return options; - } - - public static String REGRESSION_EXCLUSIONS = "Java60RegressionExclusions.txt"; - - /** - * should we check the heap footprint before and after CG construction? - */ - private static final boolean CHECK_FOOTPRINT = false; - - public static AnalysisScope makeJ2SEAnalysisScope(String scopeFile, String exclusionsFile) throws IOException { - AnalysisScope scope = AnalysisScopeReader.readJavaScope(scopeFile, (new FileProvider()).getFile(exclusionsFile), MY_CLASSLOADER); - return scope; - } - - public static CallGraph buildRTA(AnalysisOptions options, AnalysisCache cache, IClassHierarchy cha, AnalysisScope scope) - throws IllegalArgumentException, CancelException { - StopwatchGC S = null; - if (CHECK_FOOTPRINT) { - S = new StopwatchGC("build RTA graph"); - S.start(); - } - - CallGraphBuilder builder = Util.makeRTABuilder(options, cache, cha, scope); - CallGraph cg = builder.makeCallGraph(options, null); - - if (CHECK_FOOTPRINT) { - S.stop(); - System.err.println(S.report()); - } - return cg; - } - - public static CallGraph buildZeroCFA(AnalysisOptions options, AnalysisCache cache, IClassHierarchy cha, AnalysisScope scope, - boolean testPAtoString) throws IllegalArgumentException, CancelException { - StopwatchGC S = null; - if (CHECK_FOOTPRINT) { - S = new StopwatchGC("build RTA graph"); - S.start(); - } - - CallGraphBuilder builder = Util.makeZeroCFABuilder(options, cache, cha, scope); - CallGraph cg = builder.makeCallGraph(options, null); - if (testPAtoString) { - builder.getPointerAnalysis().toString(); - } - - if (CHECK_FOOTPRINT) { - S.stop(); - System.err.println(S.report()); - } - return cg; - } - - public static CallGraph buildVanillaZeroOneCFA(AnalysisOptions options, AnalysisCache cache, IClassHierarchy cha, - AnalysisScope scope) throws IllegalArgumentException, CancelException { - StopwatchGC S = null; - if (CHECK_FOOTPRINT) { - S = new StopwatchGC("build RTA graph"); - S.start(); - } - - CallGraphBuilder builder = Util.makeVanillaZeroOneCFABuilder(options, cache, cha, scope); - CallGraph cg = builder.makeCallGraph(options, null); - - if (CHECK_FOOTPRINT) { - S.stop(); - System.err.println(S.report()); - } - return cg; - } - - public static CallGraph buildZeroOneCFA(AnalysisOptions options, AnalysisCache cache, IClassHierarchy cha, AnalysisScope scope, - boolean testPAtoString) throws IllegalArgumentException, CancelException { - StopwatchGC S = null; - if (CHECK_FOOTPRINT) { - S = new StopwatchGC("build RTA graph"); - S.start(); - } - - CallGraphBuilder builder = Util.makeZeroOneCFABuilder(options, cache, cha, scope); - CallGraph cg = builder.makeCallGraph(options, null); - if (testPAtoString) { - builder.getPointerAnalysis().toString(); - } - - if (CHECK_FOOTPRINT) { - S.stop(); - System.err.println(S.report()); - } - return cg; - } - - public static CallGraph buildZeroContainerCFA(AnalysisOptions options, AnalysisCache cache, IClassHierarchy cha, - AnalysisScope scope) throws IllegalArgumentException, CancelException { - StopwatchGC S = null; - if (CHECK_FOOTPRINT) { - S = new StopwatchGC("build RTA graph"); - S.start(); - } - - CallGraphBuilder builder = Util.makeZeroContainerCFABuilder(options, cache, cha, scope); - CallGraph cg = builder.makeCallGraph(options, null); - - if (CHECK_FOOTPRINT) { - S.stop(); - System.err.println(S.report()); - } - return cg; - } - - public static CallGraph buildZeroOneContainerCFA(AnalysisOptions options, AnalysisCache cache, IClassHierarchy cha, - AnalysisScope scope) throws IllegalArgumentException, CancelException { - StopwatchGC S = null; - if (CHECK_FOOTPRINT) { - S = new StopwatchGC("build RTA graph"); - S.start(); - } - - CallGraphBuilder builder = Util.makeZeroOneContainerCFABuilder(options, cache, cha, scope); - CallGraph cg = builder.makeCallGraph(options, null); - - if (CHECK_FOOTPRINT) { - S.stop(); - System.err.println(S.report()); - } - return cg; - } - -} +/******************************************************************************* + * 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.core.tests.callGraph; + +import java.io.IOException; + +import com.ibm.wala.ipa.callgraph.AnalysisCache; +import com.ibm.wala.ipa.callgraph.AnalysisOptions; +import com.ibm.wala.ipa.callgraph.AnalysisScope; +import com.ibm.wala.ipa.callgraph.CallGraph; +import com.ibm.wala.ipa.callgraph.CallGraphBuilder; +import com.ibm.wala.ipa.callgraph.Entrypoint; +import com.ibm.wala.ipa.callgraph.impl.Util; +import com.ibm.wala.ipa.cha.IClassHierarchy; +import com.ibm.wala.util.CancelException; +import com.ibm.wala.util.config.AnalysisScopeReader; +import com.ibm.wala.util.io.FileProvider; +import com.ibm.wala.util.perf.StopwatchGC; + +/** + * Utilities for call graph tests + */ +public class CallGraphTestUtil { + + private static final ClassLoader MY_CLASSLOADER = CallGraphTestUtil.class.getClassLoader(); + + public static AnalysisOptions makeAnalysisOptions(AnalysisScope scope, Iterable entrypoints) { + AnalysisOptions options = new AnalysisOptions(scope, entrypoints); + return options; + } + + public static String REGRESSION_EXCLUSIONS = "Java60RegressionExclusions.txt"; + + /** + * should we check the heap footprint before and after CG construction? + */ + private static final boolean CHECK_FOOTPRINT = false; + + public static AnalysisScope makeJ2SEAnalysisScope(String scopeFile, String exclusionsFile) throws IOException { + AnalysisScope scope = AnalysisScopeReader.readJavaScope(scopeFile, (new FileProvider()).getFile(exclusionsFile), MY_CLASSLOADER); + return scope; + } + + public static CallGraph buildRTA(AnalysisOptions options, AnalysisCache cache, IClassHierarchy cha, AnalysisScope scope) + throws IllegalArgumentException, CancelException { + StopwatchGC S = null; + if (CHECK_FOOTPRINT) { + S = new StopwatchGC("build RTA graph"); + S.start(); + } + + CallGraphBuilder builder = Util.makeRTABuilder(options, cache, cha, scope); + CallGraph cg = builder.makeCallGraph(options, null); + + if (CHECK_FOOTPRINT) { + S.stop(); + System.err.println(S.report()); + } + return cg; + } + + public static CallGraph buildZeroCFA(AnalysisOptions options, AnalysisCache cache, IClassHierarchy cha, AnalysisScope scope, + boolean testPAtoString) throws IllegalArgumentException, CancelException { + StopwatchGC S = null; + if (CHECK_FOOTPRINT) { + S = new StopwatchGC("build RTA graph"); + S.start(); + } + + CallGraphBuilder builder = Util.makeZeroCFABuilder(options, cache, cha, scope); + CallGraph cg = builder.makeCallGraph(options, null); + if (testPAtoString) { + builder.getPointerAnalysis().toString(); + } + + if (CHECK_FOOTPRINT) { + S.stop(); + System.err.println(S.report()); + } + return cg; + } + + public static CallGraph buildVanillaZeroOneCFA(AnalysisOptions options, AnalysisCache cache, IClassHierarchy cha, + AnalysisScope scope) throws IllegalArgumentException, CancelException { + StopwatchGC S = null; + if (CHECK_FOOTPRINT) { + S = new StopwatchGC("build RTA graph"); + S.start(); + } + + CallGraphBuilder builder = Util.makeVanillaZeroOneCFABuilder(options, cache, cha, scope); + CallGraph cg = builder.makeCallGraph(options, null); + + if (CHECK_FOOTPRINT) { + S.stop(); + System.err.println(S.report()); + } + return cg; + } + + public static CallGraph buildZeroOneCFA(AnalysisOptions options, AnalysisCache cache, IClassHierarchy cha, AnalysisScope scope, + boolean testPAtoString) throws IllegalArgumentException, CancelException { + StopwatchGC S = null; + if (CHECK_FOOTPRINT) { + S = new StopwatchGC("build RTA graph"); + S.start(); + } + + CallGraphBuilder builder = Util.makeZeroOneCFABuilder(options, cache, cha, scope); + CallGraph cg = builder.makeCallGraph(options, null); + if (testPAtoString) { + builder.getPointerAnalysis().toString(); + } + + if (CHECK_FOOTPRINT) { + S.stop(); + System.err.println(S.report()); + } + return cg; + } + + public static CallGraph buildZeroContainerCFA(AnalysisOptions options, AnalysisCache cache, IClassHierarchy cha, + AnalysisScope scope) throws IllegalArgumentException, CancelException { + StopwatchGC S = null; + if (CHECK_FOOTPRINT) { + S = new StopwatchGC("build RTA graph"); + S.start(); + } + + CallGraphBuilder builder = Util.makeZeroContainerCFABuilder(options, cache, cha, scope); + CallGraph cg = builder.makeCallGraph(options, null); + + if (CHECK_FOOTPRINT) { + S.stop(); + System.err.println(S.report()); + } + return cg; + } + + public static CallGraph buildZeroOneContainerCFA(AnalysisOptions options, AnalysisCache cache, IClassHierarchy cha, + AnalysisScope scope) throws IllegalArgumentException, CancelException { + StopwatchGC S = null; + if (CHECK_FOOTPRINT) { + S = new StopwatchGC("build RTA graph"); + S.start(); + } + + CallGraphBuilder builder = Util.makeZeroOneContainerCFABuilder(options, cache, cha, scope); + CallGraph cg = builder.makeCallGraph(options, null); + + if (CHECK_FOOTPRINT) { + S.stop(); + System.err.println(S.report()); + } + return cg; + } + +} diff --git a/com.ibm.wala.core.tests/src/com/ibm/wala/core/tests/callGraph/ClassConstantTest.java b/com.ibm.wala.core.tests/src/com/ibm/wala/core/tests/callGraph/ClassConstantTest.java index 513d467d6..e199df366 100644 --- a/com.ibm.wala.core.tests/src/com/ibm/wala/core/tests/callGraph/ClassConstantTest.java +++ b/com.ibm.wala.core.tests/src/com/ibm/wala/core/tests/callGraph/ClassConstantTest.java @@ -1,76 +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.core.tests.callGraph; - -import java.io.IOException; -import java.util.Set; - -import junit.framework.Assert; - -import org.junit.Test; - -import com.ibm.wala.core.tests.util.TestConstants; -import com.ibm.wala.core.tests.util.WalaTestCase; -import com.ibm.wala.ipa.callgraph.AnalysisCache; -import com.ibm.wala.ipa.callgraph.AnalysisOptions; -import com.ibm.wala.ipa.callgraph.AnalysisScope; -import com.ibm.wala.ipa.callgraph.CGNode; -import com.ibm.wala.ipa.callgraph.CallGraph; -import com.ibm.wala.ipa.callgraph.Entrypoint; -import com.ibm.wala.ipa.callgraph.impl.Util; -import com.ibm.wala.ipa.cha.ClassHierarchy; -import com.ibm.wala.ipa.cha.ClassHierarchyException; -import com.ibm.wala.types.ClassLoaderReference; -import com.ibm.wala.types.MethodReference; -import com.ibm.wala.types.TypeReference; -import com.ibm.wala.util.CancelException; - -/** - * Check handling of class constants (test for part of 1.5 support) - */ -public class ClassConstantTest extends WalaTestCase { - - @Test public void testClassConstants() throws ClassHierarchyException, IllegalArgumentException, CancelException, IOException { - - AnalysisScope scope = CallGraphTestUtil.makeJ2SEAnalysisScope(TestConstants.WALA_TESTDATA, - CallGraphTestUtil.REGRESSION_EXCLUSIONS); - ClassHierarchy cha = ClassHierarchy.make(scope); - - // make sure we have the test class - TypeReference mainClassRef = TypeReference.findOrCreate(ClassLoaderReference.Application, TestConstants.CLASSCONSTANT_MAIN); - Assert.assertTrue(cha.lookupClass(mainClassRef) != null); - - // make call graph - Iterable entrypoints = Util.makeMainEntrypoints(scope, cha, TestConstants.CLASSCONSTANT_MAIN); - AnalysisOptions options = CallGraphTestUtil.makeAnalysisOptions(scope, entrypoints); - CallGraph cg = CallGraphTestUtil.buildZeroCFA(options, new AnalysisCache(), cha, scope, false); - // System.out.println("\nCall graph:"); - // Trace.println(cg); - - // make sure the main method is reached - MethodReference mainMethodRef = MethodReference.findOrCreate(mainClassRef, "main", "([Ljava/lang/String;)V"); - Set mainMethodNodes = cg.getNodes(mainMethodRef); - Assert.assertFalse(mainMethodNodes.isEmpty()); - CGNode mainMethodNode = (CGNode) mainMethodNodes.iterator().next(); - // Trace.println("main IR:"); - // Trace.println(mainMethodNode.getIR()); - - // Make sure call to hashCode is there (it uses the class constant) - TypeReference classRef = TypeReference.findOrCreate(ClassLoaderReference.Primordial, "Ljava/lang/Class"); - MethodReference hashCodeRef = MethodReference.findOrCreate(classRef, "hashCode", "()I"); - Set hashCodeNodes = cg.getNodes(hashCodeRef); - Assert.assertFalse(hashCodeNodes.isEmpty()); - - // make sure call to hashCode from main - Assert.assertTrue(cg.hasEdge(mainMethodNode, hashCodeNodes.iterator().next())); - } - -} +/******************************************************************************* + * 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.core.tests.callGraph; + +import java.io.IOException; +import java.util.Set; + +import junit.framework.Assert; + +import org.junit.Test; + +import com.ibm.wala.core.tests.util.TestConstants; +import com.ibm.wala.core.tests.util.WalaTestCase; +import com.ibm.wala.ipa.callgraph.AnalysisCache; +import com.ibm.wala.ipa.callgraph.AnalysisOptions; +import com.ibm.wala.ipa.callgraph.AnalysisScope; +import com.ibm.wala.ipa.callgraph.CGNode; +import com.ibm.wala.ipa.callgraph.CallGraph; +import com.ibm.wala.ipa.callgraph.Entrypoint; +import com.ibm.wala.ipa.callgraph.impl.Util; +import com.ibm.wala.ipa.cha.ClassHierarchy; +import com.ibm.wala.ipa.cha.ClassHierarchyException; +import com.ibm.wala.types.ClassLoaderReference; +import com.ibm.wala.types.MethodReference; +import com.ibm.wala.types.TypeReference; +import com.ibm.wala.util.CancelException; + +/** + * Check handling of class constants (test for part of 1.5 support) + */ +public class ClassConstantTest extends WalaTestCase { + + @Test public void testClassConstants() throws ClassHierarchyException, IllegalArgumentException, CancelException, IOException { + + AnalysisScope scope = CallGraphTestUtil.makeJ2SEAnalysisScope(TestConstants.WALA_TESTDATA, + CallGraphTestUtil.REGRESSION_EXCLUSIONS); + ClassHierarchy cha = ClassHierarchy.make(scope); + + // make sure we have the test class + TypeReference mainClassRef = TypeReference.findOrCreate(ClassLoaderReference.Application, TestConstants.CLASSCONSTANT_MAIN); + Assert.assertTrue(cha.lookupClass(mainClassRef) != null); + + // make call graph + Iterable entrypoints = Util.makeMainEntrypoints(scope, cha, TestConstants.CLASSCONSTANT_MAIN); + AnalysisOptions options = CallGraphTestUtil.makeAnalysisOptions(scope, entrypoints); + CallGraph cg = CallGraphTestUtil.buildZeroCFA(options, new AnalysisCache(), cha, scope, false); + // System.out.println("\nCall graph:"); + // Trace.println(cg); + + // make sure the main method is reached + MethodReference mainMethodRef = MethodReference.findOrCreate(mainClassRef, "main", "([Ljava/lang/String;)V"); + Set mainMethodNodes = cg.getNodes(mainMethodRef); + Assert.assertFalse(mainMethodNodes.isEmpty()); + CGNode mainMethodNode = (CGNode) mainMethodNodes.iterator().next(); + // Trace.println("main IR:"); + // Trace.println(mainMethodNode.getIR()); + + // Make sure call to hashCode is there (it uses the class constant) + TypeReference classRef = TypeReference.findOrCreate(ClassLoaderReference.Primordial, "Ljava/lang/Class"); + MethodReference hashCodeRef = MethodReference.findOrCreate(classRef, "hashCode", "()I"); + Set hashCodeNodes = cg.getNodes(hashCodeRef); + Assert.assertFalse(hashCodeNodes.isEmpty()); + + // make sure call to hashCode from main + Assert.assertTrue(cg.hasEdge(mainMethodNode, hashCodeNodes.iterator().next())); + } + +} diff --git a/com.ibm.wala.core.tests/src/com/ibm/wala/core/tests/callGraph/CloneTest.java b/com.ibm.wala.core.tests/src/com/ibm/wala/core/tests/callGraph/CloneTest.java index eddea6c86..d8930a39b 100644 --- a/com.ibm.wala.core.tests/src/com/ibm/wala/core/tests/callGraph/CloneTest.java +++ b/com.ibm.wala.core.tests/src/com/ibm/wala/core/tests/callGraph/CloneTest.java @@ -1,74 +1,74 @@ -/******************************************************************************* - * 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 com.ibm.wala.core.tests.callGraph; - -import java.io.IOException; -import java.util.Iterator; -import java.util.Set; - -import org.junit.Assert; -import org.junit.Test; - -import com.ibm.wala.classLoader.CallSiteReference; -import com.ibm.wala.core.tests.util.TestConstants; -import com.ibm.wala.core.tests.util.WalaTestCase; -import com.ibm.wala.ipa.callgraph.AnalysisCache; -import com.ibm.wala.ipa.callgraph.AnalysisOptions; -import com.ibm.wala.ipa.callgraph.AnalysisScope; -import com.ibm.wala.ipa.callgraph.CGNode; -import com.ibm.wala.ipa.callgraph.CallGraph; -import com.ibm.wala.ipa.callgraph.Entrypoint; -import com.ibm.wala.ipa.callgraph.impl.AllApplicationEntrypoints; -import com.ibm.wala.ipa.cha.ClassHierarchy; -import com.ibm.wala.ipa.cha.ClassHierarchyException; -import com.ibm.wala.types.ClassLoaderReference; -import com.ibm.wala.types.MethodReference; -import com.ibm.wala.types.TypeReference; -import com.ibm.wala.util.CancelException; - -/** - * Check properties of a call to clone() in RTA - */ -public class CloneTest extends WalaTestCase { - - @Test public void testClone() throws ClassHierarchyException, IllegalArgumentException, CancelException, IOException { - - AnalysisScope scope = CallGraphTestUtil.makeJ2SEAnalysisScope(TestConstants.WALA_TESTDATA, CallGraphTestUtil.REGRESSION_EXCLUSIONS); - ClassHierarchy cha = ClassHierarchy.make(scope); - Iterable entrypoints = new AllApplicationEntrypoints(scope, cha); - AnalysisOptions options = CallGraphTestUtil.makeAnalysisOptions(scope, entrypoints); - - CallGraph cg = CallGraphTestUtil.buildRTA(options, new AnalysisCache(),cha, scope); - - // Find node corresponding to java.text.MessageFormat.clone() - TypeReference t = TypeReference.findOrCreate(ClassLoaderReference.Primordial, "Ljava/text/MessageFormat"); - MethodReference m = MethodReference.findOrCreate(t, "clone", "()Ljava/lang/Object;"); - CGNode node = (CGNode) cg.getNodes(m).iterator().next(); - - // Check there's exactly one target for each super call in - // MessageFormat.clone() - for (Iterator i = node.iterateCallSites(); i.hasNext();) { - CallSiteReference site = (CallSiteReference) i.next(); - if (site.isSpecial()) { - if (site.getDeclaredTarget().getDeclaringClass().equals(TypeReference.JavaLangObject)) { - Set targets = cg.getPossibleTargets(node, site); - if (targets.size() != 1) { - System.err.println(targets.size() + " targets found for " + site); - for (Iterator k = targets.iterator(); k.hasNext();) { - System.err.println(" " + k.next()); - } - Assert.fail("found " + targets.size() + " targets for " + site + " in " + node); - } - } - } - } - } -} +/******************************************************************************* + * 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 com.ibm.wala.core.tests.callGraph; + +import java.io.IOException; +import java.util.Iterator; +import java.util.Set; + +import org.junit.Assert; +import org.junit.Test; + +import com.ibm.wala.classLoader.CallSiteReference; +import com.ibm.wala.core.tests.util.TestConstants; +import com.ibm.wala.core.tests.util.WalaTestCase; +import com.ibm.wala.ipa.callgraph.AnalysisCache; +import com.ibm.wala.ipa.callgraph.AnalysisOptions; +import com.ibm.wala.ipa.callgraph.AnalysisScope; +import com.ibm.wala.ipa.callgraph.CGNode; +import com.ibm.wala.ipa.callgraph.CallGraph; +import com.ibm.wala.ipa.callgraph.Entrypoint; +import com.ibm.wala.ipa.callgraph.impl.AllApplicationEntrypoints; +import com.ibm.wala.ipa.cha.ClassHierarchy; +import com.ibm.wala.ipa.cha.ClassHierarchyException; +import com.ibm.wala.types.ClassLoaderReference; +import com.ibm.wala.types.MethodReference; +import com.ibm.wala.types.TypeReference; +import com.ibm.wala.util.CancelException; + +/** + * Check properties of a call to clone() in RTA + */ +public class CloneTest extends WalaTestCase { + + @Test public void testClone() throws ClassHierarchyException, IllegalArgumentException, CancelException, IOException { + + AnalysisScope scope = CallGraphTestUtil.makeJ2SEAnalysisScope(TestConstants.WALA_TESTDATA, CallGraphTestUtil.REGRESSION_EXCLUSIONS); + ClassHierarchy cha = ClassHierarchy.make(scope); + Iterable entrypoints = new AllApplicationEntrypoints(scope, cha); + AnalysisOptions options = CallGraphTestUtil.makeAnalysisOptions(scope, entrypoints); + + CallGraph cg = CallGraphTestUtil.buildRTA(options, new AnalysisCache(),cha, scope); + + // Find node corresponding to java.text.MessageFormat.clone() + TypeReference t = TypeReference.findOrCreate(ClassLoaderReference.Primordial, "Ljava/text/MessageFormat"); + MethodReference m = MethodReference.findOrCreate(t, "clone", "()Ljava/lang/Object;"); + CGNode node = (CGNode) cg.getNodes(m).iterator().next(); + + // Check there's exactly one target for each super call in + // MessageFormat.clone() + for (Iterator i = node.iterateCallSites(); i.hasNext();) { + CallSiteReference site = (CallSiteReference) i.next(); + if (site.isSpecial()) { + if (site.getDeclaredTarget().getDeclaringClass().equals(TypeReference.JavaLangObject)) { + Set targets = cg.getPossibleTargets(node, site); + if (targets.size() != 1) { + System.err.println(targets.size() + " targets found for " + site); + for (Iterator k = targets.iterator(); k.hasNext();) { + System.err.println(" " + k.next()); + } + Assert.fail("found " + targets.size() + " targets for " + site + " in " + node); + } + } + } + } + } +} diff --git a/com.ibm.wala.core.tests/src/com/ibm/wala/core/tests/callGraph/DebuggingBitsetCallGraphTest.java b/com.ibm.wala.core.tests/src/com/ibm/wala/core/tests/callGraph/DebuggingBitsetCallGraphTest.java index dbf1bc6d0..71cf956d6 100644 --- a/com.ibm.wala.core.tests/src/com/ibm/wala/core/tests/callGraph/DebuggingBitsetCallGraphTest.java +++ b/com.ibm.wala.core.tests/src/com/ibm/wala/core/tests/callGraph/DebuggingBitsetCallGraphTest.java @@ -1,74 +1,74 @@ -/******************************************************************************* - * 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 com.ibm.wala.core.tests.callGraph; - -import java.io.IOException; - -import org.junit.Test; - -import com.ibm.wala.core.tests.util.WalaTestCase; -import com.ibm.wala.ipa.cha.ClassHierarchyException; -import com.ibm.wala.util.CancelException; -import com.ibm.wala.util.intset.BimodalMutableIntSetFactory; -import com.ibm.wala.util.intset.BitVectorIntSetFactory; -import com.ibm.wala.util.intset.DebuggingMutableIntSetFactory; -import com.ibm.wala.util.intset.IntSetUtil; -import com.ibm.wala.util.intset.MutableIntSetFactory; -import com.ibm.wala.util.intset.MutableSharedBitVectorIntSetFactory; -import com.ibm.wala.util.intset.MutableSparseIntSetFactory; -import com.ibm.wala.util.intset.SemiSparseMutableIntSetFactory; - -/** - * Run the call graph only test with paranoid debugging bit vectors - */ -public class DebuggingBitsetCallGraphTest extends WalaTestCase { - - public static void main(String[] args) { - justThisTest(DebuggingBitsetCallGraphTest.class); - } - - private final CallGraphTest graphTest; - - public DebuggingBitsetCallGraphTest() { - graphTest = new CallGraphTest(); - } - - private void runBitsetTest(MutableIntSetFactory p, MutableIntSetFactory s) throws ClassHierarchyException, IllegalArgumentException, CancelException, IOException { - MutableIntSetFactory save = IntSetUtil.getDefaultIntSetFactory(); - try { - IntSetUtil.setDefaultIntSetFactory(new DebuggingMutableIntSetFactory(p, s)); - graphTest.testJLex(); - } finally { - IntSetUtil.setDefaultIntSetFactory(save); - } - } - - @Test public void testBimodalSparse() throws ClassHierarchyException, IllegalArgumentException, CancelException, IOException { - runBitsetTest(new BimodalMutableIntSetFactory(), new MutableSparseIntSetFactory()); - } - - @Test public void testSharedBimodal() throws ClassHierarchyException, IllegalArgumentException, CancelException, IOException { - runBitsetTest(new MutableSharedBitVectorIntSetFactory(), new BimodalMutableIntSetFactory()); - } - - @Test public void testSharedSparse() throws ClassHierarchyException, IllegalArgumentException, CancelException, IOException { - runBitsetTest(new MutableSharedBitVectorIntSetFactory(), new MutableSparseIntSetFactory()); - } - - @Test public void testSharedBitVector() throws ClassHierarchyException, IllegalArgumentException, CancelException, IOException { - runBitsetTest(new MutableSharedBitVectorIntSetFactory(), new BitVectorIntSetFactory()); - } - - @Test public void testSemiSparseShared() throws ClassHierarchyException, IllegalArgumentException, CancelException, IOException { - runBitsetTest(new SemiSparseMutableIntSetFactory(), new MutableSharedBitVectorIntSetFactory()); - } - -} +/******************************************************************************* + * 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 com.ibm.wala.core.tests.callGraph; + +import java.io.IOException; + +import org.junit.Test; + +import com.ibm.wala.core.tests.util.WalaTestCase; +import com.ibm.wala.ipa.cha.ClassHierarchyException; +import com.ibm.wala.util.CancelException; +import com.ibm.wala.util.intset.BimodalMutableIntSetFactory; +import com.ibm.wala.util.intset.BitVectorIntSetFactory; +import com.ibm.wala.util.intset.DebuggingMutableIntSetFactory; +import com.ibm.wala.util.intset.IntSetUtil; +import com.ibm.wala.util.intset.MutableIntSetFactory; +import com.ibm.wala.util.intset.MutableSharedBitVectorIntSetFactory; +import com.ibm.wala.util.intset.MutableSparseIntSetFactory; +import com.ibm.wala.util.intset.SemiSparseMutableIntSetFactory; + +/** + * Run the call graph only test with paranoid debugging bit vectors + */ +public class DebuggingBitsetCallGraphTest extends WalaTestCase { + + public static void main(String[] args) { + justThisTest(DebuggingBitsetCallGraphTest.class); + } + + private final CallGraphTest graphTest; + + public DebuggingBitsetCallGraphTest() { + graphTest = new CallGraphTest(); + } + + private void runBitsetTest(MutableIntSetFactory p, MutableIntSetFactory s) throws ClassHierarchyException, IllegalArgumentException, CancelException, IOException { + MutableIntSetFactory save = IntSetUtil.getDefaultIntSetFactory(); + try { + IntSetUtil.setDefaultIntSetFactory(new DebuggingMutableIntSetFactory(p, s)); + graphTest.testJLex(); + } finally { + IntSetUtil.setDefaultIntSetFactory(save); + } + } + + @Test public void testBimodalSparse() throws ClassHierarchyException, IllegalArgumentException, CancelException, IOException { + runBitsetTest(new BimodalMutableIntSetFactory(), new MutableSparseIntSetFactory()); + } + + @Test public void testSharedBimodal() throws ClassHierarchyException, IllegalArgumentException, CancelException, IOException { + runBitsetTest(new MutableSharedBitVectorIntSetFactory(), new BimodalMutableIntSetFactory()); + } + + @Test public void testSharedSparse() throws ClassHierarchyException, IllegalArgumentException, CancelException, IOException { + runBitsetTest(new MutableSharedBitVectorIntSetFactory(), new MutableSparseIntSetFactory()); + } + + @Test public void testSharedBitVector() throws ClassHierarchyException, IllegalArgumentException, CancelException, IOException { + runBitsetTest(new MutableSharedBitVectorIntSetFactory(), new BitVectorIntSetFactory()); + } + + @Test public void testSemiSparseShared() throws ClassHierarchyException, IllegalArgumentException, CancelException, IOException { + runBitsetTest(new SemiSparseMutableIntSetFactory(), new MutableSharedBitVectorIntSetFactory()); + } + +} diff --git a/com.ibm.wala.core.tests/src/com/ibm/wala/core/tests/callGraph/PiNodeCallGraphTest.java b/com.ibm.wala.core.tests/src/com/ibm/wala/core/tests/callGraph/PiNodeCallGraphTest.java index aea1eb3c0..a42408a96 100644 --- a/com.ibm.wala.core.tests/src/com/ibm/wala/core/tests/callGraph/PiNodeCallGraphTest.java +++ b/com.ibm.wala.core.tests/src/com/ibm/wala/core/tests/callGraph/PiNodeCallGraphTest.java @@ -1,115 +1,115 @@ -/******************************************************************************* - * 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 com.ibm.wala.core.tests.callGraph; - -import java.io.IOException; -import java.util.Iterator; -import java.util.Set; - -import org.junit.Test; - -import com.ibm.wala.classLoader.CallSiteReference; -import com.ibm.wala.core.tests.util.TestConstants; -import com.ibm.wala.core.tests.util.WalaTestCase; -import com.ibm.wala.ipa.callgraph.AnalysisCache; -import com.ibm.wala.ipa.callgraph.AnalysisOptions; -import com.ibm.wala.ipa.callgraph.AnalysisScope; -import com.ibm.wala.ipa.callgraph.CGNode; -import com.ibm.wala.ipa.callgraph.CallGraph; -import com.ibm.wala.ipa.callgraph.Entrypoint; -import com.ibm.wala.ipa.cha.ClassHierarchy; -import com.ibm.wala.ipa.cha.ClassHierarchyException; -import com.ibm.wala.ssa.SSAOptions; -import com.ibm.wala.ssa.SSAPiNodePolicy; -import com.ibm.wala.types.ClassLoaderReference; -import com.ibm.wala.types.Descriptor; -import com.ibm.wala.types.MemberReference; -import com.ibm.wala.types.MethodReference; -import com.ibm.wala.types.TypeName; -import com.ibm.wala.types.TypeReference; -import com.ibm.wala.util.CancelException; -import com.ibm.wala.util.collections.HashSetFactory; -import com.ibm.wala.util.strings.Atom; - -/** - */ -public class PiNodeCallGraphTest extends WalaTestCase { - - - public static void main(String[] args) { - justThisTest(PiNodeCallGraphTest.class); - } - - private static final String whateverName = TestConstants.PI_TEST_MAIN + "$Whatever"; - - private static final String thisName = TestConstants.PI_TEST_MAIN + "$This"; - - private static final String thatName = TestConstants.PI_TEST_MAIN + "$That"; - - private static final ClassLoaderReference loader = ClassLoaderReference.Application; - - private static final TypeReference whateverRef = TypeReference.findOrCreate(loader, TypeName.string2TypeName(whateverName)); - - private static final TypeReference thisRef = TypeReference.findOrCreate(loader, TypeName.string2TypeName(thisName)); - - private static final TypeReference thatRef = TypeReference.findOrCreate(loader, TypeName.string2TypeName(thatName)); - - private static final MethodReference thisBinaryRef = MethodReference.findOrCreate(thisRef, - Atom.findOrCreateUnicodeAtom("binary"), Descriptor.findOrCreateUTF8("(" + whateverName + ";)V")); - - private static final MethodReference thatBinaryRef = MethodReference.findOrCreate(thatRef, - Atom.findOrCreateUnicodeAtom("binary"), Descriptor.findOrCreateUTF8("(" + whateverName + ";)V")); - - private static final MemberReference unary2Ref = MethodReference.findOrCreate(whateverRef, - Atom.findOrCreateUnicodeAtom("unary2"), Descriptor.findOrCreateUTF8("()V")); - - private CallGraph doGraph(boolean usePiNodes) throws ClassHierarchyException, IllegalArgumentException, CancelException, IOException { - AnalysisScope scope = CallGraphTestUtil.makeJ2SEAnalysisScope(TestConstants.WALA_TESTDATA, CallGraphTestUtil.REGRESSION_EXCLUSIONS); - ClassHierarchy cha = ClassHierarchy.make(scope); - Iterable entrypoints = com.ibm.wala.ipa.callgraph.impl.Util.makeMainEntrypoints(scope, cha, - TestConstants.PI_TEST_MAIN); - AnalysisOptions options = CallGraphTestUtil.makeAnalysisOptions(scope, entrypoints); - SSAPiNodePolicy policy = usePiNodes ? SSAOptions.getAllBuiltInPiNodes() : null; - options.getSSAOptions().setPiNodePolicy(policy); - - return CallGraphTestUtil.buildZeroCFA(options, new AnalysisCache(), cha, scope, false); - } - - private void checkCallAssertions(CallGraph cg, int desiredNumberOfTargets, int desiredNumberOfCalls) { - - int numberOfCalls = 0; - Set callerNodes = HashSetFactory.make(); - callerNodes.addAll(cg.getNodes(thisBinaryRef)); - callerNodes.addAll(cg.getNodes(thatBinaryRef)); - assert callerNodes.size() == 2; - - for (CGNode n : callerNodes) { - for (Iterator sites = n.iterateCallSites(); sites.hasNext();) { - CallSiteReference csRef = (CallSiteReference) sites.next(); - if (csRef.getDeclaredTarget().equals(unary2Ref)) { - numberOfCalls++; - assert cg.getNumberOfTargets(n, csRef) == desiredNumberOfTargets; - } - } - } - - assert numberOfCalls == desiredNumberOfCalls; - } - - @Test public void testNoPiNodes() throws ClassHierarchyException, IllegalArgumentException, CancelException, IOException { - checkCallAssertions(doGraph(false), 2, 2); - } - - @Test public void testPiNodes() throws ClassHierarchyException, IllegalArgumentException, CancelException, IOException { - checkCallAssertions(doGraph(true), 1, 2); - } - +/******************************************************************************* + * 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 com.ibm.wala.core.tests.callGraph; + +import java.io.IOException; +import java.util.Iterator; +import java.util.Set; + +import org.junit.Test; + +import com.ibm.wala.classLoader.CallSiteReference; +import com.ibm.wala.core.tests.util.TestConstants; +import com.ibm.wala.core.tests.util.WalaTestCase; +import com.ibm.wala.ipa.callgraph.AnalysisCache; +import com.ibm.wala.ipa.callgraph.AnalysisOptions; +import com.ibm.wala.ipa.callgraph.AnalysisScope; +import com.ibm.wala.ipa.callgraph.CGNode; +import com.ibm.wala.ipa.callgraph.CallGraph; +import com.ibm.wala.ipa.callgraph.Entrypoint; +import com.ibm.wala.ipa.cha.ClassHierarchy; +import com.ibm.wala.ipa.cha.ClassHierarchyException; +import com.ibm.wala.ssa.SSAOptions; +import com.ibm.wala.ssa.SSAPiNodePolicy; +import com.ibm.wala.types.ClassLoaderReference; +import com.ibm.wala.types.Descriptor; +import com.ibm.wala.types.MemberReference; +import com.ibm.wala.types.MethodReference; +import com.ibm.wala.types.TypeName; +import com.ibm.wala.types.TypeReference; +import com.ibm.wala.util.CancelException; +import com.ibm.wala.util.collections.HashSetFactory; +import com.ibm.wala.util.strings.Atom; + +/** + */ +public class PiNodeCallGraphTest extends WalaTestCase { + + + public static void main(String[] args) { + justThisTest(PiNodeCallGraphTest.class); + } + + private static final String whateverName = TestConstants.PI_TEST_MAIN + "$Whatever"; + + private static final String thisName = TestConstants.PI_TEST_MAIN + "$This"; + + private static final String thatName = TestConstants.PI_TEST_MAIN + "$That"; + + private static final ClassLoaderReference loader = ClassLoaderReference.Application; + + private static final TypeReference whateverRef = TypeReference.findOrCreate(loader, TypeName.string2TypeName(whateverName)); + + private static final TypeReference thisRef = TypeReference.findOrCreate(loader, TypeName.string2TypeName(thisName)); + + private static final TypeReference thatRef = TypeReference.findOrCreate(loader, TypeName.string2TypeName(thatName)); + + private static final MethodReference thisBinaryRef = MethodReference.findOrCreate(thisRef, + Atom.findOrCreateUnicodeAtom("binary"), Descriptor.findOrCreateUTF8("(" + whateverName + ";)V")); + + private static final MethodReference thatBinaryRef = MethodReference.findOrCreate(thatRef, + Atom.findOrCreateUnicodeAtom("binary"), Descriptor.findOrCreateUTF8("(" + whateverName + ";)V")); + + private static final MemberReference unary2Ref = MethodReference.findOrCreate(whateverRef, + Atom.findOrCreateUnicodeAtom("unary2"), Descriptor.findOrCreateUTF8("()V")); + + private CallGraph doGraph(boolean usePiNodes) throws ClassHierarchyException, IllegalArgumentException, CancelException, IOException { + AnalysisScope scope = CallGraphTestUtil.makeJ2SEAnalysisScope(TestConstants.WALA_TESTDATA, CallGraphTestUtil.REGRESSION_EXCLUSIONS); + ClassHierarchy cha = ClassHierarchy.make(scope); + Iterable entrypoints = com.ibm.wala.ipa.callgraph.impl.Util.makeMainEntrypoints(scope, cha, + TestConstants.PI_TEST_MAIN); + AnalysisOptions options = CallGraphTestUtil.makeAnalysisOptions(scope, entrypoints); + SSAPiNodePolicy policy = usePiNodes ? SSAOptions.getAllBuiltInPiNodes() : null; + options.getSSAOptions().setPiNodePolicy(policy); + + return CallGraphTestUtil.buildZeroCFA(options, new AnalysisCache(), cha, scope, false); + } + + private void checkCallAssertions(CallGraph cg, int desiredNumberOfTargets, int desiredNumberOfCalls) { + + int numberOfCalls = 0; + Set callerNodes = HashSetFactory.make(); + callerNodes.addAll(cg.getNodes(thisBinaryRef)); + callerNodes.addAll(cg.getNodes(thatBinaryRef)); + assert callerNodes.size() == 2; + + for (CGNode n : callerNodes) { + for (Iterator sites = n.iterateCallSites(); sites.hasNext();) { + CallSiteReference csRef = (CallSiteReference) sites.next(); + if (csRef.getDeclaredTarget().equals(unary2Ref)) { + numberOfCalls++; + assert cg.getNumberOfTargets(n, csRef) == desiredNumberOfTargets; + } + } + } + + assert numberOfCalls == desiredNumberOfCalls; + } + + @Test public void testNoPiNodes() throws ClassHierarchyException, IllegalArgumentException, CancelException, IOException { + checkCallAssertions(doGraph(false), 2, 2); + } + + @Test public void testPiNodes() throws ClassHierarchyException, IllegalArgumentException, CancelException, IOException { + checkCallAssertions(doGraph(true), 1, 2); + } + } \ No newline at end of file diff --git a/com.ibm.wala.core.tests/src/com/ibm/wala/core/tests/callGraph/ReflectionTest.java b/com.ibm.wala.core.tests/src/com/ibm/wala/core/tests/callGraph/ReflectionTest.java index fda266b6d..fe24f9323 100644 --- a/com.ibm.wala.core.tests/src/com/ibm/wala/core/tests/callGraph/ReflectionTest.java +++ b/com.ibm.wala.core.tests/src/com/ibm/wala/core/tests/callGraph/ReflectionTest.java @@ -1,641 +1,641 @@ -/******************************************************************************* - * 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 com.ibm.wala.core.tests.callGraph; - -import java.io.IOException; -import java.util.Collection; -import java.util.Iterator; -import java.util.Set; - -import org.junit.AfterClass; -import org.junit.Assert; -import org.junit.Test; - -import com.ibm.wala.classLoader.IClass; -import com.ibm.wala.classLoader.IMethod; -import com.ibm.wala.core.tests.util.TestConstants; -import com.ibm.wala.core.tests.util.WalaTestCase; -import com.ibm.wala.ipa.callgraph.AnalysisCache; -import com.ibm.wala.ipa.callgraph.AnalysisOptions; -import com.ibm.wala.ipa.callgraph.AnalysisScope; -import com.ibm.wala.ipa.callgraph.CGNode; -import com.ibm.wala.ipa.callgraph.CallGraph; -import com.ibm.wala.ipa.callgraph.Context; -import com.ibm.wala.ipa.callgraph.Entrypoint; -import com.ibm.wala.ipa.callgraph.impl.Everywhere; -import com.ibm.wala.ipa.callgraph.propagation.ConstantKey; -import com.ibm.wala.ipa.callgraph.propagation.ReceiverInstanceContext; -import com.ibm.wala.ipa.cha.ClassHierarchy; -import com.ibm.wala.ipa.cha.ClassHierarchyException; -import com.ibm.wala.ipa.cha.IClassHierarchy; -import com.ibm.wala.types.ClassLoaderReference; -import com.ibm.wala.types.MethodReference; -import com.ibm.wala.types.TypeReference; -import com.ibm.wala.util.CancelException; -import com.ibm.wala.util.WalaException; -import com.ibm.wala.util.collections.HashSetFactory; -import com.ibm.wala.util.warnings.Warning; -import com.ibm.wala.util.warnings.Warnings; - -/** - * Tests for Call Graph construction - */ - -public class ReflectionTest extends WalaTestCase { - - public static void main(String[] args) { - justThisTest(ReflectionTest.class); - } - - private static AnalysisScope cachedScope; - - private static AnalysisScope findOrCreateAnalysisScope() throws IOException { - if (cachedScope == null) { - cachedScope = CallGraphTestUtil.makeJ2SEAnalysisScope(TestConstants.WALA_TESTDATA, "Java60RegressionExclusions.txt"); - } - return cachedScope; - } - - private static IClassHierarchy cachedCHA; - - private static IClassHierarchy findOrCreateCHA(AnalysisScope scope) throws ClassHierarchyException { - if (cachedCHA == null) { - cachedCHA = ClassHierarchy.make(scope); - } - return cachedCHA; - } - - @AfterClass - public static void afterClass() { - cachedCHA = null; - cachedScope = null; - } - - /** - * test that when analyzing Reflect1.main(), there is no warning about - * "Integer". - */ - @Test - public void testReflect1() throws WalaException, IllegalArgumentException, CancelException, IOException { - AnalysisScope scope = findOrCreateAnalysisScope(); - IClassHierarchy cha = findOrCreateCHA(scope); - Iterable entrypoints = com.ibm.wala.ipa.callgraph.impl.Util.makeMainEntrypoints(scope, cha, - TestConstants.REFLECT1_MAIN); - AnalysisOptions options = CallGraphTestUtil.makeAnalysisOptions(scope, entrypoints); - - Warnings.clear(); - CallGraphTest.doCallGraphs(options, new AnalysisCache(), cha, scope); - for (Iterator it = Warnings.iterator(); it.hasNext();) { - Warning w = (Warning) it.next(); - if (w.toString().indexOf("com/ibm/jvm") > 0) { - continue; - } - if (w.toString().indexOf("Integer") >= 0) { - Assert.assertTrue(w.toString(), false); - } - } - } - - /** - * Test that when analyzing reflect2, the call graph includes a node for - * java.lang.Integer.. This should be forced by the call for - * Class.forName("java.lang.Integer"). - */ - @Test - public void testReflect2() throws WalaException, IllegalArgumentException, CancelException, IOException { - AnalysisScope scope = findOrCreateAnalysisScope(); - IClassHierarchy cha = findOrCreateCHA(scope); - Iterable entrypoints = com.ibm.wala.ipa.callgraph.impl.Util.makeMainEntrypoints(scope, cha, - TestConstants.REFLECT2_MAIN); - AnalysisOptions options = CallGraphTestUtil.makeAnalysisOptions(scope, entrypoints); - CallGraph cg = CallGraphTestUtil.buildZeroOneCFA(options, new AnalysisCache(), cha, scope, false); - - TypeReference tr = TypeReference.findOrCreate(ClassLoaderReference.Application, "Ljava/lang/Integer"); - MethodReference mr = MethodReference.findOrCreate(tr, "", "()V"); - Set nodes = cg.getNodes(mr); - Assert.assertFalse(nodes.isEmpty()); - } - - /** - * Check that when analyzing Reflect3, the successors of newInstance do not - * include reflection/Reflect3$Hash - */ - @Test - public void testReflect3() throws IOException, ClassHierarchyException, IllegalArgumentException, CancelException { - AnalysisScope scope = findOrCreateAnalysisScope(); - IClassHierarchy cha = findOrCreateCHA(scope); - Iterable entrypoints = com.ibm.wala.ipa.callgraph.impl.Util.makeMainEntrypoints(scope, cha, - TestConstants.REFLECT3_MAIN); - AnalysisOptions options = CallGraphTestUtil.makeAnalysisOptions(scope, entrypoints); - CallGraph cg = CallGraphTestUtil.buildZeroOneCFA(options, new AnalysisCache(), cha, scope, false); - - TypeReference tr = TypeReference.findOrCreate(ClassLoaderReference.Application, "Ljava/lang/Class"); - MethodReference mr = MethodReference.findOrCreate(tr, "newInstance", "()Ljava/lang/Object;"); - Set newInstanceNodes = cg.getNodes(mr); - Set succNodes = HashSetFactory.make(); - for (CGNode newInstanceNode : newInstanceNodes) { - Iterator succNodesIter = cg.getSuccNodes(newInstanceNode); - while (succNodesIter.hasNext()) { - succNodes.add(succNodesIter.next()); - } - } - TypeReference extraneousTR = TypeReference.findOrCreate(ClassLoaderReference.Application, "Lreflection/Reflect3$Hash"); - IClass hashClass = cha.lookupClass(extraneousTR); - assert hashClass != null; - MethodReference extraneousMR = MethodReference.findOrCreate(extraneousTR, "", "()V"); - Set extraneousNodes = cg.getNodes(extraneousMR); - succNodes.retainAll(extraneousNodes); - Assert.assertTrue(succNodes.isEmpty()); - } - - /** - * Check that when analyzing Reflect4, successors of newInstance() do not - * include FilePermission ctor. - */ - @Test - public void testReflect4() throws IOException, ClassHierarchyException, IllegalArgumentException, CancelException { - AnalysisScope scope = findOrCreateAnalysisScope(); - IClassHierarchy cha = findOrCreateCHA(scope); - Iterable entrypoints = com.ibm.wala.ipa.callgraph.impl.Util.makeMainEntrypoints(scope, cha, - TestConstants.REFLECT4_MAIN); - AnalysisOptions options = CallGraphTestUtil.makeAnalysisOptions(scope, entrypoints); - CallGraph cg = CallGraphTestUtil.buildZeroOneCFA(options, new AnalysisCache(), cha, scope, false); - - TypeReference tr = TypeReference.findOrCreate(ClassLoaderReference.Application, "Ljava/lang/Class"); - MethodReference mr = MethodReference.findOrCreate(tr, "newInstance", "()Ljava/lang/Object;"); - Set newInstanceNodes = cg.getNodes(mr); - Set succNodes = HashSetFactory.make(); - for (CGNode newInstanceNode : newInstanceNodes) { - Iterator succNodesIter = cg.getSuccNodes(newInstanceNode); - while (succNodesIter.hasNext()) { - succNodes.add(succNodesIter.next()); - } - } - TypeReference extraneousTR = TypeReference.findOrCreate(ClassLoaderReference.Application, "Ljava/io/FilePermission"); - MethodReference extraneousMR = MethodReference.findOrCreate(extraneousTR, "", "(Ljava/lang/String;Ljava/lang/String;)V"); - Set extraneousNodes = cg.getNodes(extraneousMR); - succNodes.retainAll(extraneousNodes); - Assert.assertTrue(succNodes.isEmpty()); - } - - /** - * Check that when analyzing Reflect5, successors of newInstance do not - * include a Reflect5$A ctor - */ - @Test - public void testReflect5() throws IOException, ClassHierarchyException, IllegalArgumentException, CancelException { - AnalysisScope scope = findOrCreateAnalysisScope(); - IClassHierarchy cha = findOrCreateCHA(scope); - Iterable entrypoints = com.ibm.wala.ipa.callgraph.impl.Util.makeMainEntrypoints(scope, cha, - TestConstants.REFLECT5_MAIN); - AnalysisOptions options = CallGraphTestUtil.makeAnalysisOptions(scope, entrypoints); - CallGraph cg = CallGraphTestUtil.buildZeroOneCFA(options, new AnalysisCache(), cha, scope, false); - - TypeReference tr = TypeReference.findOrCreate(ClassLoaderReference.Application, "Ljava/lang/Class"); - MethodReference mr = MethodReference.findOrCreate(tr, "newInstance", "()Ljava/lang/Object;"); - Set newInstanceNodes = cg.getNodes(mr); - Set succNodes = HashSetFactory.make(); - for (CGNode newInstanceNode : newInstanceNodes) { - Iterator succNodesIter = cg.getSuccNodes(newInstanceNode); - while (succNodesIter.hasNext()) { - succNodes.add(succNodesIter.next()); - } - } - TypeReference extraneousTR = TypeReference.findOrCreate(ClassLoaderReference.Application, "Lreflection/Reflect5$A"); - MethodReference extraneousMR = MethodReference.findOrCreate(extraneousTR, "", "()V"); - Set extraneousNodes = cg.getNodes(extraneousMR); - succNodes.retainAll(extraneousNodes); - Assert.assertTrue(succNodes.isEmpty()); - } - - /** - * Check that when analyzing Reflect6, successors of newInstance do not - * include a Reflect6$A ctor - */ - @Test - public void testReflect6() throws IOException, ClassHierarchyException, IllegalArgumentException, CancelException { - AnalysisScope scope = findOrCreateAnalysisScope(); - IClassHierarchy cha = findOrCreateCHA(scope); - Iterable entrypoints = com.ibm.wala.ipa.callgraph.impl.Util.makeMainEntrypoints(scope, cha, - TestConstants.REFLECT6_MAIN); - AnalysisOptions options = CallGraphTestUtil.makeAnalysisOptions(scope, entrypoints); - CallGraph cg = CallGraphTestUtil.buildZeroOneCFA(options, new AnalysisCache(), cha, scope, false); - - TypeReference tr = TypeReference.findOrCreate(ClassLoaderReference.Application, "Ljava/lang/Class"); - MethodReference mr = MethodReference.findOrCreate(tr, "newInstance", "()Ljava/lang/Object;"); - Set newInstanceNodes = cg.getNodes(mr); - Set succNodes = HashSetFactory.make(); - for (CGNode newInstanceNode : newInstanceNodes) { - Iterator succNodesIter = cg.getSuccNodes(newInstanceNode); - while (succNodesIter.hasNext()) { - succNodes.add(succNodesIter.next()); - } - } - TypeReference extraneousTR = TypeReference.findOrCreate(ClassLoaderReference.Application, "Lreflection/Reflect6$A"); - MethodReference extraneousMR = MethodReference.findOrCreate(extraneousTR, "", "(I)V"); - Set extraneousNodes = cg.getNodes(extraneousMR); - succNodes.retainAll(extraneousNodes); - Assert.assertTrue(succNodes.isEmpty()); - } - - @SuppressWarnings("unchecked") - @Test - public void testReflect7() throws Exception { - AnalysisScope scope = findOrCreateAnalysisScope(); - IClassHierarchy cha = findOrCreateCHA(scope); - Iterable entrypoints = com.ibm.wala.ipa.callgraph.impl.Util.makeMainEntrypoints(scope, cha, - TestConstants.REFLECT7_MAIN); - AnalysisOptions options = CallGraphTestUtil.makeAnalysisOptions(scope, entrypoints); - CallGraph cg = CallGraphTestUtil.buildZeroOneCFA(options, new AnalysisCache(), cha, scope, false); - - final String mainClass = "Lreflection/Reflect7"; - TypeReference mainTr = TypeReference.findOrCreate(ClassLoaderReference.Application, mainClass); - MethodReference mainMr = MethodReference.findOrCreate(mainTr, "main", "([Ljava/lang/String;)V"); - - TypeReference constrTr = TypeReference.findOrCreate(ClassLoaderReference.Primordial, "Ljava/lang/reflect/Constructor"); - MethodReference newInstanceMr = MethodReference - .findOrCreate(constrTr, "newInstance", "([Ljava/lang/Object;)Ljava/lang/Object;"); - - String fpInitSig = "java.io.FilePermission.(Ljava/lang/String;Ljava/lang/String;)V"; - String fpToStringSig = "java.security.Permission.toString()Ljava/lang/String;"; - - Set mainNodes = cg.getNodes(mainMr); - - // Get all the children of the main node(s) - Collection mainChildren = getSuccNodes(cg, mainNodes); - - // Verify that one of those children is Constructor.newInstance, where - // Constructor is a FilePermission constructor - CGNode filePermConstrNewInstanceNode = null; - - for (CGNode node : mainChildren) { - Context context = node.getContext(); - if (context instanceof ReceiverInstanceContext && node.getMethod().getReference().equals(newInstanceMr)) { - ReceiverInstanceContext r = (ReceiverInstanceContext) context; - ConstantKey c = (ConstantKey) r.getReceiver(); - IMethod ctor = (IMethod) c.getValue(); - if (ctor.getSignature().equals(fpInitSig)) { - filePermConstrNewInstanceNode = node; - break; - } - } - } - Assert.assertTrue(filePermConstrNewInstanceNode != null); - - // Now verify that this node has FilePermission. children - CGNode filePermInitNode = null; - - Iterator filePermConstrNewInstanceChildren = cg.getSuccNodes(filePermConstrNewInstanceNode); - while (filePermConstrNewInstanceChildren.hasNext()) { - CGNode node = filePermConstrNewInstanceChildren.next(); - if (node.getMethod().getSignature().equals(fpInitSig)) { - filePermInitNode = node; - break; - } - } - Assert.assertTrue(filePermInitNode != null); - - // Furthermore, verify that main has a FilePermission.toString child - CGNode filePermToStringNode = null; - for (CGNode node : mainChildren) { - if (node.getMethod().getSignature().equals(fpToStringSig)) { - filePermToStringNode = node; - break; - } - } - - Assert.assertTrue(filePermToStringNode != null); - } - - private Collection getSuccNodes(CallGraph cg, Collection nodes) { - Set succNodes = HashSetFactory.make(); - for (CGNode newInstanceNode : nodes) { - Iterator succNodesIter = cg.getSuccNodes(newInstanceNode); - while (succNodesIter.hasNext()) { - succNodes.add(succNodesIter.next()); - } - } - return succNodes; - } - - /** - * Test that when analyzing reflect8, the call graph includes a node for - * java.lang.Integer.toString() - */ - @Test - public void testReflect8() throws WalaException, IllegalArgumentException, CancelException, IOException { - AnalysisScope scope = findOrCreateAnalysisScope(); - IClassHierarchy cha = findOrCreateCHA(scope); - Iterable entrypoints = com.ibm.wala.ipa.callgraph.impl.Util.makeMainEntrypoints(scope, cha, - TestConstants.REFLECT8_MAIN); - AnalysisOptions options = CallGraphTestUtil.makeAnalysisOptions(scope, entrypoints); - CallGraph cg = CallGraphTestUtil.buildZeroOneCFA(options, new AnalysisCache(), cha, scope, false); - TypeReference tr = TypeReference.findOrCreate(ClassLoaderReference.Primordial, "Ljava/lang/Integer"); - MethodReference mr = MethodReference.findOrCreate(tr, "toString", "()Ljava/lang/String;"); - Set nodes = cg.getNodes(mr); - Assert.assertFalse(nodes.isEmpty()); - } - - /** - * Test that when analyzing reflect9, the call graph includes a node for - * java.lang.Integer.toString() - */ - @Test - public void testReflect9() throws WalaException, IllegalArgumentException, CancelException, IOException { - AnalysisScope scope = findOrCreateAnalysisScope(); - IClassHierarchy cha = findOrCreateCHA(scope); - Iterable entrypoints = com.ibm.wala.ipa.callgraph.impl.Util.makeMainEntrypoints(scope, cha, - TestConstants.REFLECT9_MAIN); - AnalysisOptions options = CallGraphTestUtil.makeAnalysisOptions(scope, entrypoints); - CallGraph cg = CallGraphTestUtil.buildZeroOneCFA(options, new AnalysisCache(), cha, scope, false); - TypeReference tr = TypeReference.findOrCreate(ClassLoaderReference.Primordial, "Ljava/lang/Integer"); - MethodReference mr = MethodReference.findOrCreate(tr, "toString", "()Ljava/lang/String;"); - Set nodes = cg.getNodes(mr); - Assert.assertFalse(nodes.isEmpty()); - } - - /** - * Test that when analyzing Reflect10, the call graph includes a node for - * java.lang.Integer.toString() - */ - @Test - public void testReflect10() throws WalaException, IllegalArgumentException, CancelException, IOException { - AnalysisScope scope = findOrCreateAnalysisScope(); - IClassHierarchy cha = findOrCreateCHA(scope); - Iterable entrypoints = com.ibm.wala.ipa.callgraph.impl.Util.makeMainEntrypoints(scope, cha, - TestConstants.REFLECT10_MAIN); - AnalysisOptions options = CallGraphTestUtil.makeAnalysisOptions(scope, entrypoints); - CallGraph cg = CallGraphTestUtil.buildZeroOneCFA(options, new AnalysisCache(), cha, scope, false); - TypeReference tr = TypeReference.findOrCreate(ClassLoaderReference.Primordial, "Ljava/lang/Integer"); - MethodReference mr = MethodReference.findOrCreate(tr, "toString", "()Ljava/lang/String;"); - Set nodes = cg.getNodes(mr); - Assert.assertFalse(nodes.isEmpty()); - } - - /** - * Test that when analyzing Reflect11, the call graph includes a node for - * java.lang.Object.wait() - */ - @Test - public void testReflect11() throws WalaException, IllegalArgumentException, CancelException, IOException { - AnalysisScope scope = findOrCreateAnalysisScope(); - IClassHierarchy cha = findOrCreateCHA(scope); - Iterable entrypoints = com.ibm.wala.ipa.callgraph.impl.Util.makeMainEntrypoints(scope, cha, - TestConstants.REFLECT11_MAIN); - AnalysisOptions options = CallGraphTestUtil.makeAnalysisOptions(scope, entrypoints); - CallGraph cg = CallGraphTestUtil.buildZeroOneCFA(options, new AnalysisCache(), cha, scope, false); - TypeReference tr = TypeReference.findOrCreate(ClassLoaderReference.Primordial, "Ljava/lang/Object"); - MethodReference mr = MethodReference.findOrCreate(tr, "wait", "()V"); - Set nodes = cg.getNodes(mr); - Assert.assertFalse(nodes.isEmpty()); - } - - /** - * Test that when analyzing Reflect12, the call graph does not include a node - * for reflection.Helper.n but does include a node for reflection.Helper.m - */ - @Test - public void testReflect12() throws WalaException, IllegalArgumentException, CancelException, IOException { - AnalysisScope scope = findOrCreateAnalysisScope(); - IClassHierarchy cha = findOrCreateCHA(scope); - Iterable entrypoints = com.ibm.wala.ipa.callgraph.impl.Util.makeMainEntrypoints(scope, cha, - TestConstants.REFLECT12_MAIN); - AnalysisOptions options = CallGraphTestUtil.makeAnalysisOptions(scope, entrypoints); - CallGraph cg = CallGraphTestUtil.buildZeroOneCFA(options, new AnalysisCache(), cha, scope, false); - TypeReference tr = TypeReference.findOrCreate(ClassLoaderReference.Application, "Lreflection/Helper"); - MethodReference mr = MethodReference.findOrCreate(tr, "m", "(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)V"); - Set nodes = cg.getNodes(mr); - Assert.assertFalse(nodes.isEmpty()); - mr = MethodReference.findOrCreate(tr, "n", "(Ljava/lang/Object;Ljava/lang/Object;)V"); - nodes = cg.getNodes(mr); - Assert.assertTrue(nodes.isEmpty()); - } - - /** - * Test that when analyzing Reflect13, the call graph includes both a node for - * reflection.Helper.n and a node for reflection.Helper.m - */ - @Test - public void testReflect13() throws WalaException, IllegalArgumentException, CancelException, IOException { - AnalysisScope scope = findOrCreateAnalysisScope(); - IClassHierarchy cha = findOrCreateCHA(scope); - Iterable entrypoints = com.ibm.wala.ipa.callgraph.impl.Util.makeMainEntrypoints(scope, cha, - TestConstants.REFLECT13_MAIN); - AnalysisOptions options = CallGraphTestUtil.makeAnalysisOptions(scope, entrypoints); - CallGraph cg = CallGraphTestUtil.buildZeroOneCFA(options, new AnalysisCache(), cha, scope, false); - TypeReference tr = TypeReference.findOrCreate(ClassLoaderReference.Application, "Lreflection/Helper"); - MethodReference mr = MethodReference.findOrCreate(tr, "m", "(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)V"); - Set nodes = cg.getNodes(mr); - Assert.assertFalse(nodes.isEmpty()); - mr = MethodReference.findOrCreate(tr, "n", "(Ljava/lang/Object;Ljava/lang/Object;)V"); - nodes = cg.getNodes(mr); - Assert.assertFalse(nodes.isEmpty()); - } - - /** - * Test that when analyzing Reflect14, the call graph does not include a node - * for reflection.Helper.n but does include a node for reflection.Helper.s - */ - @Test - public void testReflect14() throws WalaException, IllegalArgumentException, CancelException, IOException { - AnalysisScope scope = findOrCreateAnalysisScope(); - IClassHierarchy cha = findOrCreateCHA(scope); - Iterable entrypoints = com.ibm.wala.ipa.callgraph.impl.Util.makeMainEntrypoints(scope, cha, - TestConstants.REFLECT14_MAIN); - AnalysisOptions options = CallGraphTestUtil.makeAnalysisOptions(scope, entrypoints); - CallGraph cg = CallGraphTestUtil.buildZeroOneCFA(options, new AnalysisCache(), cha, scope, false); - TypeReference tr = TypeReference.findOrCreate(ClassLoaderReference.Application, "Lreflection/Helper"); - MethodReference mr = MethodReference.findOrCreate(tr, "s", "(Ljava/lang/Object;Ljava/lang/Object;)V"); - Set nodes = cg.getNodes(mr); - Assert.assertFalse(nodes.isEmpty()); - mr = MethodReference.findOrCreate(tr, "n", "(Ljava/lang/Object;Ljava/lang/Object;)V"); - nodes = cg.getNodes(mr); - Assert.assertTrue(nodes.isEmpty()); - } - - /** - * Test that when analyzing Reflect15, the call graph includes a node for the - * constructor of Helper that takes 2 parameters and for Helper.n, but no node - * for the constructors of Helper that takes 0 or 1 parameters. - */ - @Test - public void testReflect15() throws WalaException, IllegalArgumentException, CancelException, IOException { - AnalysisScope scope = findOrCreateAnalysisScope(); - IClassHierarchy cha = findOrCreateCHA(scope); - Iterable entrypoints = com.ibm.wala.ipa.callgraph.impl.Util.makeMainEntrypoints(scope, cha, - TestConstants.REFLECT15_MAIN); - AnalysisOptions options = CallGraphTestUtil.makeAnalysisOptions(scope, entrypoints); - CallGraph cg = CallGraphTestUtil.buildZeroOneCFA(options, new AnalysisCache(), cha, scope, false); - TypeReference tr = TypeReference.findOrCreate(ClassLoaderReference.Application, "Lreflection/Helper"); - MethodReference mr = MethodReference.findOrCreate(tr, "", "(Ljava/lang/Object;Ljava/lang/Object;)V"); - Set nodes = cg.getNodes(mr); - Assert.assertFalse(nodes.isEmpty()); - mr = MethodReference.findOrCreate(tr, "", "(Ljava/lang/Object;)V"); - nodes = cg.getNodes(mr); - Assert.assertTrue(nodes.isEmpty()); - mr = MethodReference.findOrCreate(tr, "", "()V"); - nodes = cg.getNodes(mr); - Assert.assertTrue(nodes.isEmpty()); - mr = MethodReference.findOrCreate(tr, "n", "(Ljava/lang/Object;Ljava/lang/Object;)V"); - nodes = cg.getNodes(mr); - Assert.assertFalse(nodes.isEmpty()); - } - - /** - * Test that when analyzing Reflect16, the call graph includes a node for - * java.lang.Integer.toString() - */ - @Test - public void testReflect16() throws WalaException, IllegalArgumentException, CancelException, IOException { - AnalysisScope scope = findOrCreateAnalysisScope(); - IClassHierarchy cha = findOrCreateCHA(scope); - Iterable entrypoints = com.ibm.wala.ipa.callgraph.impl.Util.makeMainEntrypoints(scope, cha, - TestConstants.REFLECT16_MAIN); - AnalysisOptions options = CallGraphTestUtil.makeAnalysisOptions(scope, entrypoints); - CallGraph cg = CallGraphTestUtil.buildZeroOneCFA(options, new AnalysisCache(), cha, scope, false); - TypeReference tr = TypeReference.findOrCreate(ClassLoaderReference.Primordial, "Ljava/lang/Integer"); - MethodReference mr = MethodReference.findOrCreate(tr, "toString", "()Ljava/lang/String;"); - Set nodes = cg.getNodes(mr); - Assert.assertFalse(nodes.isEmpty()); - } - - /** - * Test that when analyzing Reflect17, the call graph does not include any - * edges from reflection.Helper.t() - */ - @Test - public void testReflect17() throws WalaException, IllegalArgumentException, CancelException, IOException { - AnalysisScope scope = findOrCreateAnalysisScope(); - IClassHierarchy cha = findOrCreateCHA(scope); - Iterable entrypoints = com.ibm.wala.ipa.callgraph.impl.Util.makeMainEntrypoints(scope, cha, - TestConstants.REFLECT17_MAIN); - AnalysisOptions options = CallGraphTestUtil.makeAnalysisOptions(scope, entrypoints); - CallGraph cg = CallGraphTestUtil.buildZeroOneCFA(options, new AnalysisCache(), cha, scope, false); - TypeReference tr = TypeReference.findOrCreate(ClassLoaderReference.Application, "Lreflection/Helper"); - MethodReference mr = MethodReference.findOrCreate(tr, "t", "(Ljava/lang/Integer;)V"); - CGNode node = cg.getNode(cg.getClassHierarchy().resolveMethod(mr), Everywhere.EVERYWHERE); - Assert.assertEquals(0, cg.getSuccNodeCount(node)); - } - - /** - * Test that when analyzing Reflect18, the call graph includes a node for - * java.lang.Integer.toString() - */ - @Test - public void testReflect18() throws WalaException, IllegalArgumentException, CancelException, IOException { - AnalysisScope scope = findOrCreateAnalysisScope(); - IClassHierarchy cha = findOrCreateCHA(scope); - Iterable entrypoints = com.ibm.wala.ipa.callgraph.impl.Util.makeMainEntrypoints(scope, cha, - TestConstants.REFLECT18_MAIN); - AnalysisOptions options = CallGraphTestUtil.makeAnalysisOptions(scope, entrypoints); - CallGraph cg = CallGraphTestUtil.buildZeroOneCFA(options, new AnalysisCache(), cha, scope, false); - TypeReference tr = TypeReference.findOrCreate(ClassLoaderReference.Application, "Lreflection/Helper"); - MethodReference mr = MethodReference.findOrCreate(tr, "t", "(Ljava/lang/Integer;)V"); - CGNode node = cg.getNode(cg.getClassHierarchy().resolveMethod(mr), Everywhere.EVERYWHERE); - Assert.assertEquals(1, cg.getSuccNodeCount(node)); - CGNode succ = cg.getSuccNodes(node).next(); - Assert.assertEquals("Node: < Primordial, Ljava/lang/Integer, toString()Ljava/lang/String; > Context: Everywhere", - succ.toString()); - } - - /** - * Test that when analyzing Reflect19, the call graph includes a node for - * java.lang.Integer.toString() - */ - @Test - public void testReflect19() throws WalaException, IllegalArgumentException, CancelException, IOException { - AnalysisScope scope = findOrCreateAnalysisScope(); - IClassHierarchy cha = findOrCreateCHA(scope); - Iterable entrypoints = com.ibm.wala.ipa.callgraph.impl.Util.makeMainEntrypoints(scope, cha, - TestConstants.REFLECT19_MAIN); - AnalysisOptions options = CallGraphTestUtil.makeAnalysisOptions(scope, entrypoints); - CallGraph cg = CallGraphTestUtil.buildZeroOneCFA(options, new AnalysisCache(), cha, scope, false); - TypeReference tr = TypeReference.findOrCreate(ClassLoaderReference.Primordial, "Ljava/lang/Integer"); - MethodReference mr = MethodReference.findOrCreate(tr, "toString", "()Ljava/lang/String;"); - Set nodes = cg.getNodes(mr); - Assert.assertFalse(nodes.isEmpty()); - } - - /** - * Test that when analyzing Reflect20, the call graph includes a node for - * Helper.o. - */ - @Test - public void testReflect20() throws WalaException, IllegalArgumentException, CancelException, IOException { - AnalysisScope scope = findOrCreateAnalysisScope(); - IClassHierarchy cha = findOrCreateCHA(scope); - Iterable entrypoints = com.ibm.wala.ipa.callgraph.impl.Util.makeMainEntrypoints(scope, cha, - TestConstants.REFLECT20_MAIN); - AnalysisOptions options = CallGraphTestUtil.makeAnalysisOptions(scope, entrypoints); - CallGraph cg = CallGraphTestUtil.buildZeroOneCFA(options, new AnalysisCache(), cha, scope, false); - TypeReference tr = TypeReference.findOrCreate(ClassLoaderReference.Application, "Lreflection/Helper"); - MethodReference mr = MethodReference.findOrCreate(tr, "o", "(Ljava/lang/Object;Ljava/lang/Object;)V"); - Set nodes = cg.getNodes(mr); - Assert.assertFalse(nodes.isEmpty()); - } - - /** - * Test that when analyzing Reflect21, the call graph includes a node for the - * constructor of {@link Helper} that takes two {@link Object} parameters. - * This is to test the support for Class.getDeclaredConstructor. - */ - @Test - public void testReflect21() throws WalaException, IllegalArgumentException, CancelException, IOException { - AnalysisScope scope = findOrCreateAnalysisScope(); - IClassHierarchy cha = findOrCreateCHA(scope); - Iterable entrypoints = com.ibm.wala.ipa.callgraph.impl.Util.makeMainEntrypoints(scope, cha, - TestConstants.REFLECT21_MAIN); - AnalysisOptions options = CallGraphTestUtil.makeAnalysisOptions(scope, entrypoints); - CallGraph cg = CallGraphTestUtil.buildZeroOneCFA(options, new AnalysisCache(), cha, scope, false); - TypeReference tr = TypeReference.findOrCreate(ClassLoaderReference.Application, "Lreflection/Helper"); - MethodReference mr = MethodReference.findOrCreate(tr, "", "(Ljava/lang/Object;Ljava/lang/Object;)V"); - Set nodes = cg.getNodes(mr); - Assert.assertFalse(nodes.isEmpty()); - } - - /** - * Test that when analyzing Reflect22, the call graph includes a node for the - * constructor of {@link Helper} that takes one {@link Integer} parameters. - * This is to test the support for Class.getDeclaredConstructors. - */ - @Test - public void testReflect22() throws WalaException, IllegalArgumentException, CancelException, IOException { - AnalysisScope scope = findOrCreateAnalysisScope(); - IClassHierarchy cha = findOrCreateCHA(scope); - Iterable entrypoints = com.ibm.wala.ipa.callgraph.impl.Util.makeMainEntrypoints(scope, cha, - TestConstants.REFLECT22_MAIN); - AnalysisOptions options = CallGraphTestUtil.makeAnalysisOptions(scope, entrypoints); - CallGraph cg = CallGraphTestUtil.buildZeroOneCFA(options, new AnalysisCache(), cha, scope, false); - TypeReference tr = TypeReference.findOrCreate(ClassLoaderReference.Application, "Lreflection/Helper"); - MethodReference mr = MethodReference.findOrCreate(tr, "", "(Ljava/lang/Integer;)V"); - Set nodes = cg.getNodes(mr); - Assert.assertFalse(nodes.isEmpty()); - } - - /** - * Test that when analyzing Reflect22, the call graph includes a node for the - * constructor of {@link Helper} that takes one {@link Integer} parameters. - * This is to test the support for Class.getDeclaredConstructors. - */ - @Test - public void testReflect23() throws WalaException, IllegalArgumentException, CancelException, IOException { - AnalysisScope scope = findOrCreateAnalysisScope(); - IClassHierarchy cha = findOrCreateCHA(scope); - Iterable entrypoints = com.ibm.wala.ipa.callgraph.impl.Util.makeMainEntrypoints(scope, cha, - TestConstants.REFLECT23_MAIN); - AnalysisOptions options = CallGraphTestUtil.makeAnalysisOptions(scope, entrypoints); - CallGraph cg = CallGraphTestUtil.buildZeroOneCFA(options, new AnalysisCache(), cha, scope, false); - TypeReference tr = TypeReference.findOrCreate(ClassLoaderReference.Application, "Lreflection/Helper"); - MethodReference mr = MethodReference.findOrCreate(tr, "u", "(Ljava/lang/Integer;)V"); - Set nodes = cg.getNodes(mr); - Assert.assertFalse(nodes.isEmpty()); - } -} +/******************************************************************************* + * 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 com.ibm.wala.core.tests.callGraph; + +import java.io.IOException; +import java.util.Collection; +import java.util.Iterator; +import java.util.Set; + +import org.junit.AfterClass; +import org.junit.Assert; +import org.junit.Test; + +import com.ibm.wala.classLoader.IClass; +import com.ibm.wala.classLoader.IMethod; +import com.ibm.wala.core.tests.util.TestConstants; +import com.ibm.wala.core.tests.util.WalaTestCase; +import com.ibm.wala.ipa.callgraph.AnalysisCache; +import com.ibm.wala.ipa.callgraph.AnalysisOptions; +import com.ibm.wala.ipa.callgraph.AnalysisScope; +import com.ibm.wala.ipa.callgraph.CGNode; +import com.ibm.wala.ipa.callgraph.CallGraph; +import com.ibm.wala.ipa.callgraph.Context; +import com.ibm.wala.ipa.callgraph.Entrypoint; +import com.ibm.wala.ipa.callgraph.impl.Everywhere; +import com.ibm.wala.ipa.callgraph.propagation.ConstantKey; +import com.ibm.wala.ipa.callgraph.propagation.ReceiverInstanceContext; +import com.ibm.wala.ipa.cha.ClassHierarchy; +import com.ibm.wala.ipa.cha.ClassHierarchyException; +import com.ibm.wala.ipa.cha.IClassHierarchy; +import com.ibm.wala.types.ClassLoaderReference; +import com.ibm.wala.types.MethodReference; +import com.ibm.wala.types.TypeReference; +import com.ibm.wala.util.CancelException; +import com.ibm.wala.util.WalaException; +import com.ibm.wala.util.collections.HashSetFactory; +import com.ibm.wala.util.warnings.Warning; +import com.ibm.wala.util.warnings.Warnings; + +/** + * Tests for Call Graph construction + */ + +public class ReflectionTest extends WalaTestCase { + + public static void main(String[] args) { + justThisTest(ReflectionTest.class); + } + + private static AnalysisScope cachedScope; + + private static AnalysisScope findOrCreateAnalysisScope() throws IOException { + if (cachedScope == null) { + cachedScope = CallGraphTestUtil.makeJ2SEAnalysisScope(TestConstants.WALA_TESTDATA, "Java60RegressionExclusions.txt"); + } + return cachedScope; + } + + private static IClassHierarchy cachedCHA; + + private static IClassHierarchy findOrCreateCHA(AnalysisScope scope) throws ClassHierarchyException { + if (cachedCHA == null) { + cachedCHA = ClassHierarchy.make(scope); + } + return cachedCHA; + } + + @AfterClass + public static void afterClass() { + cachedCHA = null; + cachedScope = null; + } + + /** + * test that when analyzing Reflect1.main(), there is no warning about + * "Integer". + */ + @Test + public void testReflect1() throws WalaException, IllegalArgumentException, CancelException, IOException { + AnalysisScope scope = findOrCreateAnalysisScope(); + IClassHierarchy cha = findOrCreateCHA(scope); + Iterable entrypoints = com.ibm.wala.ipa.callgraph.impl.Util.makeMainEntrypoints(scope, cha, + TestConstants.REFLECT1_MAIN); + AnalysisOptions options = CallGraphTestUtil.makeAnalysisOptions(scope, entrypoints); + + Warnings.clear(); + CallGraphTest.doCallGraphs(options, new AnalysisCache(), cha, scope); + for (Iterator it = Warnings.iterator(); it.hasNext();) { + Warning w = (Warning) it.next(); + if (w.toString().indexOf("com/ibm/jvm") > 0) { + continue; + } + if (w.toString().indexOf("Integer") >= 0) { + Assert.assertTrue(w.toString(), false); + } + } + } + + /** + * Test that when analyzing reflect2, the call graph includes a node for + * java.lang.Integer.. This should be forced by the call for + * Class.forName("java.lang.Integer"). + */ + @Test + public void testReflect2() throws WalaException, IllegalArgumentException, CancelException, IOException { + AnalysisScope scope = findOrCreateAnalysisScope(); + IClassHierarchy cha = findOrCreateCHA(scope); + Iterable entrypoints = com.ibm.wala.ipa.callgraph.impl.Util.makeMainEntrypoints(scope, cha, + TestConstants.REFLECT2_MAIN); + AnalysisOptions options = CallGraphTestUtil.makeAnalysisOptions(scope, entrypoints); + CallGraph cg = CallGraphTestUtil.buildZeroOneCFA(options, new AnalysisCache(), cha, scope, false); + + TypeReference tr = TypeReference.findOrCreate(ClassLoaderReference.Application, "Ljava/lang/Integer"); + MethodReference mr = MethodReference.findOrCreate(tr, "", "()V"); + Set nodes = cg.getNodes(mr); + Assert.assertFalse(nodes.isEmpty()); + } + + /** + * Check that when analyzing Reflect3, the successors of newInstance do not + * include reflection/Reflect3$Hash + */ + @Test + public void testReflect3() throws IOException, ClassHierarchyException, IllegalArgumentException, CancelException { + AnalysisScope scope = findOrCreateAnalysisScope(); + IClassHierarchy cha = findOrCreateCHA(scope); + Iterable entrypoints = com.ibm.wala.ipa.callgraph.impl.Util.makeMainEntrypoints(scope, cha, + TestConstants.REFLECT3_MAIN); + AnalysisOptions options = CallGraphTestUtil.makeAnalysisOptions(scope, entrypoints); + CallGraph cg = CallGraphTestUtil.buildZeroOneCFA(options, new AnalysisCache(), cha, scope, false); + + TypeReference tr = TypeReference.findOrCreate(ClassLoaderReference.Application, "Ljava/lang/Class"); + MethodReference mr = MethodReference.findOrCreate(tr, "newInstance", "()Ljava/lang/Object;"); + Set newInstanceNodes = cg.getNodes(mr); + Set succNodes = HashSetFactory.make(); + for (CGNode newInstanceNode : newInstanceNodes) { + Iterator succNodesIter = cg.getSuccNodes(newInstanceNode); + while (succNodesIter.hasNext()) { + succNodes.add(succNodesIter.next()); + } + } + TypeReference extraneousTR = TypeReference.findOrCreate(ClassLoaderReference.Application, "Lreflection/Reflect3$Hash"); + IClass hashClass = cha.lookupClass(extraneousTR); + assert hashClass != null; + MethodReference extraneousMR = MethodReference.findOrCreate(extraneousTR, "", "()V"); + Set extraneousNodes = cg.getNodes(extraneousMR); + succNodes.retainAll(extraneousNodes); + Assert.assertTrue(succNodes.isEmpty()); + } + + /** + * Check that when analyzing Reflect4, successors of newInstance() do not + * include FilePermission ctor. + */ + @Test + public void testReflect4() throws IOException, ClassHierarchyException, IllegalArgumentException, CancelException { + AnalysisScope scope = findOrCreateAnalysisScope(); + IClassHierarchy cha = findOrCreateCHA(scope); + Iterable entrypoints = com.ibm.wala.ipa.callgraph.impl.Util.makeMainEntrypoints(scope, cha, + TestConstants.REFLECT4_MAIN); + AnalysisOptions options = CallGraphTestUtil.makeAnalysisOptions(scope, entrypoints); + CallGraph cg = CallGraphTestUtil.buildZeroOneCFA(options, new AnalysisCache(), cha, scope, false); + + TypeReference tr = TypeReference.findOrCreate(ClassLoaderReference.Application, "Ljava/lang/Class"); + MethodReference mr = MethodReference.findOrCreate(tr, "newInstance", "()Ljava/lang/Object;"); + Set newInstanceNodes = cg.getNodes(mr); + Set succNodes = HashSetFactory.make(); + for (CGNode newInstanceNode : newInstanceNodes) { + Iterator succNodesIter = cg.getSuccNodes(newInstanceNode); + while (succNodesIter.hasNext()) { + succNodes.add(succNodesIter.next()); + } + } + TypeReference extraneousTR = TypeReference.findOrCreate(ClassLoaderReference.Application, "Ljava/io/FilePermission"); + MethodReference extraneousMR = MethodReference.findOrCreate(extraneousTR, "", "(Ljava/lang/String;Ljava/lang/String;)V"); + Set extraneousNodes = cg.getNodes(extraneousMR); + succNodes.retainAll(extraneousNodes); + Assert.assertTrue(succNodes.isEmpty()); + } + + /** + * Check that when analyzing Reflect5, successors of newInstance do not + * include a Reflect5$A ctor + */ + @Test + public void testReflect5() throws IOException, ClassHierarchyException, IllegalArgumentException, CancelException { + AnalysisScope scope = findOrCreateAnalysisScope(); + IClassHierarchy cha = findOrCreateCHA(scope); + Iterable entrypoints = com.ibm.wala.ipa.callgraph.impl.Util.makeMainEntrypoints(scope, cha, + TestConstants.REFLECT5_MAIN); + AnalysisOptions options = CallGraphTestUtil.makeAnalysisOptions(scope, entrypoints); + CallGraph cg = CallGraphTestUtil.buildZeroOneCFA(options, new AnalysisCache(), cha, scope, false); + + TypeReference tr = TypeReference.findOrCreate(ClassLoaderReference.Application, "Ljava/lang/Class"); + MethodReference mr = MethodReference.findOrCreate(tr, "newInstance", "()Ljava/lang/Object;"); + Set newInstanceNodes = cg.getNodes(mr); + Set succNodes = HashSetFactory.make(); + for (CGNode newInstanceNode : newInstanceNodes) { + Iterator succNodesIter = cg.getSuccNodes(newInstanceNode); + while (succNodesIter.hasNext()) { + succNodes.add(succNodesIter.next()); + } + } + TypeReference extraneousTR = TypeReference.findOrCreate(ClassLoaderReference.Application, "Lreflection/Reflect5$A"); + MethodReference extraneousMR = MethodReference.findOrCreate(extraneousTR, "", "()V"); + Set extraneousNodes = cg.getNodes(extraneousMR); + succNodes.retainAll(extraneousNodes); + Assert.assertTrue(succNodes.isEmpty()); + } + + /** + * Check that when analyzing Reflect6, successors of newInstance do not + * include a Reflect6$A ctor + */ + @Test + public void testReflect6() throws IOException, ClassHierarchyException, IllegalArgumentException, CancelException { + AnalysisScope scope = findOrCreateAnalysisScope(); + IClassHierarchy cha = findOrCreateCHA(scope); + Iterable entrypoints = com.ibm.wala.ipa.callgraph.impl.Util.makeMainEntrypoints(scope, cha, + TestConstants.REFLECT6_MAIN); + AnalysisOptions options = CallGraphTestUtil.makeAnalysisOptions(scope, entrypoints); + CallGraph cg = CallGraphTestUtil.buildZeroOneCFA(options, new AnalysisCache(), cha, scope, false); + + TypeReference tr = TypeReference.findOrCreate(ClassLoaderReference.Application, "Ljava/lang/Class"); + MethodReference mr = MethodReference.findOrCreate(tr, "newInstance", "()Ljava/lang/Object;"); + Set newInstanceNodes = cg.getNodes(mr); + Set succNodes = HashSetFactory.make(); + for (CGNode newInstanceNode : newInstanceNodes) { + Iterator succNodesIter = cg.getSuccNodes(newInstanceNode); + while (succNodesIter.hasNext()) { + succNodes.add(succNodesIter.next()); + } + } + TypeReference extraneousTR = TypeReference.findOrCreate(ClassLoaderReference.Application, "Lreflection/Reflect6$A"); + MethodReference extraneousMR = MethodReference.findOrCreate(extraneousTR, "", "(I)V"); + Set extraneousNodes = cg.getNodes(extraneousMR); + succNodes.retainAll(extraneousNodes); + Assert.assertTrue(succNodes.isEmpty()); + } + + @SuppressWarnings("unchecked") + @Test + public void testReflect7() throws Exception { + AnalysisScope scope = findOrCreateAnalysisScope(); + IClassHierarchy cha = findOrCreateCHA(scope); + Iterable entrypoints = com.ibm.wala.ipa.callgraph.impl.Util.makeMainEntrypoints(scope, cha, + TestConstants.REFLECT7_MAIN); + AnalysisOptions options = CallGraphTestUtil.makeAnalysisOptions(scope, entrypoints); + CallGraph cg = CallGraphTestUtil.buildZeroOneCFA(options, new AnalysisCache(), cha, scope, false); + + final String mainClass = "Lreflection/Reflect7"; + TypeReference mainTr = TypeReference.findOrCreate(ClassLoaderReference.Application, mainClass); + MethodReference mainMr = MethodReference.findOrCreate(mainTr, "main", "([Ljava/lang/String;)V"); + + TypeReference constrTr = TypeReference.findOrCreate(ClassLoaderReference.Primordial, "Ljava/lang/reflect/Constructor"); + MethodReference newInstanceMr = MethodReference + .findOrCreate(constrTr, "newInstance", "([Ljava/lang/Object;)Ljava/lang/Object;"); + + String fpInitSig = "java.io.FilePermission.(Ljava/lang/String;Ljava/lang/String;)V"; + String fpToStringSig = "java.security.Permission.toString()Ljava/lang/String;"; + + Set mainNodes = cg.getNodes(mainMr); + + // Get all the children of the main node(s) + Collection mainChildren = getSuccNodes(cg, mainNodes); + + // Verify that one of those children is Constructor.newInstance, where + // Constructor is a FilePermission constructor + CGNode filePermConstrNewInstanceNode = null; + + for (CGNode node : mainChildren) { + Context context = node.getContext(); + if (context instanceof ReceiverInstanceContext && node.getMethod().getReference().equals(newInstanceMr)) { + ReceiverInstanceContext r = (ReceiverInstanceContext) context; + ConstantKey c = (ConstantKey) r.getReceiver(); + IMethod ctor = (IMethod) c.getValue(); + if (ctor.getSignature().equals(fpInitSig)) { + filePermConstrNewInstanceNode = node; + break; + } + } + } + Assert.assertTrue(filePermConstrNewInstanceNode != null); + + // Now verify that this node has FilePermission. children + CGNode filePermInitNode = null; + + Iterator filePermConstrNewInstanceChildren = cg.getSuccNodes(filePermConstrNewInstanceNode); + while (filePermConstrNewInstanceChildren.hasNext()) { + CGNode node = filePermConstrNewInstanceChildren.next(); + if (node.getMethod().getSignature().equals(fpInitSig)) { + filePermInitNode = node; + break; + } + } + Assert.assertTrue(filePermInitNode != null); + + // Furthermore, verify that main has a FilePermission.toString child + CGNode filePermToStringNode = null; + for (CGNode node : mainChildren) { + if (node.getMethod().getSignature().equals(fpToStringSig)) { + filePermToStringNode = node; + break; + } + } + + Assert.assertTrue(filePermToStringNode != null); + } + + private Collection getSuccNodes(CallGraph cg, Collection nodes) { + Set succNodes = HashSetFactory.make(); + for (CGNode newInstanceNode : nodes) { + Iterator succNodesIter = cg.getSuccNodes(newInstanceNode); + while (succNodesIter.hasNext()) { + succNodes.add(succNodesIter.next()); + } + } + return succNodes; + } + + /** + * Test that when analyzing reflect8, the call graph includes a node for + * java.lang.Integer.toString() + */ + @Test + public void testReflect8() throws WalaException, IllegalArgumentException, CancelException, IOException { + AnalysisScope scope = findOrCreateAnalysisScope(); + IClassHierarchy cha = findOrCreateCHA(scope); + Iterable entrypoints = com.ibm.wala.ipa.callgraph.impl.Util.makeMainEntrypoints(scope, cha, + TestConstants.REFLECT8_MAIN); + AnalysisOptions options = CallGraphTestUtil.makeAnalysisOptions(scope, entrypoints); + CallGraph cg = CallGraphTestUtil.buildZeroOneCFA(options, new AnalysisCache(), cha, scope, false); + TypeReference tr = TypeReference.findOrCreate(ClassLoaderReference.Primordial, "Ljava/lang/Integer"); + MethodReference mr = MethodReference.findOrCreate(tr, "toString", "()Ljava/lang/String;"); + Set nodes = cg.getNodes(mr); + Assert.assertFalse(nodes.isEmpty()); + } + + /** + * Test that when analyzing reflect9, the call graph includes a node for + * java.lang.Integer.toString() + */ + @Test + public void testReflect9() throws WalaException, IllegalArgumentException, CancelException, IOException { + AnalysisScope scope = findOrCreateAnalysisScope(); + IClassHierarchy cha = findOrCreateCHA(scope); + Iterable entrypoints = com.ibm.wala.ipa.callgraph.impl.Util.makeMainEntrypoints(scope, cha, + TestConstants.REFLECT9_MAIN); + AnalysisOptions options = CallGraphTestUtil.makeAnalysisOptions(scope, entrypoints); + CallGraph cg = CallGraphTestUtil.buildZeroOneCFA(options, new AnalysisCache(), cha, scope, false); + TypeReference tr = TypeReference.findOrCreate(ClassLoaderReference.Primordial, "Ljava/lang/Integer"); + MethodReference mr = MethodReference.findOrCreate(tr, "toString", "()Ljava/lang/String;"); + Set nodes = cg.getNodes(mr); + Assert.assertFalse(nodes.isEmpty()); + } + + /** + * Test that when analyzing Reflect10, the call graph includes a node for + * java.lang.Integer.toString() + */ + @Test + public void testReflect10() throws WalaException, IllegalArgumentException, CancelException, IOException { + AnalysisScope scope = findOrCreateAnalysisScope(); + IClassHierarchy cha = findOrCreateCHA(scope); + Iterable entrypoints = com.ibm.wala.ipa.callgraph.impl.Util.makeMainEntrypoints(scope, cha, + TestConstants.REFLECT10_MAIN); + AnalysisOptions options = CallGraphTestUtil.makeAnalysisOptions(scope, entrypoints); + CallGraph cg = CallGraphTestUtil.buildZeroOneCFA(options, new AnalysisCache(), cha, scope, false); + TypeReference tr = TypeReference.findOrCreate(ClassLoaderReference.Primordial, "Ljava/lang/Integer"); + MethodReference mr = MethodReference.findOrCreate(tr, "toString", "()Ljava/lang/String;"); + Set nodes = cg.getNodes(mr); + Assert.assertFalse(nodes.isEmpty()); + } + + /** + * Test that when analyzing Reflect11, the call graph includes a node for + * java.lang.Object.wait() + */ + @Test + public void testReflect11() throws WalaException, IllegalArgumentException, CancelException, IOException { + AnalysisScope scope = findOrCreateAnalysisScope(); + IClassHierarchy cha = findOrCreateCHA(scope); + Iterable entrypoints = com.ibm.wala.ipa.callgraph.impl.Util.makeMainEntrypoints(scope, cha, + TestConstants.REFLECT11_MAIN); + AnalysisOptions options = CallGraphTestUtil.makeAnalysisOptions(scope, entrypoints); + CallGraph cg = CallGraphTestUtil.buildZeroOneCFA(options, new AnalysisCache(), cha, scope, false); + TypeReference tr = TypeReference.findOrCreate(ClassLoaderReference.Primordial, "Ljava/lang/Object"); + MethodReference mr = MethodReference.findOrCreate(tr, "wait", "()V"); + Set nodes = cg.getNodes(mr); + Assert.assertFalse(nodes.isEmpty()); + } + + /** + * Test that when analyzing Reflect12, the call graph does not include a node + * for reflection.Helper.n but does include a node for reflection.Helper.m + */ + @Test + public void testReflect12() throws WalaException, IllegalArgumentException, CancelException, IOException { + AnalysisScope scope = findOrCreateAnalysisScope(); + IClassHierarchy cha = findOrCreateCHA(scope); + Iterable entrypoints = com.ibm.wala.ipa.callgraph.impl.Util.makeMainEntrypoints(scope, cha, + TestConstants.REFLECT12_MAIN); + AnalysisOptions options = CallGraphTestUtil.makeAnalysisOptions(scope, entrypoints); + CallGraph cg = CallGraphTestUtil.buildZeroOneCFA(options, new AnalysisCache(), cha, scope, false); + TypeReference tr = TypeReference.findOrCreate(ClassLoaderReference.Application, "Lreflection/Helper"); + MethodReference mr = MethodReference.findOrCreate(tr, "m", "(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)V"); + Set nodes = cg.getNodes(mr); + Assert.assertFalse(nodes.isEmpty()); + mr = MethodReference.findOrCreate(tr, "n", "(Ljava/lang/Object;Ljava/lang/Object;)V"); + nodes = cg.getNodes(mr); + Assert.assertTrue(nodes.isEmpty()); + } + + /** + * Test that when analyzing Reflect13, the call graph includes both a node for + * reflection.Helper.n and a node for reflection.Helper.m + */ + @Test + public void testReflect13() throws WalaException, IllegalArgumentException, CancelException, IOException { + AnalysisScope scope = findOrCreateAnalysisScope(); + IClassHierarchy cha = findOrCreateCHA(scope); + Iterable entrypoints = com.ibm.wala.ipa.callgraph.impl.Util.makeMainEntrypoints(scope, cha, + TestConstants.REFLECT13_MAIN); + AnalysisOptions options = CallGraphTestUtil.makeAnalysisOptions(scope, entrypoints); + CallGraph cg = CallGraphTestUtil.buildZeroOneCFA(options, new AnalysisCache(), cha, scope, false); + TypeReference tr = TypeReference.findOrCreate(ClassLoaderReference.Application, "Lreflection/Helper"); + MethodReference mr = MethodReference.findOrCreate(tr, "m", "(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)V"); + Set nodes = cg.getNodes(mr); + Assert.assertFalse(nodes.isEmpty()); + mr = MethodReference.findOrCreate(tr, "n", "(Ljava/lang/Object;Ljava/lang/Object;)V"); + nodes = cg.getNodes(mr); + Assert.assertFalse(nodes.isEmpty()); + } + + /** + * Test that when analyzing Reflect14, the call graph does not include a node + * for reflection.Helper.n but does include a node for reflection.Helper.s + */ + @Test + public void testReflect14() throws WalaException, IllegalArgumentException, CancelException, IOException { + AnalysisScope scope = findOrCreateAnalysisScope(); + IClassHierarchy cha = findOrCreateCHA(scope); + Iterable entrypoints = com.ibm.wala.ipa.callgraph.impl.Util.makeMainEntrypoints(scope, cha, + TestConstants.REFLECT14_MAIN); + AnalysisOptions options = CallGraphTestUtil.makeAnalysisOptions(scope, entrypoints); + CallGraph cg = CallGraphTestUtil.buildZeroOneCFA(options, new AnalysisCache(), cha, scope, false); + TypeReference tr = TypeReference.findOrCreate(ClassLoaderReference.Application, "Lreflection/Helper"); + MethodReference mr = MethodReference.findOrCreate(tr, "s", "(Ljava/lang/Object;Ljava/lang/Object;)V"); + Set nodes = cg.getNodes(mr); + Assert.assertFalse(nodes.isEmpty()); + mr = MethodReference.findOrCreate(tr, "n", "(Ljava/lang/Object;Ljava/lang/Object;)V"); + nodes = cg.getNodes(mr); + Assert.assertTrue(nodes.isEmpty()); + } + + /** + * Test that when analyzing Reflect15, the call graph includes a node for the + * constructor of Helper that takes 2 parameters and for Helper.n, but no node + * for the constructors of Helper that takes 0 or 1 parameters. + */ + @Test + public void testReflect15() throws WalaException, IllegalArgumentException, CancelException, IOException { + AnalysisScope scope = findOrCreateAnalysisScope(); + IClassHierarchy cha = findOrCreateCHA(scope); + Iterable entrypoints = com.ibm.wala.ipa.callgraph.impl.Util.makeMainEntrypoints(scope, cha, + TestConstants.REFLECT15_MAIN); + AnalysisOptions options = CallGraphTestUtil.makeAnalysisOptions(scope, entrypoints); + CallGraph cg = CallGraphTestUtil.buildZeroOneCFA(options, new AnalysisCache(), cha, scope, false); + TypeReference tr = TypeReference.findOrCreate(ClassLoaderReference.Application, "Lreflection/Helper"); + MethodReference mr = MethodReference.findOrCreate(tr, "", "(Ljava/lang/Object;Ljava/lang/Object;)V"); + Set nodes = cg.getNodes(mr); + Assert.assertFalse(nodes.isEmpty()); + mr = MethodReference.findOrCreate(tr, "", "(Ljava/lang/Object;)V"); + nodes = cg.getNodes(mr); + Assert.assertTrue(nodes.isEmpty()); + mr = MethodReference.findOrCreate(tr, "", "()V"); + nodes = cg.getNodes(mr); + Assert.assertTrue(nodes.isEmpty()); + mr = MethodReference.findOrCreate(tr, "n", "(Ljava/lang/Object;Ljava/lang/Object;)V"); + nodes = cg.getNodes(mr); + Assert.assertFalse(nodes.isEmpty()); + } + + /** + * Test that when analyzing Reflect16, the call graph includes a node for + * java.lang.Integer.toString() + */ + @Test + public void testReflect16() throws WalaException, IllegalArgumentException, CancelException, IOException { + AnalysisScope scope = findOrCreateAnalysisScope(); + IClassHierarchy cha = findOrCreateCHA(scope); + Iterable entrypoints = com.ibm.wala.ipa.callgraph.impl.Util.makeMainEntrypoints(scope, cha, + TestConstants.REFLECT16_MAIN); + AnalysisOptions options = CallGraphTestUtil.makeAnalysisOptions(scope, entrypoints); + CallGraph cg = CallGraphTestUtil.buildZeroOneCFA(options, new AnalysisCache(), cha, scope, false); + TypeReference tr = TypeReference.findOrCreate(ClassLoaderReference.Primordial, "Ljava/lang/Integer"); + MethodReference mr = MethodReference.findOrCreate(tr, "toString", "()Ljava/lang/String;"); + Set nodes = cg.getNodes(mr); + Assert.assertFalse(nodes.isEmpty()); + } + + /** + * Test that when analyzing Reflect17, the call graph does not include any + * edges from reflection.Helper.t() + */ + @Test + public void testReflect17() throws WalaException, IllegalArgumentException, CancelException, IOException { + AnalysisScope scope = findOrCreateAnalysisScope(); + IClassHierarchy cha = findOrCreateCHA(scope); + Iterable entrypoints = com.ibm.wala.ipa.callgraph.impl.Util.makeMainEntrypoints(scope, cha, + TestConstants.REFLECT17_MAIN); + AnalysisOptions options = CallGraphTestUtil.makeAnalysisOptions(scope, entrypoints); + CallGraph cg = CallGraphTestUtil.buildZeroOneCFA(options, new AnalysisCache(), cha, scope, false); + TypeReference tr = TypeReference.findOrCreate(ClassLoaderReference.Application, "Lreflection/Helper"); + MethodReference mr = MethodReference.findOrCreate(tr, "t", "(Ljava/lang/Integer;)V"); + CGNode node = cg.getNode(cg.getClassHierarchy().resolveMethod(mr), Everywhere.EVERYWHERE); + Assert.assertEquals(0, cg.getSuccNodeCount(node)); + } + + /** + * Test that when analyzing Reflect18, the call graph includes a node for + * java.lang.Integer.toString() + */ + @Test + public void testReflect18() throws WalaException, IllegalArgumentException, CancelException, IOException { + AnalysisScope scope = findOrCreateAnalysisScope(); + IClassHierarchy cha = findOrCreateCHA(scope); + Iterable entrypoints = com.ibm.wala.ipa.callgraph.impl.Util.makeMainEntrypoints(scope, cha, + TestConstants.REFLECT18_MAIN); + AnalysisOptions options = CallGraphTestUtil.makeAnalysisOptions(scope, entrypoints); + CallGraph cg = CallGraphTestUtil.buildZeroOneCFA(options, new AnalysisCache(), cha, scope, false); + TypeReference tr = TypeReference.findOrCreate(ClassLoaderReference.Application, "Lreflection/Helper"); + MethodReference mr = MethodReference.findOrCreate(tr, "t", "(Ljava/lang/Integer;)V"); + CGNode node = cg.getNode(cg.getClassHierarchy().resolveMethod(mr), Everywhere.EVERYWHERE); + Assert.assertEquals(1, cg.getSuccNodeCount(node)); + CGNode succ = cg.getSuccNodes(node).next(); + Assert.assertEquals("Node: < Primordial, Ljava/lang/Integer, toString()Ljava/lang/String; > Context: Everywhere", + succ.toString()); + } + + /** + * Test that when analyzing Reflect19, the call graph includes a node for + * java.lang.Integer.toString() + */ + @Test + public void testReflect19() throws WalaException, IllegalArgumentException, CancelException, IOException { + AnalysisScope scope = findOrCreateAnalysisScope(); + IClassHierarchy cha = findOrCreateCHA(scope); + Iterable entrypoints = com.ibm.wala.ipa.callgraph.impl.Util.makeMainEntrypoints(scope, cha, + TestConstants.REFLECT19_MAIN); + AnalysisOptions options = CallGraphTestUtil.makeAnalysisOptions(scope, entrypoints); + CallGraph cg = CallGraphTestUtil.buildZeroOneCFA(options, new AnalysisCache(), cha, scope, false); + TypeReference tr = TypeReference.findOrCreate(ClassLoaderReference.Primordial, "Ljava/lang/Integer"); + MethodReference mr = MethodReference.findOrCreate(tr, "toString", "()Ljava/lang/String;"); + Set nodes = cg.getNodes(mr); + Assert.assertFalse(nodes.isEmpty()); + } + + /** + * Test that when analyzing Reflect20, the call graph includes a node for + * Helper.o. + */ + @Test + public void testReflect20() throws WalaException, IllegalArgumentException, CancelException, IOException { + AnalysisScope scope = findOrCreateAnalysisScope(); + IClassHierarchy cha = findOrCreateCHA(scope); + Iterable entrypoints = com.ibm.wala.ipa.callgraph.impl.Util.makeMainEntrypoints(scope, cha, + TestConstants.REFLECT20_MAIN); + AnalysisOptions options = CallGraphTestUtil.makeAnalysisOptions(scope, entrypoints); + CallGraph cg = CallGraphTestUtil.buildZeroOneCFA(options, new AnalysisCache(), cha, scope, false); + TypeReference tr = TypeReference.findOrCreate(ClassLoaderReference.Application, "Lreflection/Helper"); + MethodReference mr = MethodReference.findOrCreate(tr, "o", "(Ljava/lang/Object;Ljava/lang/Object;)V"); + Set nodes = cg.getNodes(mr); + Assert.assertFalse(nodes.isEmpty()); + } + + /** + * Test that when analyzing Reflect21, the call graph includes a node for the + * constructor of {@link Helper} that takes two {@link Object} parameters. + * This is to test the support for Class.getDeclaredConstructor. + */ + @Test + public void testReflect21() throws WalaException, IllegalArgumentException, CancelException, IOException { + AnalysisScope scope = findOrCreateAnalysisScope(); + IClassHierarchy cha = findOrCreateCHA(scope); + Iterable entrypoints = com.ibm.wala.ipa.callgraph.impl.Util.makeMainEntrypoints(scope, cha, + TestConstants.REFLECT21_MAIN); + AnalysisOptions options = CallGraphTestUtil.makeAnalysisOptions(scope, entrypoints); + CallGraph cg = CallGraphTestUtil.buildZeroOneCFA(options, new AnalysisCache(), cha, scope, false); + TypeReference tr = TypeReference.findOrCreate(ClassLoaderReference.Application, "Lreflection/Helper"); + MethodReference mr = MethodReference.findOrCreate(tr, "", "(Ljava/lang/Object;Ljava/lang/Object;)V"); + Set nodes = cg.getNodes(mr); + Assert.assertFalse(nodes.isEmpty()); + } + + /** + * Test that when analyzing Reflect22, the call graph includes a node for the + * constructor of {@link Helper} that takes one {@link Integer} parameters. + * This is to test the support for Class.getDeclaredConstructors. + */ + @Test + public void testReflect22() throws WalaException, IllegalArgumentException, CancelException, IOException { + AnalysisScope scope = findOrCreateAnalysisScope(); + IClassHierarchy cha = findOrCreateCHA(scope); + Iterable entrypoints = com.ibm.wala.ipa.callgraph.impl.Util.makeMainEntrypoints(scope, cha, + TestConstants.REFLECT22_MAIN); + AnalysisOptions options = CallGraphTestUtil.makeAnalysisOptions(scope, entrypoints); + CallGraph cg = CallGraphTestUtil.buildZeroOneCFA(options, new AnalysisCache(), cha, scope, false); + TypeReference tr = TypeReference.findOrCreate(ClassLoaderReference.Application, "Lreflection/Helper"); + MethodReference mr = MethodReference.findOrCreate(tr, "", "(Ljava/lang/Integer;)V"); + Set nodes = cg.getNodes(mr); + Assert.assertFalse(nodes.isEmpty()); + } + + /** + * Test that when analyzing Reflect22, the call graph includes a node for the + * constructor of {@link Helper} that takes one {@link Integer} parameters. + * This is to test the support for Class.getDeclaredConstructors. + */ + @Test + public void testReflect23() throws WalaException, IllegalArgumentException, CancelException, IOException { + AnalysisScope scope = findOrCreateAnalysisScope(); + IClassHierarchy cha = findOrCreateCHA(scope); + Iterable entrypoints = com.ibm.wala.ipa.callgraph.impl.Util.makeMainEntrypoints(scope, cha, + TestConstants.REFLECT23_MAIN); + AnalysisOptions options = CallGraphTestUtil.makeAnalysisOptions(scope, entrypoints); + CallGraph cg = CallGraphTestUtil.buildZeroOneCFA(options, new AnalysisCache(), cha, scope, false); + TypeReference tr = TypeReference.findOrCreate(ClassLoaderReference.Application, "Lreflection/Helper"); + MethodReference mr = MethodReference.findOrCreate(tr, "u", "(Ljava/lang/Integer;)V"); + Set nodes = cg.getNodes(mr); + Assert.assertFalse(nodes.isEmpty()); + } +} diff --git a/com.ibm.wala.core.tests/src/com/ibm/wala/core/tests/callGraph/SyntheticTest.java b/com.ibm.wala.core.tests/src/com/ibm/wala/core/tests/callGraph/SyntheticTest.java index 1806b9fbe..0c3a6644c 100644 --- a/com.ibm.wala.core.tests/src/com/ibm/wala/core/tests/callGraph/SyntheticTest.java +++ b/com.ibm.wala.core.tests/src/com/ibm/wala/core/tests/callGraph/SyntheticTest.java @@ -1,67 +1,67 @@ -/******************************************************************************* - * 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 com.ibm.wala.core.tests.callGraph; - -import java.io.IOException; -import java.util.Collections; - -import org.junit.Assert; -import org.junit.Test; - -import com.ibm.wala.classLoader.IMethod; -import com.ibm.wala.core.tests.util.TestConstants; -import com.ibm.wala.core.tests.util.WalaTestCase; -import com.ibm.wala.ipa.callgraph.AnalysisCache; -import com.ibm.wala.ipa.callgraph.AnalysisOptions; -import com.ibm.wala.ipa.callgraph.AnalysisScope; -import com.ibm.wala.ipa.callgraph.CGNode; -import com.ibm.wala.ipa.callgraph.CallGraph; -import com.ibm.wala.ipa.callgraph.Entrypoint; -import com.ibm.wala.ipa.callgraph.impl.SubtypesEntrypoint; -import com.ibm.wala.ipa.cha.ClassHierarchy; -import com.ibm.wala.ipa.cha.ClassHierarchyException; -import com.ibm.wala.ssa.IR; -import com.ibm.wala.types.ClassLoaderReference; -import com.ibm.wala.types.MethodReference; -import com.ibm.wala.types.TypeReference; -import com.ibm.wala.util.CancelException; - -/** - * Tests for synthetic methods - */ -public class SyntheticTest extends WalaTestCase { - - @Test public void testMultiSubtypes() throws ClassHierarchyException, IllegalArgumentException, CancelException, IOException { - AnalysisScope scope = CallGraphTestUtil.makeJ2SEAnalysisScope(TestConstants.WALA_TESTDATA, - CallGraphTestUtil.REGRESSION_EXCLUSIONS); - ClassHierarchy cha = ClassHierarchy.make(scope); - TypeReference t = TypeReference.findOrCreate(ClassLoaderReference.Application, "LmultiTypes/Foo"); - MethodReference mref = MethodReference.findOrCreate(t, "foo", "(LmultiTypes/Foo$A;)V"); - IMethod m = cha.resolveMethod(mref); - assert m != null; - SubtypesEntrypoint e = new SubtypesEntrypoint(m, cha); - AnalysisOptions options = CallGraphTestUtil.makeAnalysisOptions(scope, Collections.singleton(e)); - - CallGraph cg = CallGraphTestUtil.buildZeroCFA(options, new AnalysisCache(), cha, scope, false); - - TypeReference tA = TypeReference.findOrCreate(ClassLoaderReference.Application, "LmultiTypes/Foo$A"); - MethodReference barA = MethodReference.findOrCreate(tA, "bar", "()V"); - TypeReference tB = TypeReference.findOrCreate(ClassLoaderReference.Application, "LmultiTypes/Foo$B"); - MethodReference barB = MethodReference.findOrCreate(tB, "bar", "()V"); - Assert.assertTrue(cg.getNodes(barA).size() == 1); - Assert.assertTrue(cg.getNodes(barB).size() == 1); - - CGNode root = cg.getFakeRootNode(); - IR ir = root.getIR(); - Assert.assertTrue(ir.iteratePhis().hasNext()); - } - -} +/******************************************************************************* + * 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 com.ibm.wala.core.tests.callGraph; + +import java.io.IOException; +import java.util.Collections; + +import org.junit.Assert; +import org.junit.Test; + +import com.ibm.wala.classLoader.IMethod; +import com.ibm.wala.core.tests.util.TestConstants; +import com.ibm.wala.core.tests.util.WalaTestCase; +import com.ibm.wala.ipa.callgraph.AnalysisCache; +import com.ibm.wala.ipa.callgraph.AnalysisOptions; +import com.ibm.wala.ipa.callgraph.AnalysisScope; +import com.ibm.wala.ipa.callgraph.CGNode; +import com.ibm.wala.ipa.callgraph.CallGraph; +import com.ibm.wala.ipa.callgraph.Entrypoint; +import com.ibm.wala.ipa.callgraph.impl.SubtypesEntrypoint; +import com.ibm.wala.ipa.cha.ClassHierarchy; +import com.ibm.wala.ipa.cha.ClassHierarchyException; +import com.ibm.wala.ssa.IR; +import com.ibm.wala.types.ClassLoaderReference; +import com.ibm.wala.types.MethodReference; +import com.ibm.wala.types.TypeReference; +import com.ibm.wala.util.CancelException; + +/** + * Tests for synthetic methods + */ +public class SyntheticTest extends WalaTestCase { + + @Test public void testMultiSubtypes() throws ClassHierarchyException, IllegalArgumentException, CancelException, IOException { + AnalysisScope scope = CallGraphTestUtil.makeJ2SEAnalysisScope(TestConstants.WALA_TESTDATA, + CallGraphTestUtil.REGRESSION_EXCLUSIONS); + ClassHierarchy cha = ClassHierarchy.make(scope); + TypeReference t = TypeReference.findOrCreate(ClassLoaderReference.Application, "LmultiTypes/Foo"); + MethodReference mref = MethodReference.findOrCreate(t, "foo", "(LmultiTypes/Foo$A;)V"); + IMethod m = cha.resolveMethod(mref); + assert m != null; + SubtypesEntrypoint e = new SubtypesEntrypoint(m, cha); + AnalysisOptions options = CallGraphTestUtil.makeAnalysisOptions(scope, Collections.singleton(e)); + + CallGraph cg = CallGraphTestUtil.buildZeroCFA(options, new AnalysisCache(), cha, scope, false); + + TypeReference tA = TypeReference.findOrCreate(ClassLoaderReference.Application, "LmultiTypes/Foo$A"); + MethodReference barA = MethodReference.findOrCreate(tA, "bar", "()V"); + TypeReference tB = TypeReference.findOrCreate(ClassLoaderReference.Application, "LmultiTypes/Foo$B"); + MethodReference barB = MethodReference.findOrCreate(tB, "bar", "()V"); + Assert.assertTrue(cg.getNodes(barA).size() == 1); + Assert.assertTrue(cg.getNodes(barB).size() == 1); + + CGNode root = cg.getFakeRootNode(); + IR ir = root.getIR(); + Assert.assertTrue(ir.iteratePhis().hasNext()); + } + +} diff --git a/com.ibm.wala.core.tests/src/com/ibm/wala/core/tests/cha/GetTargetsTest.java b/com.ibm.wala.core.tests/src/com/ibm/wala/core/tests/cha/GetTargetsTest.java index 638fa2c66..eea7c1448 100644 --- a/com.ibm.wala.core.tests/src/com/ibm/wala/core/tests/cha/GetTargetsTest.java +++ b/com.ibm.wala.core.tests/src/com/ibm/wala/core/tests/cha/GetTargetsTest.java @@ -1,98 +1,98 @@ -/******************************************************************************* - * 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.core.tests.cha; - -import java.util.Collection; - -import org.junit.AfterClass; -import org.junit.Assert; -import org.junit.BeforeClass; -import org.junit.Test; - -import com.ibm.wala.classLoader.ClassLoaderFactory; -import com.ibm.wala.classLoader.ClassLoaderFactoryImpl; -import com.ibm.wala.classLoader.IMethod; -import com.ibm.wala.core.tests.util.TestConstants; -import com.ibm.wala.core.tests.util.WalaTestCase; -import com.ibm.wala.ipa.callgraph.AnalysisScope; -import com.ibm.wala.ipa.cha.ClassHierarchy; -import com.ibm.wala.ipa.cha.ClassHierarchyException; -import com.ibm.wala.types.ClassLoaderReference; -import com.ibm.wala.types.MethodReference; -import com.ibm.wala.types.TypeReference; -import com.ibm.wala.util.config.AnalysisScopeReader; -import com.ibm.wala.util.io.FileProvider; - -/** - * Test ClassHierarchy.getPossibleTargets - */ -public class GetTargetsTest extends WalaTestCase { - - private static final ClassLoader MY_CLASSLOADER = GetTargetsTest.class.getClassLoader(); - - private static AnalysisScope scope; - private static ClassHierarchy cha; - - public static void main(String[] args) { - justThisTest(GetTargetsTest.class); - } - - @BeforeClass - public static void beforeClass() throws Exception { - - scope = AnalysisScopeReader.readJavaScope(TestConstants.WALA_TESTDATA, (new FileProvider()).getFile("J2SEClassHierarchyExclusions.txt"), MY_CLASSLOADER); - - ClassLoaderFactory factory = new ClassLoaderFactoryImpl(scope.getExclusions() ); - - try { - cha = ClassHierarchy.make(scope, factory); - } catch (ClassHierarchyException e) { - throw new Exception(); - } - } - - /* - * (non-Javadoc) - * - * @see junit.framework.TestCase#tearDown() - */ - @AfterClass - public static void afterClass() throws Exception { - scope = null; - cha = null; - } - - - /** - * Test for bug 1714480, reported OOM on {@link ClassHierarchy} getPossibleTargets() - */ - @Test public void testCell() { - TypeReference t = TypeReference.findOrCreate(ClassLoaderReference.Application, "Lcell/Cell"); - MethodReference m = MethodReference.findOrCreate(t, "", "(Ljava/lang/Object;)V"); - Collection c = cha.getPossibleTargets(m); - for (IMethod method : c) { - System.err.println(method); - } - Assert.assertEquals(1, c.size()); - } - - /** - * test that calls to methods are treated specially - */ - @Test public void testObjInit() { - MethodReference m = MethodReference.findOrCreate(TypeReference.JavaLangObject, MethodReference.initSelector); - Collection c = cha.getPossibleTargets(m); - for (IMethod method : c) { - System.err.println(method); - } - Assert.assertEquals(1, c.size()); - } -} +/******************************************************************************* + * 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.core.tests.cha; + +import java.util.Collection; + +import org.junit.AfterClass; +import org.junit.Assert; +import org.junit.BeforeClass; +import org.junit.Test; + +import com.ibm.wala.classLoader.ClassLoaderFactory; +import com.ibm.wala.classLoader.ClassLoaderFactoryImpl; +import com.ibm.wala.classLoader.IMethod; +import com.ibm.wala.core.tests.util.TestConstants; +import com.ibm.wala.core.tests.util.WalaTestCase; +import com.ibm.wala.ipa.callgraph.AnalysisScope; +import com.ibm.wala.ipa.cha.ClassHierarchy; +import com.ibm.wala.ipa.cha.ClassHierarchyException; +import com.ibm.wala.types.ClassLoaderReference; +import com.ibm.wala.types.MethodReference; +import com.ibm.wala.types.TypeReference; +import com.ibm.wala.util.config.AnalysisScopeReader; +import com.ibm.wala.util.io.FileProvider; + +/** + * Test ClassHierarchy.getPossibleTargets + */ +public class GetTargetsTest extends WalaTestCase { + + private static final ClassLoader MY_CLASSLOADER = GetTargetsTest.class.getClassLoader(); + + private static AnalysisScope scope; + private static ClassHierarchy cha; + + public static void main(String[] args) { + justThisTest(GetTargetsTest.class); + } + + @BeforeClass + public static void beforeClass() throws Exception { + + scope = AnalysisScopeReader.readJavaScope(TestConstants.WALA_TESTDATA, (new FileProvider()).getFile("J2SEClassHierarchyExclusions.txt"), MY_CLASSLOADER); + + ClassLoaderFactory factory = new ClassLoaderFactoryImpl(scope.getExclusions() ); + + try { + cha = ClassHierarchy.make(scope, factory); + } catch (ClassHierarchyException e) { + throw new Exception(); + } + } + + /* + * (non-Javadoc) + * + * @see junit.framework.TestCase#tearDown() + */ + @AfterClass + public static void afterClass() throws Exception { + scope = null; + cha = null; + } + + + /** + * Test for bug 1714480, reported OOM on {@link ClassHierarchy} getPossibleTargets() + */ + @Test public void testCell() { + TypeReference t = TypeReference.findOrCreate(ClassLoaderReference.Application, "Lcell/Cell"); + MethodReference m = MethodReference.findOrCreate(t, "", "(Ljava/lang/Object;)V"); + Collection c = cha.getPossibleTargets(m); + for (IMethod method : c) { + System.err.println(method); + } + Assert.assertEquals(1, c.size()); + } + + /** + * test that calls to methods are treated specially + */ + @Test public void testObjInit() { + MethodReference m = MethodReference.findOrCreate(TypeReference.JavaLangObject, MethodReference.initSelector); + Collection c = cha.getPossibleTargets(m); + for (IMethod method : c) { + System.err.println(method); + } + Assert.assertEquals(1, c.size()); + } +} diff --git a/com.ibm.wala.core.tests/src/com/ibm/wala/core/tests/cha/InnerClassesTest.java b/com.ibm.wala.core.tests/src/com/ibm/wala/core/tests/cha/InnerClassesTest.java index 2e01d6405..5f52e3142 100644 --- a/com.ibm.wala.core.tests/src/com/ibm/wala/core/tests/cha/InnerClassesTest.java +++ b/com.ibm.wala.core.tests/src/com/ibm/wala/core/tests/cha/InnerClassesTest.java @@ -1,98 +1,98 @@ -/******************************************************************************* - * Copyright (c) 20078 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.core.tests.cha; - -import org.junit.AfterClass; -import org.junit.Assert; -import org.junit.BeforeClass; -import org.junit.Test; - -import com.ibm.wala.classLoader.ClassLoaderFactory; -import com.ibm.wala.classLoader.ClassLoaderFactoryImpl; -import com.ibm.wala.classLoader.IClass; -import com.ibm.wala.classLoader.ShrikeClass; -import com.ibm.wala.core.tests.util.TestConstants; -import com.ibm.wala.core.tests.util.WalaTestCase; -import com.ibm.wala.ipa.callgraph.AnalysisScope; -import com.ibm.wala.ipa.cha.ClassHierarchy; -import com.ibm.wala.ipa.cha.ClassHierarchyException; -import com.ibm.wala.shrikeCT.InvalidClassFileException; -import com.ibm.wala.types.ClassLoaderReference; -import com.ibm.wala.types.TypeName; -import com.ibm.wala.types.TypeReference; -import com.ibm.wala.util.config.AnalysisScopeReader; -import com.ibm.wala.util.io.FileProvider; - -/** - * Test stuff with inner classes - */ -public class InnerClassesTest extends WalaTestCase { - - private static final ClassLoader MY_CLASSLOADER = InnerClassesTest.class.getClassLoader(); - - private static AnalysisScope scope; - - private static ClassHierarchy cha; - - public static void main(String[] args) { - justThisTest(InnerClassesTest.class); - } - - @BeforeClass - public static void beforeClass() throws Exception { - scope = AnalysisScopeReader.readJavaScope(TestConstants.WALA_TESTDATA, (new FileProvider()).getFile("J2SEClassHierarchyExclusions.txt"), - MY_CLASSLOADER); - - ClassLoaderFactory factory = new ClassLoaderFactoryImpl(scope.getExclusions()); - - try { - cha = ClassHierarchy.make(scope, factory); - } catch (ClassHierarchyException e) { - throw new Exception(); - } - } - - @AfterClass - public static void afterClass() throws Exception { - scope = null; - cha = null; - } - - @Test public void test1() throws InvalidClassFileException { - TypeReference t = TypeReference.findOrCreate(ClassLoaderReference.Application, TypeName - .string2TypeName("Linner/TestStaticInner")); - IClass klass = cha.lookupClass(t); - assert klass != null; - ShrikeClass s = (ShrikeClass)klass; - Assert.assertFalse(s.isInnerClass()); - } - - @Test public void test2() throws InvalidClassFileException { - TypeReference t = TypeReference.findOrCreate(ClassLoaderReference.Application, TypeName - .string2TypeName("Linner/TestStaticInner$A")); - IClass klass = cha.lookupClass(t); - assert klass != null; - ShrikeClass s = (ShrikeClass)klass; - Assert.assertTrue(s.isInnerClass()); - Assert.assertTrue(s.isStaticInnerClass()); - } - - @Test public void test3() throws InvalidClassFileException { - TypeReference t = TypeReference.findOrCreate(ClassLoaderReference.Application, TypeName - .string2TypeName("Linner/TestInner$A")); - IClass klass = cha.lookupClass(t); - assert klass != null; - ShrikeClass s = (ShrikeClass)klass; - Assert.assertTrue(s.isInnerClass()); - Assert.assertFalse(s.isStaticInnerClass()); - } - -} +/******************************************************************************* + * Copyright (c) 20078 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.core.tests.cha; + +import org.junit.AfterClass; +import org.junit.Assert; +import org.junit.BeforeClass; +import org.junit.Test; + +import com.ibm.wala.classLoader.ClassLoaderFactory; +import com.ibm.wala.classLoader.ClassLoaderFactoryImpl; +import com.ibm.wala.classLoader.IClass; +import com.ibm.wala.classLoader.ShrikeClass; +import com.ibm.wala.core.tests.util.TestConstants; +import com.ibm.wala.core.tests.util.WalaTestCase; +import com.ibm.wala.ipa.callgraph.AnalysisScope; +import com.ibm.wala.ipa.cha.ClassHierarchy; +import com.ibm.wala.ipa.cha.ClassHierarchyException; +import com.ibm.wala.shrikeCT.InvalidClassFileException; +import com.ibm.wala.types.ClassLoaderReference; +import com.ibm.wala.types.TypeName; +import com.ibm.wala.types.TypeReference; +import com.ibm.wala.util.config.AnalysisScopeReader; +import com.ibm.wala.util.io.FileProvider; + +/** + * Test stuff with inner classes + */ +public class InnerClassesTest extends WalaTestCase { + + private static final ClassLoader MY_CLASSLOADER = InnerClassesTest.class.getClassLoader(); + + private static AnalysisScope scope; + + private static ClassHierarchy cha; + + public static void main(String[] args) { + justThisTest(InnerClassesTest.class); + } + + @BeforeClass + public static void beforeClass() throws Exception { + scope = AnalysisScopeReader.readJavaScope(TestConstants.WALA_TESTDATA, (new FileProvider()).getFile("J2SEClassHierarchyExclusions.txt"), + MY_CLASSLOADER); + + ClassLoaderFactory factory = new ClassLoaderFactoryImpl(scope.getExclusions()); + + try { + cha = ClassHierarchy.make(scope, factory); + } catch (ClassHierarchyException e) { + throw new Exception(); + } + } + + @AfterClass + public static void afterClass() throws Exception { + scope = null; + cha = null; + } + + @Test public void test1() throws InvalidClassFileException { + TypeReference t = TypeReference.findOrCreate(ClassLoaderReference.Application, TypeName + .string2TypeName("Linner/TestStaticInner")); + IClass klass = cha.lookupClass(t); + assert klass != null; + ShrikeClass s = (ShrikeClass)klass; + Assert.assertFalse(s.isInnerClass()); + } + + @Test public void test2() throws InvalidClassFileException { + TypeReference t = TypeReference.findOrCreate(ClassLoaderReference.Application, TypeName + .string2TypeName("Linner/TestStaticInner$A")); + IClass klass = cha.lookupClass(t); + assert klass != null; + ShrikeClass s = (ShrikeClass)klass; + Assert.assertTrue(s.isInnerClass()); + Assert.assertTrue(s.isStaticInnerClass()); + } + + @Test public void test3() throws InvalidClassFileException { + TypeReference t = TypeReference.findOrCreate(ClassLoaderReference.Application, TypeName + .string2TypeName("Linner/TestInner$A")); + IClass klass = cha.lookupClass(t); + assert klass != null; + ShrikeClass s = (ShrikeClass)klass; + Assert.assertTrue(s.isInnerClass()); + Assert.assertFalse(s.isStaticInnerClass()); + } + +} diff --git a/com.ibm.wala.core.tests/src/com/ibm/wala/core/tests/cha/InterfaceTest.java b/com.ibm.wala.core.tests/src/com/ibm/wala/core/tests/cha/InterfaceTest.java index 16518dc82..ebe317ad8 100644 --- a/com.ibm.wala.core.tests/src/com/ibm/wala/core/tests/cha/InterfaceTest.java +++ b/com.ibm.wala.core.tests/src/com/ibm/wala/core/tests/cha/InterfaceTest.java @@ -1,101 +1,101 @@ -/******************************************************************************* - * Copyright (c) 2007 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.core.tests.cha; - -import org.junit.AfterClass; -import org.junit.Assert; -import org.junit.BeforeClass; -import org.junit.Test; - -import com.ibm.wala.classLoader.ClassLoaderFactory; -import com.ibm.wala.classLoader.ClassLoaderFactoryImpl; -import com.ibm.wala.classLoader.IClass; -import com.ibm.wala.core.tests.util.TestConstants; -import com.ibm.wala.core.tests.util.WalaTestCase; -import com.ibm.wala.ipa.callgraph.AnalysisScope; -import com.ibm.wala.ipa.cha.ClassHierarchy; -import com.ibm.wala.ipa.cha.ClassHierarchyException; -import com.ibm.wala.types.ClassLoaderReference; -import com.ibm.wala.types.TypeName; -import com.ibm.wala.types.TypeReference; -import com.ibm.wala.util.config.AnalysisScopeReader; -import com.ibm.wala.util.io.FileProvider; - -/** - * Test interface subtype stuff - */ -public class InterfaceTest extends WalaTestCase { - - private static final ClassLoader MY_CLASSLOADER = InterfaceTest.class.getClassLoader(); - - private static AnalysisScope scope; - private static ClassHierarchy cha; - - public static void main(String[] args) { - justThisTest(InterfaceTest.class); - } - - @BeforeClass - public static void beforeClass() throws Exception { - scope = AnalysisScopeReader.readJavaScope(TestConstants.WALA_TESTDATA, (new FileProvider()).getFile("J2SEClassHierarchyExclusions.txt"), MY_CLASSLOADER); - - ClassLoaderFactory factory = new ClassLoaderFactoryImpl(scope.getExclusions() ); - - try { - cha = ClassHierarchy.make(scope, factory); - } catch (ClassHierarchyException e) { - throw new Exception(); - } - } - - @AfterClass - public static void afterClass() throws Exception { - scope = null; - cha = null; - } - - - /** - * Test for subtype tests with interfaces; bug reported by Bruno Dufour - */ - @Test public void test1() { - TypeReference prep_stmt_type = TypeReference.findOrCreate(ClassLoaderReference.Primordial, TypeName - .string2TypeName("Ljava/sql/PreparedStatement")); - TypeReference stmt_type = TypeReference.findOrCreate(ClassLoaderReference.Primordial, TypeName - .string2TypeName("Ljava/sql/Statement")); - IClass prep_stmt = cha.lookupClass(prep_stmt_type); - IClass stmt = cha.lookupClass(stmt_type); - - Assert.assertTrue("did not find PreparedStatement", prep_stmt != null); - Assert.assertTrue("did not find Statement", stmt != null); - - Assert.assertTrue(cha.implementsInterface(prep_stmt, stmt)); - Assert.assertFalse(cha.implementsInterface(stmt, prep_stmt)); - Assert.assertTrue(cha.isAssignableFrom(stmt, prep_stmt)); - Assert.assertFalse(cha.isAssignableFrom(prep_stmt, stmt)); - } - - /** - * check that arrays implement Cloneable and Serializable - */ - @Test public void test2() { - IClass objArrayClass = cha.lookupClass(TypeReference.JavaLangObject.getArrayTypeForElementType()); - IClass stringArrayClass = cha.lookupClass(TypeReference.JavaLangString.getArrayTypeForElementType()); - IClass cloneableClass = cha.lookupClass(TypeReference.JavaLangCloneable); - IClass serializableClass = cha.lookupClass(TypeReference.JavaIoSerializable); - - Assert.assertTrue(cha.implementsInterface(objArrayClass, cloneableClass)); - Assert.assertTrue(cha.implementsInterface(objArrayClass, serializableClass)); - Assert.assertTrue(cha.implementsInterface(stringArrayClass, cloneableClass)); - Assert.assertTrue(cha.implementsInterface(stringArrayClass, serializableClass)); - } - -} +/******************************************************************************* + * Copyright (c) 2007 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.core.tests.cha; + +import org.junit.AfterClass; +import org.junit.Assert; +import org.junit.BeforeClass; +import org.junit.Test; + +import com.ibm.wala.classLoader.ClassLoaderFactory; +import com.ibm.wala.classLoader.ClassLoaderFactoryImpl; +import com.ibm.wala.classLoader.IClass; +import com.ibm.wala.core.tests.util.TestConstants; +import com.ibm.wala.core.tests.util.WalaTestCase; +import com.ibm.wala.ipa.callgraph.AnalysisScope; +import com.ibm.wala.ipa.cha.ClassHierarchy; +import com.ibm.wala.ipa.cha.ClassHierarchyException; +import com.ibm.wala.types.ClassLoaderReference; +import com.ibm.wala.types.TypeName; +import com.ibm.wala.types.TypeReference; +import com.ibm.wala.util.config.AnalysisScopeReader; +import com.ibm.wala.util.io.FileProvider; + +/** + * Test interface subtype stuff + */ +public class InterfaceTest extends WalaTestCase { + + private static final ClassLoader MY_CLASSLOADER = InterfaceTest.class.getClassLoader(); + + private static AnalysisScope scope; + private static ClassHierarchy cha; + + public static void main(String[] args) { + justThisTest(InterfaceTest.class); + } + + @BeforeClass + public static void beforeClass() throws Exception { + scope = AnalysisScopeReader.readJavaScope(TestConstants.WALA_TESTDATA, (new FileProvider()).getFile("J2SEClassHierarchyExclusions.txt"), MY_CLASSLOADER); + + ClassLoaderFactory factory = new ClassLoaderFactoryImpl(scope.getExclusions() ); + + try { + cha = ClassHierarchy.make(scope, factory); + } catch (ClassHierarchyException e) { + throw new Exception(); + } + } + + @AfterClass + public static void afterClass() throws Exception { + scope = null; + cha = null; + } + + + /** + * Test for subtype tests with interfaces; bug reported by Bruno Dufour + */ + @Test public void test1() { + TypeReference prep_stmt_type = TypeReference.findOrCreate(ClassLoaderReference.Primordial, TypeName + .string2TypeName("Ljava/sql/PreparedStatement")); + TypeReference stmt_type = TypeReference.findOrCreate(ClassLoaderReference.Primordial, TypeName + .string2TypeName("Ljava/sql/Statement")); + IClass prep_stmt = cha.lookupClass(prep_stmt_type); + IClass stmt = cha.lookupClass(stmt_type); + + Assert.assertTrue("did not find PreparedStatement", prep_stmt != null); + Assert.assertTrue("did not find Statement", stmt != null); + + Assert.assertTrue(cha.implementsInterface(prep_stmt, stmt)); + Assert.assertFalse(cha.implementsInterface(stmt, prep_stmt)); + Assert.assertTrue(cha.isAssignableFrom(stmt, prep_stmt)); + Assert.assertFalse(cha.isAssignableFrom(prep_stmt, stmt)); + } + + /** + * check that arrays implement Cloneable and Serializable + */ + @Test public void test2() { + IClass objArrayClass = cha.lookupClass(TypeReference.JavaLangObject.getArrayTypeForElementType()); + IClass stringArrayClass = cha.lookupClass(TypeReference.JavaLangString.getArrayTypeForElementType()); + IClass cloneableClass = cha.lookupClass(TypeReference.JavaLangCloneable); + IClass serializableClass = cha.lookupClass(TypeReference.JavaIoSerializable); + + Assert.assertTrue(cha.implementsInterface(objArrayClass, cloneableClass)); + Assert.assertTrue(cha.implementsInterface(objArrayClass, serializableClass)); + Assert.assertTrue(cha.implementsInterface(stringArrayClass, cloneableClass)); + Assert.assertTrue(cha.implementsInterface(stringArrayClass, serializableClass)); + } + +} diff --git a/com.ibm.wala.core.tests/src/com/ibm/wala/core/tests/cha/LibraryVersionTest.java b/com.ibm.wala.core.tests/src/com/ibm/wala/core/tests/cha/LibraryVersionTest.java index d7271a040..e4edc7210 100644 --- a/com.ibm.wala.core.tests/src/com/ibm/wala/core/tests/cha/LibraryVersionTest.java +++ b/com.ibm.wala.core.tests/src/com/ibm/wala/core/tests/cha/LibraryVersionTest.java @@ -1,42 +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.core.tests.cha; - -import java.io.IOException; - -import junit.framework.Assert; - -import org.junit.Test; - -import com.ibm.wala.core.tests.ir.DeterministicIRTest; -import com.ibm.wala.core.tests.util.TestConstants; -import com.ibm.wala.core.tests.util.WalaTestCase; -import com.ibm.wala.ipa.callgraph.AnalysisScope; -import com.ibm.wala.util.config.AnalysisScopeReader; -import com.ibm.wala.util.io.FileProvider; - -/** - * Test code that attempts to find the library version from - * the analysis scope. - * - * @author Julian Dolby (dolby@us.ibm.com) - */ -public class LibraryVersionTest extends WalaTestCase { - - private static final ClassLoader MY_CLASSLOADER = DeterministicIRTest.class.getClassLoader(); - - @Test public void testLibraryVersion() throws IOException { - AnalysisScope scope = AnalysisScopeReader.readJavaScope(TestConstants.WALA_TESTDATA, (new FileProvider()).getFile("J2SEClassHierarchyExclusions.txt"), MY_CLASSLOADER); - System.err.println("java library version is " + scope.getJavaLibraryVersion()); - Assert.assertTrue(scope.isJava17Libraries() || scope.isJava16Libraries() || scope.isJava15Libraries()||scope.isJava14Libraries()); - } - -} +/******************************************************************************* + * 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.core.tests.cha; + +import java.io.IOException; + +import junit.framework.Assert; + +import org.junit.Test; + +import com.ibm.wala.core.tests.ir.DeterministicIRTest; +import com.ibm.wala.core.tests.util.TestConstants; +import com.ibm.wala.core.tests.util.WalaTestCase; +import com.ibm.wala.ipa.callgraph.AnalysisScope; +import com.ibm.wala.util.config.AnalysisScopeReader; +import com.ibm.wala.util.io.FileProvider; + +/** + * Test code that attempts to find the library version from + * the analysis scope. + * + * @author Julian Dolby (dolby@us.ibm.com) + */ +public class LibraryVersionTest extends WalaTestCase { + + private static final ClassLoader MY_CLASSLOADER = DeterministicIRTest.class.getClassLoader(); + + @Test public void testLibraryVersion() throws IOException { + AnalysisScope scope = AnalysisScopeReader.readJavaScope(TestConstants.WALA_TESTDATA, (new FileProvider()).getFile("J2SEClassHierarchyExclusions.txt"), MY_CLASSLOADER); + System.err.println("java library version is " + scope.getJavaLibraryVersion()); + Assert.assertTrue(scope.isJava17Libraries() || scope.isJava16Libraries() || scope.isJava15Libraries()||scope.isJava14Libraries()); + } + +} diff --git a/com.ibm.wala.core.tests/src/com/ibm/wala/core/tests/cha/SourceMapTest.java b/com.ibm.wala.core.tests/src/com/ibm/wala/core/tests/cha/SourceMapTest.java index 39586ea85..4ce8e0eed 100644 --- a/com.ibm.wala.core.tests/src/com/ibm/wala/core/tests/cha/SourceMapTest.java +++ b/com.ibm.wala.core.tests/src/com/ibm/wala/core/tests/cha/SourceMapTest.java @@ -1,62 +1,62 @@ -/******************************************************************************* - * 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.core.tests.cha; - -import java.io.IOException; - -import org.junit.Assert; -import org.junit.Test; - -import com.ibm.wala.classLoader.IClass; -import com.ibm.wala.core.tests.util.TestConstants; -import com.ibm.wala.core.tests.util.WalaTestCase; -import com.ibm.wala.ipa.callgraph.AnalysisScope; -import com.ibm.wala.ipa.cha.ClassHierarchy; -import com.ibm.wala.ipa.cha.ClassHierarchyException; -import com.ibm.wala.types.TypeReference; -import com.ibm.wala.util.config.AnalysisScopeReader; - -/** - * A test of support for source file mapping - */ -public class SourceMapTest extends WalaTestCase { - private static final ClassLoader MY_CLASSLOADER = SourceMapTest.class.getClassLoader(); - - private final static String CLASS_IN_PRIMORDIAL_JAR = "Lcom/ibm/wala/model/SyntheticFactory"; - - @Test public void testHello() throws ClassHierarchyException, IOException { - AnalysisScope scope = null; - scope = AnalysisScopeReader.readJavaScope(TestConstants.HELLO, null, MY_CLASSLOADER); - // TODO: it's annoying to have to build a class hierarchy here. - // see feature 38676 - ClassHierarchy cha = ClassHierarchy.make(scope); - TypeReference t = TypeReference.findOrCreate(scope.getApplicationLoader(), TestConstants.HELLO_MAIN); - IClass klass = cha.lookupClass(t); - Assert.assertTrue("failed to load " + t, klass != null); - String sourceFile = klass.getSourceFileName(); - System.err.println("Source file: " + sourceFile); - Assert.assertTrue(sourceFile != null); - } - - @Test public void testFromJar() throws ClassHierarchyException, IOException { - AnalysisScope scope = null; - scope = AnalysisScopeReader.readJavaScope(TestConstants.HELLO, null, MY_CLASSLOADER); - // TODO: it's annoying to have to build a class hierarchy here. - // open a feature to fix this - ClassHierarchy cha = ClassHierarchy.make(scope); - TypeReference t = TypeReference.findOrCreate(scope.getPrimordialLoader(), CLASS_IN_PRIMORDIAL_JAR); - IClass klass = cha.lookupClass(t); - Assert.assertTrue(klass != null); - String sourceFile = klass.getSourceFileName(); - Assert.assertTrue(sourceFile != null); - System.err.println("Source file: " + sourceFile); - } +/******************************************************************************* + * 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.core.tests.cha; + +import java.io.IOException; + +import org.junit.Assert; +import org.junit.Test; + +import com.ibm.wala.classLoader.IClass; +import com.ibm.wala.core.tests.util.TestConstants; +import com.ibm.wala.core.tests.util.WalaTestCase; +import com.ibm.wala.ipa.callgraph.AnalysisScope; +import com.ibm.wala.ipa.cha.ClassHierarchy; +import com.ibm.wala.ipa.cha.ClassHierarchyException; +import com.ibm.wala.types.TypeReference; +import com.ibm.wala.util.config.AnalysisScopeReader; + +/** + * A test of support for source file mapping + */ +public class SourceMapTest extends WalaTestCase { + private static final ClassLoader MY_CLASSLOADER = SourceMapTest.class.getClassLoader(); + + private final static String CLASS_IN_PRIMORDIAL_JAR = "Lcom/ibm/wala/model/SyntheticFactory"; + + @Test public void testHello() throws ClassHierarchyException, IOException { + AnalysisScope scope = null; + scope = AnalysisScopeReader.readJavaScope(TestConstants.HELLO, null, MY_CLASSLOADER); + // TODO: it's annoying to have to build a class hierarchy here. + // see feature 38676 + ClassHierarchy cha = ClassHierarchy.make(scope); + TypeReference t = TypeReference.findOrCreate(scope.getApplicationLoader(), TestConstants.HELLO_MAIN); + IClass klass = cha.lookupClass(t); + Assert.assertTrue("failed to load " + t, klass != null); + String sourceFile = klass.getSourceFileName(); + System.err.println("Source file: " + sourceFile); + Assert.assertTrue(sourceFile != null); + } + + @Test public void testFromJar() throws ClassHierarchyException, IOException { + AnalysisScope scope = null; + scope = AnalysisScopeReader.readJavaScope(TestConstants.HELLO, null, MY_CLASSLOADER); + // TODO: it's annoying to have to build a class hierarchy here. + // open a feature to fix this + ClassHierarchy cha = ClassHierarchy.make(scope); + TypeReference t = TypeReference.findOrCreate(scope.getPrimordialLoader(), CLASS_IN_PRIMORDIAL_JAR); + IClass klass = cha.lookupClass(t); + Assert.assertTrue(klass != null); + String sourceFile = klass.getSourceFileName(); + Assert.assertTrue(sourceFile != null); + System.err.println("Source file: " + sourceFile); + } } \ No newline at end of file diff --git a/com.ibm.wala.core.tests/src/com/ibm/wala/core/tests/collections/SemiSparseMutableIntSetTest.java b/com.ibm.wala.core.tests/src/com/ibm/wala/core/tests/collections/SemiSparseMutableIntSetTest.java index 6375928e3..21fc11580 100644 --- a/com.ibm.wala.core.tests/src/com/ibm/wala/core/tests/collections/SemiSparseMutableIntSetTest.java +++ b/com.ibm.wala.core.tests/src/com/ibm/wala/core/tests/collections/SemiSparseMutableIntSetTest.java @@ -1,35 +1,35 @@ -/* - * Licensed Materials - Property of IBM - * 5724-D15 - * (C) Copyright IBM Corporation 2008-2009. All Rights Reserved. - * Note to U.S. Government Users Restricted Rights: - * Use, duplication or disclosure restricted by GSA ADP Schedule Contract with IBM Corp. - */ -package com.ibm.wala.core.tests.collections; - -import org.junit.Test; - -import com.ibm.wala.core.tests.util.WalaTestCase; -import com.ibm.wala.util.intset.SemiSparseMutableIntSet; - -/** - * Tests {@link SemiSparseMutableIntSet} class. - * - * @author egeay - */ -public final class SemiSparseMutableIntSetTest extends WalaTestCase { - - public static void main(final String[] args) { - justThisTest(SemiSparseMutableIntSetTest.class); - } - - // --- Test cases - - @Test public void testCase1() { - final SemiSparseMutableIntSet ssmIntSet = new SemiSparseMutableIntSet(); - ssmIntSet.add(1); - final SemiSparseMutableIntSet ssmIntSet2 = SemiSparseMutableIntSet.diff(ssmIntSet, ssmIntSet); - ssmIntSet2.max(); - } - -} +/* + * Licensed Materials - Property of IBM + * 5724-D15 + * (C) Copyright IBM Corporation 2008-2009. All Rights Reserved. + * Note to U.S. Government Users Restricted Rights: + * Use, duplication or disclosure restricted by GSA ADP Schedule Contract with IBM Corp. + */ +package com.ibm.wala.core.tests.collections; + +import org.junit.Test; + +import com.ibm.wala.core.tests.util.WalaTestCase; +import com.ibm.wala.util.intset.SemiSparseMutableIntSet; + +/** + * Tests {@link SemiSparseMutableIntSet} class. + * + * @author egeay + */ +public final class SemiSparseMutableIntSetTest extends WalaTestCase { + + public static void main(final String[] args) { + justThisTest(SemiSparseMutableIntSetTest.class); + } + + // --- Test cases + + @Test public void testCase1() { + final SemiSparseMutableIntSet ssmIntSet = new SemiSparseMutableIntSet(); + ssmIntSet.add(1); + final SemiSparseMutableIntSet ssmIntSet2 = SemiSparseMutableIntSet.diff(ssmIntSet, ssmIntSet); + ssmIntSet2.max(); + } + +} diff --git a/com.ibm.wala.core.tests/src/com/ibm/wala/core/tests/collections/TwoLevelVectorTest.java b/com.ibm.wala.core.tests/src/com/ibm/wala/core/tests/collections/TwoLevelVectorTest.java index 3feb9442b..60f5642b0 100644 --- a/com.ibm.wala.core.tests/src/com/ibm/wala/core/tests/collections/TwoLevelVectorTest.java +++ b/com.ibm.wala.core.tests/src/com/ibm/wala/core/tests/collections/TwoLevelVectorTest.java @@ -1,37 +1,37 @@ -/* - * Licensed Materials - Property of IBM - * 5724-D15 - * (C) Copyright IBM Corporation 2008-2009. All Rights Reserved. - * Note to U.S. Government Users Restricted Rights: - * Use, duplication or disclosure restricted by GSA ADP Schedule Contract with IBM Corp. - */ -package com.ibm.wala.core.tests.collections; - -import org.junit.Assert; -import org.junit.Test; - -import com.ibm.wala.core.tests.util.WalaTestCase; -import com.ibm.wala.util.collections.TwoLevelVector; - -/** - * Tests {@link TwoLevelVector} class. - * - * @author egeay - */ -public final class TwoLevelVectorTest extends WalaTestCase { - - public static void main(final String[] args) { - justThisTest(TwoLevelVectorTest.class); - } - - // --- Test cases - - @Test public void testCase1() { - final TwoLevelVector tlVector = new TwoLevelVector(); - tlVector.iterator(); - tlVector.set(2147483647, 56); - Assert.assertNotNull(tlVector.iterator()); - Assert.assertEquals(Integer.valueOf(56), tlVector.get(2147483647)); - } - -} +/* + * Licensed Materials - Property of IBM + * 5724-D15 + * (C) Copyright IBM Corporation 2008-2009. All Rights Reserved. + * Note to U.S. Government Users Restricted Rights: + * Use, duplication or disclosure restricted by GSA ADP Schedule Contract with IBM Corp. + */ +package com.ibm.wala.core.tests.collections; + +import org.junit.Assert; +import org.junit.Test; + +import com.ibm.wala.core.tests.util.WalaTestCase; +import com.ibm.wala.util.collections.TwoLevelVector; + +/** + * Tests {@link TwoLevelVector} class. + * + * @author egeay + */ +public final class TwoLevelVectorTest extends WalaTestCase { + + public static void main(final String[] args) { + justThisTest(TwoLevelVectorTest.class); + } + + // --- Test cases + + @Test public void testCase1() { + final TwoLevelVector tlVector = new TwoLevelVector(); + tlVector.iterator(); + tlVector.set(2147483647, 56); + Assert.assertNotNull(tlVector.iterator()); + Assert.assertEquals(Integer.valueOf(56), tlVector.get(2147483647)); + } + +} diff --git a/com.ibm.wala.core.tests/src/com/ibm/wala/core/tests/demandpa/AbstractPtrTest.java b/com.ibm.wala.core.tests/src/com/ibm/wala/core/tests/demandpa/AbstractPtrTest.java index d0c90f8d7..2f9367ef9 100644 --- a/com.ibm.wala.core.tests/src/com/ibm/wala/core/tests/demandpa/AbstractPtrTest.java +++ b/com.ibm.wala.core.tests/src/com/ibm/wala/core/tests/demandpa/AbstractPtrTest.java @@ -1,283 +1,283 @@ -/******************************************************************************* - * 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. - * - * This file is a derivative of code released by the University of - * California under the terms listed below. - * - * Refinement Analysis Tools is Copyright (c) 2007 The Regents of the - * University of California (Regents). Provided that this notice and - * the following two paragraphs are included in any distribution of - * Refinement Analysis Tools or its derivative work, Regents agrees - * not to assert any of Regents' copyright rights in Refinement - * Analysis Tools against recipient for recipient's reproduction, - * preparation of derivative works, public display, public - * performance, distribution or sublicensing of Refinement Analysis - * Tools and derivative works, in source code and object code form. - * This agreement not to assert does not confer, by implication, - * estoppel, or otherwise any license or rights in any intellectual - * property of Regents, including, but not limited to, any patents - * of Regents or Regents' employees. - * - * IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, - * INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, - * INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE - * AND ITS DOCUMENTATION, EVEN IF REGENTS HAS BEEN ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE AND FURTHER DISCLAIMS ANY STATUTORY - * WARRANTY OF NON-INFRINGEMENT. THE SOFTWARE AND ACCOMPANYING - * DOCUMENTATION, IF ANY, PROVIDED HEREUNDER IS PROVIDED "AS - * IS". REGENTS HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, - * UPDATES, ENHANCEMENTS, OR MODIFICATIONS. - */ -package com.ibm.wala.core.tests.demandpa; - -import java.io.IOException; -import java.util.Collection; -import java.util.Iterator; - -import org.junit.AfterClass; -import org.junit.Assert; - -import com.ibm.wala.classLoader.IClass; -import com.ibm.wala.classLoader.NewSiteReference; -import com.ibm.wala.core.tests.callGraph.CallGraphTestUtil; -import com.ibm.wala.demandpa.alg.DemandRefinementPointsTo; -import com.ibm.wala.demandpa.alg.statemachine.DummyStateMachine; -import com.ibm.wala.demandpa.alg.statemachine.StateMachineFactory; -import com.ibm.wala.demandpa.flowgraph.IFlowLabel; -import com.ibm.wala.demandpa.util.MemoryAccessMap; -import com.ibm.wala.demandpa.util.PABasedMemoryAccessMap; -import com.ibm.wala.ipa.callgraph.AnalysisCache; -import com.ibm.wala.ipa.callgraph.AnalysisOptions; -import com.ibm.wala.ipa.callgraph.AnalysisScope; -import com.ibm.wala.ipa.callgraph.CGNode; -import com.ibm.wala.ipa.callgraph.CallGraph; -import com.ibm.wala.ipa.callgraph.CallGraphBuilder; -import com.ibm.wala.ipa.callgraph.Entrypoint; -import com.ibm.wala.ipa.callgraph.impl.Util; -import com.ibm.wala.ipa.callgraph.propagation.HeapModel; -import com.ibm.wala.ipa.callgraph.propagation.InstanceKey; -import com.ibm.wala.ipa.callgraph.propagation.PointerKey; -import com.ibm.wala.ipa.callgraph.propagation.SSAPropagationCallGraphBuilder; -import com.ibm.wala.ipa.cha.ClassHierarchy; -import com.ibm.wala.ipa.cha.ClassHierarchyException; -import com.ibm.wala.ipa.cha.IClassHierarchy; -import com.ibm.wala.ssa.IR; -import com.ibm.wala.ssa.SSAInstruction; -import com.ibm.wala.ssa.SSAInvokeInstruction; -import com.ibm.wala.types.ClassLoaderReference; -import com.ibm.wala.types.Descriptor; -import com.ibm.wala.types.TypeReference; -import com.ibm.wala.util.CancelException; -import com.ibm.wala.util.collections.Iterator2Iterable; -import com.ibm.wala.util.debug.Assertions; -import com.ibm.wala.util.intset.IntSet; -import com.ibm.wala.util.strings.Atom; -import com.ibm.wala.util.strings.StringStuff; - -public abstract class AbstractPtrTest { - - protected boolean debug = false; - - /** - * file holding analysis scope specification - */ - protected final String scopeFile; - - protected AbstractPtrTest(String scopeFile) { - this.scopeFile = scopeFile; - } - - private static AnalysisScope cachedScope; - - private static IClassHierarchy cachedCHA; - - public static CGNode findMainMethod(CallGraph cg) { - Descriptor d = Descriptor.findOrCreateUTF8("([Ljava/lang/String;)V"); - Atom name = Atom.findOrCreateUnicodeAtom("main"); - for (Iterator it = cg.getSuccNodes(cg.getFakeRootNode()); it.hasNext();) { - CGNode n = it.next(); - if (n.getMethod().getName().equals(name) && n.getMethod().getDescriptor().equals(d)) { - return n; - } - } - Assertions.UNREACHABLE("failed to find method"); - return null; - } - - public static CGNode findStaticMethod(CallGraph cg, Atom name, Descriptor args) { - for (Iterator it = cg.iterator(); it.hasNext();) { - CGNode n = it.next(); - // System.err.println(n.getMethod().getName() + " " + - // n.getMethod().getDescriptor()); - if (n.getMethod().getName().equals(name) && n.getMethod().getDescriptor().equals(args)) { - return n; - } - } - Assertions.UNREACHABLE("failed to find method"); - return null; - } - - public static CGNode findInstanceMethod(CallGraph cg, IClass declaringClass, Atom name, Descriptor args) { - for (Iterator it = cg.iterator(); it.hasNext();) { - CGNode n = it.next(); - // System.err.println(n.getMethod().getDeclaringClass() + " " + - // n.getMethod().getName() + " " + n.getMethod().getDescriptor()); - if (n.getMethod().getDeclaringClass().equals(declaringClass) && n.getMethod().getName().equals(name) - && n.getMethod().getDescriptor().equals(args)) { - return n; - } - } - Assertions.UNREACHABLE("failed to find method"); - return null; - } - - public static PointerKey getParam(CGNode n, String methodName, HeapModel heapModel) { - IR ir = n.getIR(); - for (Iterator it = ir.iterateAllInstructions(); it.hasNext();) { - SSAInstruction s = it.next(); - if (s instanceof SSAInvokeInstruction) { - SSAInvokeInstruction call = (SSAInvokeInstruction) s; - if (call.getCallSite().getDeclaredTarget().getName().toString().equals(methodName)) { - IntSet indices = ir.getCallInstructionIndices(((SSAInvokeInstruction) s).getCallSite()); - Assertions.productionAssertion(indices.size() == 1, "expected 1 but got " + indices.size()); - SSAInstruction callInstr = ir.getInstructions()[indices.intIterator().next()]; - Assertions.productionAssertion(callInstr.getNumberOfUses() == 1, "multiple uses for call"); - return heapModel.getPointerKeyForLocal(n, callInstr.getUse(0)); - } - } - } - Assertions.UNREACHABLE("failed to find call to " + methodName + " in " + n); - return null; - } - - - protected void doFlowsToSizeTest(String mainClass, int size) throws ClassHierarchyException, IllegalArgumentException, - CancelException, IOException { - Collection flowsTo = getFlowsToSetToTest(mainClass); - if (debug) { - System.err.println("flows-to for " + mainClass + ": " + flowsTo); - } - Assert.assertEquals(size, flowsTo.size()); - } - - private Collection getFlowsToSetToTest(String mainClass) throws ClassHierarchyException, IllegalArgumentException, - CancelException, IOException { - final DemandRefinementPointsTo dmp = makeDemandPointerAnalysis(mainClass); - - // find the single allocation site of FlowsToType, make an InstanceKey, and - // query it - CGNode mainMethod = AbstractPtrTest.findMainMethod(dmp.getBaseCallGraph()); - InstanceKey keyToQuery = getFlowsToInstanceKey(mainMethod, dmp.getHeapModel()); - Collection flowsTo = dmp.getFlowsTo(keyToQuery).snd; - return flowsTo; - } - - /** - * returns the instance key corresponding to the single allocation site of - * type FlowsToType - */ - private InstanceKey getFlowsToInstanceKey(CGNode mainMethod, HeapModel heapModel) { - // TODO Auto-generated method stub - TypeReference flowsToTypeRef = TypeReference.findOrCreate(ClassLoaderReference.Application, - StringStuff.deployment2CanonicalTypeString("demandpa.FlowsToType")); - final IR mainIR = mainMethod.getIR(); - if (debug) { - System.err.println(mainIR); - } - for (NewSiteReference n : Iterator2Iterable.make(mainIR.iterateNewSites())) { - if (n.getDeclaredType().equals(flowsToTypeRef)) { - return heapModel.getInstanceKeyForAllocation(mainMethod, n); - } - } - assert false : "could not find appropriate allocation"; - return null; - } - - protected void doPointsToSizeTest(String mainClass, int expectedSize) throws ClassHierarchyException, IllegalArgumentException, - CancelException, IOException { - Collection pointsTo = getPointsToSetToTest(mainClass); - if (debug) { - System.err.println("points-to for " + mainClass + ": " + pointsTo); - } - Assert.assertEquals(expectedSize, pointsTo.size()); - } - - private Collection getPointsToSetToTest(String mainClass) throws ClassHierarchyException, IllegalArgumentException, - CancelException, IOException { - final DemandRefinementPointsTo dmp = makeDemandPointerAnalysis(mainClass); - - // find the testThisVar call, and check the parameter's points-to set - CGNode mainMethod = AbstractPtrTest.findMainMethod(dmp.getBaseCallGraph()); - PointerKey keyToQuery = AbstractPtrTest.getParam(mainMethod, "testThisVar", dmp.getHeapModel()); - Collection pointsTo = dmp.getPointsTo(keyToQuery); - return pointsTo; - } - - protected DemandRefinementPointsTo makeDemandPointerAnalysis(String mainClass) throws ClassHierarchyException, - IllegalArgumentException, CancelException, IOException { - AnalysisScope scope = findOrCreateAnalysisScope(); - // build a type hierarchy - IClassHierarchy cha = findOrCreateCHA(scope); - - // set up call graph construction options; mainly what should be considered - // entrypoints? - Iterable entrypoints = com.ibm.wala.ipa.callgraph.impl.Util.makeMainEntrypoints(scope, cha, mainClass); - AnalysisOptions options = CallGraphTestUtil.makeAnalysisOptions(scope, entrypoints); - - final AnalysisCache analysisCache = new AnalysisCache(); - CallGraphBuilder cgBuilder = Util.makeZeroCFABuilder(options, analysisCache, cha, scope); - final CallGraph cg = cgBuilder.makeCallGraph(options, null); - // System.err.println(cg.toString()); - - // MemoryAccessMap mam = new SimpleMemoryAccessMap(cg, - // cgBuilder.getPointerAnalysis().getHeapModel(), false); - MemoryAccessMap mam = new PABasedMemoryAccessMap(cg, cgBuilder.getPointerAnalysis()); - SSAPropagationCallGraphBuilder builder = Util.makeVanillaZeroOneCFABuilder(options, analysisCache, cha, scope); - DemandRefinementPointsTo fullDemandPointsTo = DemandRefinementPointsTo.makeWithDefaultFlowGraph(cg, builder, mam, cha, options, - getStateMachineFactory()); - - return fullDemandPointsTo; - } - - /** - * @param scope - * @return - * @throws ClassHierarchyException - */ - private IClassHierarchy findOrCreateCHA(AnalysisScope scope) throws ClassHierarchyException { - if (cachedCHA == null) { - cachedCHA = ClassHierarchy.make(scope); - } - return cachedCHA; - } - - /** - * @param scopeFile - * @return - * @throws IOException - */ - private AnalysisScope findOrCreateAnalysisScope() throws IOException { - if (cachedScope == null) { - cachedScope = CallGraphTestUtil.makeJ2SEAnalysisScope(scopeFile, CallGraphTestUtil.REGRESSION_EXCLUSIONS); - } - return cachedScope; - } - - @AfterClass - public static void cleanup() { - cachedScope = null; - cachedCHA = null; - } - - protected StateMachineFactory getStateMachineFactory() { - return new DummyStateMachine.Factory(); - } - -} +/******************************************************************************* + * 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. + * + * This file is a derivative of code released by the University of + * California under the terms listed below. + * + * Refinement Analysis Tools is Copyright (c) 2007 The Regents of the + * University of California (Regents). Provided that this notice and + * the following two paragraphs are included in any distribution of + * Refinement Analysis Tools or its derivative work, Regents agrees + * not to assert any of Regents' copyright rights in Refinement + * Analysis Tools against recipient for recipient's reproduction, + * preparation of derivative works, public display, public + * performance, distribution or sublicensing of Refinement Analysis + * Tools and derivative works, in source code and object code form. + * This agreement not to assert does not confer, by implication, + * estoppel, or otherwise any license or rights in any intellectual + * property of Regents, including, but not limited to, any patents + * of Regents or Regents' employees. + * + * IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, + * INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, + * INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE + * AND ITS DOCUMENTATION, EVEN IF REGENTS HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE AND FURTHER DISCLAIMS ANY STATUTORY + * WARRANTY OF NON-INFRINGEMENT. THE SOFTWARE AND ACCOMPANYING + * DOCUMENTATION, IF ANY, PROVIDED HEREUNDER IS PROVIDED "AS + * IS". REGENTS HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, + * UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + */ +package com.ibm.wala.core.tests.demandpa; + +import java.io.IOException; +import java.util.Collection; +import java.util.Iterator; + +import org.junit.AfterClass; +import org.junit.Assert; + +import com.ibm.wala.classLoader.IClass; +import com.ibm.wala.classLoader.NewSiteReference; +import com.ibm.wala.core.tests.callGraph.CallGraphTestUtil; +import com.ibm.wala.demandpa.alg.DemandRefinementPointsTo; +import com.ibm.wala.demandpa.alg.statemachine.DummyStateMachine; +import com.ibm.wala.demandpa.alg.statemachine.StateMachineFactory; +import com.ibm.wala.demandpa.flowgraph.IFlowLabel; +import com.ibm.wala.demandpa.util.MemoryAccessMap; +import com.ibm.wala.demandpa.util.PABasedMemoryAccessMap; +import com.ibm.wala.ipa.callgraph.AnalysisCache; +import com.ibm.wala.ipa.callgraph.AnalysisOptions; +import com.ibm.wala.ipa.callgraph.AnalysisScope; +import com.ibm.wala.ipa.callgraph.CGNode; +import com.ibm.wala.ipa.callgraph.CallGraph; +import com.ibm.wala.ipa.callgraph.CallGraphBuilder; +import com.ibm.wala.ipa.callgraph.Entrypoint; +import com.ibm.wala.ipa.callgraph.impl.Util; +import com.ibm.wala.ipa.callgraph.propagation.HeapModel; +import com.ibm.wala.ipa.callgraph.propagation.InstanceKey; +import com.ibm.wala.ipa.callgraph.propagation.PointerKey; +import com.ibm.wala.ipa.callgraph.propagation.SSAPropagationCallGraphBuilder; +import com.ibm.wala.ipa.cha.ClassHierarchy; +import com.ibm.wala.ipa.cha.ClassHierarchyException; +import com.ibm.wala.ipa.cha.IClassHierarchy; +import com.ibm.wala.ssa.IR; +import com.ibm.wala.ssa.SSAInstruction; +import com.ibm.wala.ssa.SSAInvokeInstruction; +import com.ibm.wala.types.ClassLoaderReference; +import com.ibm.wala.types.Descriptor; +import com.ibm.wala.types.TypeReference; +import com.ibm.wala.util.CancelException; +import com.ibm.wala.util.collections.Iterator2Iterable; +import com.ibm.wala.util.debug.Assertions; +import com.ibm.wala.util.intset.IntSet; +import com.ibm.wala.util.strings.Atom; +import com.ibm.wala.util.strings.StringStuff; + +public abstract class AbstractPtrTest { + + protected boolean debug = false; + + /** + * file holding analysis scope specification + */ + protected final String scopeFile; + + protected AbstractPtrTest(String scopeFile) { + this.scopeFile = scopeFile; + } + + private static AnalysisScope cachedScope; + + private static IClassHierarchy cachedCHA; + + public static CGNode findMainMethod(CallGraph cg) { + Descriptor d = Descriptor.findOrCreateUTF8("([Ljava/lang/String;)V"); + Atom name = Atom.findOrCreateUnicodeAtom("main"); + for (Iterator it = cg.getSuccNodes(cg.getFakeRootNode()); it.hasNext();) { + CGNode n = it.next(); + if (n.getMethod().getName().equals(name) && n.getMethod().getDescriptor().equals(d)) { + return n; + } + } + Assertions.UNREACHABLE("failed to find method"); + return null; + } + + public static CGNode findStaticMethod(CallGraph cg, Atom name, Descriptor args) { + for (Iterator it = cg.iterator(); it.hasNext();) { + CGNode n = it.next(); + // System.err.println(n.getMethod().getName() + " " + + // n.getMethod().getDescriptor()); + if (n.getMethod().getName().equals(name) && n.getMethod().getDescriptor().equals(args)) { + return n; + } + } + Assertions.UNREACHABLE("failed to find method"); + return null; + } + + public static CGNode findInstanceMethod(CallGraph cg, IClass declaringClass, Atom name, Descriptor args) { + for (Iterator it = cg.iterator(); it.hasNext();) { + CGNode n = it.next(); + // System.err.println(n.getMethod().getDeclaringClass() + " " + + // n.getMethod().getName() + " " + n.getMethod().getDescriptor()); + if (n.getMethod().getDeclaringClass().equals(declaringClass) && n.getMethod().getName().equals(name) + && n.getMethod().getDescriptor().equals(args)) { + return n; + } + } + Assertions.UNREACHABLE("failed to find method"); + return null; + } + + public static PointerKey getParam(CGNode n, String methodName, HeapModel heapModel) { + IR ir = n.getIR(); + for (Iterator it = ir.iterateAllInstructions(); it.hasNext();) { + SSAInstruction s = it.next(); + if (s instanceof SSAInvokeInstruction) { + SSAInvokeInstruction call = (SSAInvokeInstruction) s; + if (call.getCallSite().getDeclaredTarget().getName().toString().equals(methodName)) { + IntSet indices = ir.getCallInstructionIndices(((SSAInvokeInstruction) s).getCallSite()); + Assertions.productionAssertion(indices.size() == 1, "expected 1 but got " + indices.size()); + SSAInstruction callInstr = ir.getInstructions()[indices.intIterator().next()]; + Assertions.productionAssertion(callInstr.getNumberOfUses() == 1, "multiple uses for call"); + return heapModel.getPointerKeyForLocal(n, callInstr.getUse(0)); + } + } + } + Assertions.UNREACHABLE("failed to find call to " + methodName + " in " + n); + return null; + } + + + protected void doFlowsToSizeTest(String mainClass, int size) throws ClassHierarchyException, IllegalArgumentException, + CancelException, IOException { + Collection flowsTo = getFlowsToSetToTest(mainClass); + if (debug) { + System.err.println("flows-to for " + mainClass + ": " + flowsTo); + } + Assert.assertEquals(size, flowsTo.size()); + } + + private Collection getFlowsToSetToTest(String mainClass) throws ClassHierarchyException, IllegalArgumentException, + CancelException, IOException { + final DemandRefinementPointsTo dmp = makeDemandPointerAnalysis(mainClass); + + // find the single allocation site of FlowsToType, make an InstanceKey, and + // query it + CGNode mainMethod = AbstractPtrTest.findMainMethod(dmp.getBaseCallGraph()); + InstanceKey keyToQuery = getFlowsToInstanceKey(mainMethod, dmp.getHeapModel()); + Collection flowsTo = dmp.getFlowsTo(keyToQuery).snd; + return flowsTo; + } + + /** + * returns the instance key corresponding to the single allocation site of + * type FlowsToType + */ + private InstanceKey getFlowsToInstanceKey(CGNode mainMethod, HeapModel heapModel) { + // TODO Auto-generated method stub + TypeReference flowsToTypeRef = TypeReference.findOrCreate(ClassLoaderReference.Application, + StringStuff.deployment2CanonicalTypeString("demandpa.FlowsToType")); + final IR mainIR = mainMethod.getIR(); + if (debug) { + System.err.println(mainIR); + } + for (NewSiteReference n : Iterator2Iterable.make(mainIR.iterateNewSites())) { + if (n.getDeclaredType().equals(flowsToTypeRef)) { + return heapModel.getInstanceKeyForAllocation(mainMethod, n); + } + } + assert false : "could not find appropriate allocation"; + return null; + } + + protected void doPointsToSizeTest(String mainClass, int expectedSize) throws ClassHierarchyException, IllegalArgumentException, + CancelException, IOException { + Collection pointsTo = getPointsToSetToTest(mainClass); + if (debug) { + System.err.println("points-to for " + mainClass + ": " + pointsTo); + } + Assert.assertEquals(expectedSize, pointsTo.size()); + } + + private Collection getPointsToSetToTest(String mainClass) throws ClassHierarchyException, IllegalArgumentException, + CancelException, IOException { + final DemandRefinementPointsTo dmp = makeDemandPointerAnalysis(mainClass); + + // find the testThisVar call, and check the parameter's points-to set + CGNode mainMethod = AbstractPtrTest.findMainMethod(dmp.getBaseCallGraph()); + PointerKey keyToQuery = AbstractPtrTest.getParam(mainMethod, "testThisVar", dmp.getHeapModel()); + Collection pointsTo = dmp.getPointsTo(keyToQuery); + return pointsTo; + } + + protected DemandRefinementPointsTo makeDemandPointerAnalysis(String mainClass) throws ClassHierarchyException, + IllegalArgumentException, CancelException, IOException { + AnalysisScope scope = findOrCreateAnalysisScope(); + // build a type hierarchy + IClassHierarchy cha = findOrCreateCHA(scope); + + // set up call graph construction options; mainly what should be considered + // entrypoints? + Iterable entrypoints = com.ibm.wala.ipa.callgraph.impl.Util.makeMainEntrypoints(scope, cha, mainClass); + AnalysisOptions options = CallGraphTestUtil.makeAnalysisOptions(scope, entrypoints); + + final AnalysisCache analysisCache = new AnalysisCache(); + CallGraphBuilder cgBuilder = Util.makeZeroCFABuilder(options, analysisCache, cha, scope); + final CallGraph cg = cgBuilder.makeCallGraph(options, null); + // System.err.println(cg.toString()); + + // MemoryAccessMap mam = new SimpleMemoryAccessMap(cg, + // cgBuilder.getPointerAnalysis().getHeapModel(), false); + MemoryAccessMap mam = new PABasedMemoryAccessMap(cg, cgBuilder.getPointerAnalysis()); + SSAPropagationCallGraphBuilder builder = Util.makeVanillaZeroOneCFABuilder(options, analysisCache, cha, scope); + DemandRefinementPointsTo fullDemandPointsTo = DemandRefinementPointsTo.makeWithDefaultFlowGraph(cg, builder, mam, cha, options, + getStateMachineFactory()); + + return fullDemandPointsTo; + } + + /** + * @param scope + * @return + * @throws ClassHierarchyException + */ + private IClassHierarchy findOrCreateCHA(AnalysisScope scope) throws ClassHierarchyException { + if (cachedCHA == null) { + cachedCHA = ClassHierarchy.make(scope); + } + return cachedCHA; + } + + /** + * @param scopeFile + * @return + * @throws IOException + */ + private AnalysisScope findOrCreateAnalysisScope() throws IOException { + if (cachedScope == null) { + cachedScope = CallGraphTestUtil.makeJ2SEAnalysisScope(scopeFile, CallGraphTestUtil.REGRESSION_EXCLUSIONS); + } + return cachedScope; + } + + @AfterClass + public static void cleanup() { + cachedScope = null; + cachedCHA = null; + } + + protected StateMachineFactory getStateMachineFactory() { + return new DummyStateMachine.Factory(); + } + +} diff --git a/com.ibm.wala.core.tests/src/com/ibm/wala/core/tests/demandpa/ContextSensitiveTest.java b/com.ibm.wala.core.tests/src/com/ibm/wala/core/tests/demandpa/ContextSensitiveTest.java index a2c60ddaf..a9c043292 100644 --- a/com.ibm.wala.core.tests/src/com/ibm/wala/core/tests/demandpa/ContextSensitiveTest.java +++ b/com.ibm.wala.core.tests/src/com/ibm/wala/core/tests/demandpa/ContextSensitiveTest.java @@ -1,185 +1,185 @@ -/******************************************************************************* - * 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. - * - * This file is a derivative of code released by the University of - * California under the terms listed below. - * - * Refinement Analysis Tools is Copyright (c) 2007 The Regents of the - * University of California (Regents). Provided that this notice and - * the following two paragraphs are included in any distribution of - * Refinement Analysis Tools or its derivative work, Regents agrees - * not to assert any of Regents' copyright rights in Refinement - * Analysis Tools against recipient for recipient's reproduction, - * preparation of derivative works, public display, public - * performance, distribution or sublicensing of Refinement Analysis - * Tools and derivative works, in source code and object code form. - * This agreement not to assert does not confer, by implication, - * estoppel, or otherwise any license or rights in any intellectual - * property of Regents, including, but not limited to, any patents - * of Regents or Regents' employees. - * - * IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, - * INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, - * INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE - * AND ITS DOCUMENTATION, EVEN IF REGENTS HAS BEEN ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE AND FURTHER DISCLAIMS ANY STATUTORY - * WARRANTY OF NON-INFRINGEMENT. THE SOFTWARE AND ACCOMPANYING - * DOCUMENTATION, IF ANY, PROVIDED HEREUNDER IS PROVIDED "AS - * IS". REGENTS HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, - * UPDATES, ENHANCEMENTS, OR MODIFICATIONS. - */ -package com.ibm.wala.core.tests.demandpa; - -import java.io.IOException; -import java.util.Collection; - -import org.junit.Assert; -import org.junit.Ignore; -import org.junit.Test; - -import com.ibm.wala.demandpa.alg.ContextSensitiveStateMachine; -import com.ibm.wala.demandpa.alg.DemandRefinementPointsTo; -import com.ibm.wala.demandpa.alg.IDemandPointerAnalysis; -import com.ibm.wala.demandpa.alg.refinepolicy.AlwaysRefineCGPolicy; -import com.ibm.wala.demandpa.alg.refinepolicy.AlwaysRefineFieldsPolicy; -import com.ibm.wala.demandpa.alg.refinepolicy.SinglePassRefinementPolicy; -import com.ibm.wala.demandpa.alg.statemachine.StateMachineFactory; -import com.ibm.wala.demandpa.flowgraph.IFlowLabel; -import com.ibm.wala.ipa.callgraph.CGNode; -import com.ibm.wala.ipa.callgraph.propagation.InstanceKey; -import com.ibm.wala.ipa.callgraph.propagation.PointerKey; -import com.ibm.wala.ipa.cha.ClassHierarchyException; -import com.ibm.wala.types.ClassLoaderReference; -import com.ibm.wala.types.Descriptor; -import com.ibm.wala.types.TypeReference; -import com.ibm.wala.util.CancelException; -import com.ibm.wala.util.strings.Atom; - -public class ContextSensitiveTest extends AbstractPtrTest { - - public ContextSensitiveTest() { - super(TestInfo.SCOPE_FILE); - } - - @Test - public void testArraySet() throws ClassHierarchyException, IllegalArgumentException, CancelException, IOException { - doPointsToSizeTest(TestInfo.TEST_ARRAY_SET, 1); - } - - @Test - public void testClone() throws ClassHierarchyException, IllegalArgumentException, CancelException, IOException { - doPointsToSizeTest(TestInfo.TEST_CLONE, 1); - } - - @Test - public void testFooId() throws ClassHierarchyException, IllegalArgumentException, CancelException, IOException { - doPointsToSizeTest(TestInfo.TEST_ID, 1); - } - - @Test - public void testHashtableEnum() throws ClassHierarchyException, IllegalArgumentException, CancelException, IOException { - // 3 because - // can't tell between key and value enumerators in Hashtable - doPointsToSizeTest(TestInfo.TEST_HASHTABLE_ENUM, 2); - } - - @Ignore("support for this combination of context sensitivity and on-the-fly call graph refinement is not yet implemented") - @Test - public void testOnTheFlyCS() throws ClassHierarchyException, IllegalArgumentException, CancelException, IOException { - String mainClass = TestInfo.TEST_ONTHEFLY_CS; - final IDemandPointerAnalysis dmp = makeDemandPointerAnalysis(mainClass); - CGNode testMethod = AbstractPtrTest.findInstanceMethod( - dmp.getBaseCallGraph(), - dmp.getClassHierarchy().lookupClass( - TypeReference.findOrCreate(ClassLoaderReference.Application, "Ldemandpa/TestOnTheFlyCS$C2")), - Atom.findOrCreateUnicodeAtom("doSomething"), Descriptor.findOrCreateUTF8("(Ljava/lang/Object;)V")); - PointerKey keyToQuery = AbstractPtrTest.getParam(testMethod, "testThisVar", dmp.getHeapModel()); - Collection pointsTo = dmp.getPointsTo(keyToQuery); - if (debug) { - System.err.println("points-to for " + mainClass + ": " + pointsTo); - } - Assert.assertEquals(1, pointsTo.size()); - } - - @Test - public void testWithinMethodCall() throws ClassHierarchyException, IllegalArgumentException, CancelException, IOException { - String mainClass = TestInfo.TEST_WITHIN_METHOD_CALL; - final IDemandPointerAnalysis dmp = makeDemandPointerAnalysis(mainClass); - - CGNode testMethod = AbstractPtrTest.findStaticMethod(dmp.getBaseCallGraph(), Atom.findOrCreateUnicodeAtom("testMethod"), - Descriptor.findOrCreateUTF8("(Ljava/lang/Object;)V")); - PointerKey keyToQuery = AbstractPtrTest.getParam(testMethod, "testThisVar", dmp.getHeapModel()); - Collection pointsTo = dmp.getPointsTo(keyToQuery); - if (debug) { - System.err.println("points-to for " + mainClass + ": " + pointsTo); - } - Assert.assertEquals(1, pointsTo.size()); - } - - @Test - public void testLinkedListIter() throws ClassHierarchyException, IllegalArgumentException, CancelException, IOException { - doPointsToSizeTest(TestInfo.TEST_LINKEDLIST_ITER, 1); - } - - @Test - public void testGlobal() throws ClassHierarchyException, IllegalArgumentException, CancelException, IOException { - doPointsToSizeTest(TestInfo.TEST_GLOBAL, 1); - } - - @Test - public void testHashSet() throws ClassHierarchyException, IllegalArgumentException, CancelException, IOException { - doPointsToSizeTest(TestInfo.TEST_HASH_SET, 1); - } - - @Test - public void testHashMapGet() throws ClassHierarchyException, IllegalArgumentException, CancelException, IOException { - doPointsToSizeTest(TestInfo.TEST_HASHMAP_GET, 1); - } - - @Test - public void testMethodRecursion() throws ClassHierarchyException, IllegalArgumentException, CancelException, IOException { - doPointsToSizeTest(TestInfo.TEST_METHOD_RECURSION, 2); - } - - @Test - public void testArraySetIter() throws ClassHierarchyException, IllegalArgumentException, CancelException, IOException { - doPointsToSizeTest(TestInfo.TEST_ARRAY_SET_ITER, 1); - } - - @Test - public void testArrayList() throws ClassHierarchyException, IllegalArgumentException, CancelException, IOException { - doPointsToSizeTest(TestInfo.TEST_ARRAY_LIST, 1); - } - - @Test - public void testLinkedList() throws ClassHierarchyException, IllegalArgumentException, CancelException, IOException { - doPointsToSizeTest(TestInfo.TEST_LINKED_LIST, 1); - } - - @Test - public void testFlowsToArraySetIter() throws ClassHierarchyException, IllegalArgumentException, CancelException, IOException { - doFlowsToSizeTest(TestInfo.FLOWSTO_TEST_ARRAYSET_ITER, 7); - } - - @Override - protected StateMachineFactory getStateMachineFactory() { - return new ContextSensitiveStateMachine.Factory(); - } - - @Override - protected DemandRefinementPointsTo makeDemandPointerAnalysis(String mainClass) throws ClassHierarchyException, - IllegalArgumentException, CancelException, IOException { - DemandRefinementPointsTo dmp = super.makeDemandPointerAnalysis(mainClass); - dmp.setRefinementPolicyFactory(new SinglePassRefinementPolicy.Factory(new AlwaysRefineFieldsPolicy(), - new AlwaysRefineCGPolicy())); - return dmp; - } - -} +/******************************************************************************* + * 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. + * + * This file is a derivative of code released by the University of + * California under the terms listed below. + * + * Refinement Analysis Tools is Copyright (c) 2007 The Regents of the + * University of California (Regents). Provided that this notice and + * the following two paragraphs are included in any distribution of + * Refinement Analysis Tools or its derivative work, Regents agrees + * not to assert any of Regents' copyright rights in Refinement + * Analysis Tools against recipient for recipient's reproduction, + * preparation of derivative works, public display, public + * performance, distribution or sublicensing of Refinement Analysis + * Tools and derivative works, in source code and object code form. + * This agreement not to assert does not confer, by implication, + * estoppel, or otherwise any license or rights in any intellectual + * property of Regents, including, but not limited to, any patents + * of Regents or Regents' employees. + * + * IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, + * INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, + * INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE + * AND ITS DOCUMENTATION, EVEN IF REGENTS HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE AND FURTHER DISCLAIMS ANY STATUTORY + * WARRANTY OF NON-INFRINGEMENT. THE SOFTWARE AND ACCOMPANYING + * DOCUMENTATION, IF ANY, PROVIDED HEREUNDER IS PROVIDED "AS + * IS". REGENTS HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, + * UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + */ +package com.ibm.wala.core.tests.demandpa; + +import java.io.IOException; +import java.util.Collection; + +import org.junit.Assert; +import org.junit.Ignore; +import org.junit.Test; + +import com.ibm.wala.demandpa.alg.ContextSensitiveStateMachine; +import com.ibm.wala.demandpa.alg.DemandRefinementPointsTo; +import com.ibm.wala.demandpa.alg.IDemandPointerAnalysis; +import com.ibm.wala.demandpa.alg.refinepolicy.AlwaysRefineCGPolicy; +import com.ibm.wala.demandpa.alg.refinepolicy.AlwaysRefineFieldsPolicy; +import com.ibm.wala.demandpa.alg.refinepolicy.SinglePassRefinementPolicy; +import com.ibm.wala.demandpa.alg.statemachine.StateMachineFactory; +import com.ibm.wala.demandpa.flowgraph.IFlowLabel; +import com.ibm.wala.ipa.callgraph.CGNode; +import com.ibm.wala.ipa.callgraph.propagation.InstanceKey; +import com.ibm.wala.ipa.callgraph.propagation.PointerKey; +import com.ibm.wala.ipa.cha.ClassHierarchyException; +import com.ibm.wala.types.ClassLoaderReference; +import com.ibm.wala.types.Descriptor; +import com.ibm.wala.types.TypeReference; +import com.ibm.wala.util.CancelException; +import com.ibm.wala.util.strings.Atom; + +public class ContextSensitiveTest extends AbstractPtrTest { + + public ContextSensitiveTest() { + super(TestInfo.SCOPE_FILE); + } + + @Test + public void testArraySet() throws ClassHierarchyException, IllegalArgumentException, CancelException, IOException { + doPointsToSizeTest(TestInfo.TEST_ARRAY_SET, 1); + } + + @Test + public void testClone() throws ClassHierarchyException, IllegalArgumentException, CancelException, IOException { + doPointsToSizeTest(TestInfo.TEST_CLONE, 1); + } + + @Test + public void testFooId() throws ClassHierarchyException, IllegalArgumentException, CancelException, IOException { + doPointsToSizeTest(TestInfo.TEST_ID, 1); + } + + @Test + public void testHashtableEnum() throws ClassHierarchyException, IllegalArgumentException, CancelException, IOException { + // 3 because + // can't tell between key and value enumerators in Hashtable + doPointsToSizeTest(TestInfo.TEST_HASHTABLE_ENUM, 2); + } + + @Ignore("support for this combination of context sensitivity and on-the-fly call graph refinement is not yet implemented") + @Test + public void testOnTheFlyCS() throws ClassHierarchyException, IllegalArgumentException, CancelException, IOException { + String mainClass = TestInfo.TEST_ONTHEFLY_CS; + final IDemandPointerAnalysis dmp = makeDemandPointerAnalysis(mainClass); + CGNode testMethod = AbstractPtrTest.findInstanceMethod( + dmp.getBaseCallGraph(), + dmp.getClassHierarchy().lookupClass( + TypeReference.findOrCreate(ClassLoaderReference.Application, "Ldemandpa/TestOnTheFlyCS$C2")), + Atom.findOrCreateUnicodeAtom("doSomething"), Descriptor.findOrCreateUTF8("(Ljava/lang/Object;)V")); + PointerKey keyToQuery = AbstractPtrTest.getParam(testMethod, "testThisVar", dmp.getHeapModel()); + Collection pointsTo = dmp.getPointsTo(keyToQuery); + if (debug) { + System.err.println("points-to for " + mainClass + ": " + pointsTo); + } + Assert.assertEquals(1, pointsTo.size()); + } + + @Test + public void testWithinMethodCall() throws ClassHierarchyException, IllegalArgumentException, CancelException, IOException { + String mainClass = TestInfo.TEST_WITHIN_METHOD_CALL; + final IDemandPointerAnalysis dmp = makeDemandPointerAnalysis(mainClass); + + CGNode testMethod = AbstractPtrTest.findStaticMethod(dmp.getBaseCallGraph(), Atom.findOrCreateUnicodeAtom("testMethod"), + Descriptor.findOrCreateUTF8("(Ljava/lang/Object;)V")); + PointerKey keyToQuery = AbstractPtrTest.getParam(testMethod, "testThisVar", dmp.getHeapModel()); + Collection pointsTo = dmp.getPointsTo(keyToQuery); + if (debug) { + System.err.println("points-to for " + mainClass + ": " + pointsTo); + } + Assert.assertEquals(1, pointsTo.size()); + } + + @Test + public void testLinkedListIter() throws ClassHierarchyException, IllegalArgumentException, CancelException, IOException { + doPointsToSizeTest(TestInfo.TEST_LINKEDLIST_ITER, 1); + } + + @Test + public void testGlobal() throws ClassHierarchyException, IllegalArgumentException, CancelException, IOException { + doPointsToSizeTest(TestInfo.TEST_GLOBAL, 1); + } + + @Test + public void testHashSet() throws ClassHierarchyException, IllegalArgumentException, CancelException, IOException { + doPointsToSizeTest(TestInfo.TEST_HASH_SET, 1); + } + + @Test + public void testHashMapGet() throws ClassHierarchyException, IllegalArgumentException, CancelException, IOException { + doPointsToSizeTest(TestInfo.TEST_HASHMAP_GET, 1); + } + + @Test + public void testMethodRecursion() throws ClassHierarchyException, IllegalArgumentException, CancelException, IOException { + doPointsToSizeTest(TestInfo.TEST_METHOD_RECURSION, 2); + } + + @Test + public void testArraySetIter() throws ClassHierarchyException, IllegalArgumentException, CancelException, IOException { + doPointsToSizeTest(TestInfo.TEST_ARRAY_SET_ITER, 1); + } + + @Test + public void testArrayList() throws ClassHierarchyException, IllegalArgumentException, CancelException, IOException { + doPointsToSizeTest(TestInfo.TEST_ARRAY_LIST, 1); + } + + @Test + public void testLinkedList() throws ClassHierarchyException, IllegalArgumentException, CancelException, IOException { + doPointsToSizeTest(TestInfo.TEST_LINKED_LIST, 1); + } + + @Test + public void testFlowsToArraySetIter() throws ClassHierarchyException, IllegalArgumentException, CancelException, IOException { + doFlowsToSizeTest(TestInfo.FLOWSTO_TEST_ARRAYSET_ITER, 7); + } + + @Override + protected StateMachineFactory getStateMachineFactory() { + return new ContextSensitiveStateMachine.Factory(); + } + + @Override + protected DemandRefinementPointsTo makeDemandPointerAnalysis(String mainClass) throws ClassHierarchyException, + IllegalArgumentException, CancelException, IOException { + DemandRefinementPointsTo dmp = super.makeDemandPointerAnalysis(mainClass); + dmp.setRefinementPolicyFactory(new SinglePassRefinementPolicy.Factory(new AlwaysRefineFieldsPolicy(), + new AlwaysRefineCGPolicy())); + return dmp; + } + +} diff --git a/com.ibm.wala.core.tests/src/com/ibm/wala/core/tests/demandpa/IntraprocTest.java b/com.ibm.wala.core.tests/src/com/ibm/wala/core/tests/demandpa/IntraprocTest.java index 29637d7b4..64f24c887 100644 --- a/com.ibm.wala.core.tests/src/com/ibm/wala/core/tests/demandpa/IntraprocTest.java +++ b/com.ibm.wala.core.tests/src/com/ibm/wala/core/tests/demandpa/IntraprocTest.java @@ -1,65 +1,65 @@ -/******************************************************************************* - * 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. - * - * This file is a derivative of code released by the University of - * California under the terms listed below. - * - * Refinement Analysis Tools is Copyright (c) 2007 The Regents of the - * University of California (Regents). Provided that this notice and - * the following two paragraphs are included in any distribution of - * Refinement Analysis Tools or its derivative work, Regents agrees - * not to assert any of Regents' copyright rights in Refinement - * Analysis Tools against recipient for recipient's reproduction, - * preparation of derivative works, public display, public - * performance, distribution or sublicensing of Refinement Analysis - * Tools and derivative works, in source code and object code form. - * This agreement not to assert does not confer, by implication, - * estoppel, or otherwise any license or rights in any intellectual - * property of Regents, including, but not limited to, any patents - * of Regents or Regents' employees. - * - * IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, - * INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, - * INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE - * AND ITS DOCUMENTATION, EVEN IF REGENTS HAS BEEN ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE AND FURTHER DISCLAIMS ANY STATUTORY - * WARRANTY OF NON-INFRINGEMENT. THE SOFTWARE AND ACCOMPANYING - * DOCUMENTATION, IF ANY, PROVIDED HEREUNDER IS PROVIDED "AS - * IS". REGENTS HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, - * UPDATES, ENHANCEMENTS, OR MODIFICATIONS. - */ -package com.ibm.wala.core.tests.demandpa; - -import java.io.IOException; - -import org.junit.Test; - -import com.ibm.wala.demandpa.alg.IntraProcFilter; -import com.ibm.wala.demandpa.alg.statemachine.StateMachineFactory; -import com.ibm.wala.demandpa.flowgraph.IFlowLabel; -import com.ibm.wala.ipa.cha.ClassHierarchyException; -import com.ibm.wala.util.CancelException; - -public class IntraprocTest extends AbstractPtrTest { - - public IntraprocTest() { - super(TestInfo.SCOPE_FILE); - } - - @Test public void testId() throws ClassHierarchyException, IllegalArgumentException, CancelException, IOException { - doPointsToSizeTest(TestInfo.TEST_ID, 0); - } - - @Override - protected StateMachineFactory getStateMachineFactory() { - return new IntraProcFilter.Factory(); - } - -} +/******************************************************************************* + * 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. + * + * This file is a derivative of code released by the University of + * California under the terms listed below. + * + * Refinement Analysis Tools is Copyright (c) 2007 The Regents of the + * University of California (Regents). Provided that this notice and + * the following two paragraphs are included in any distribution of + * Refinement Analysis Tools or its derivative work, Regents agrees + * not to assert any of Regents' copyright rights in Refinement + * Analysis Tools against recipient for recipient's reproduction, + * preparation of derivative works, public display, public + * performance, distribution or sublicensing of Refinement Analysis + * Tools and derivative works, in source code and object code form. + * This agreement not to assert does not confer, by implication, + * estoppel, or otherwise any license or rights in any intellectual + * property of Regents, including, but not limited to, any patents + * of Regents or Regents' employees. + * + * IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, + * INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, + * INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE + * AND ITS DOCUMENTATION, EVEN IF REGENTS HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE AND FURTHER DISCLAIMS ANY STATUTORY + * WARRANTY OF NON-INFRINGEMENT. THE SOFTWARE AND ACCOMPANYING + * DOCUMENTATION, IF ANY, PROVIDED HEREUNDER IS PROVIDED "AS + * IS". REGENTS HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, + * UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + */ +package com.ibm.wala.core.tests.demandpa; + +import java.io.IOException; + +import org.junit.Test; + +import com.ibm.wala.demandpa.alg.IntraProcFilter; +import com.ibm.wala.demandpa.alg.statemachine.StateMachineFactory; +import com.ibm.wala.demandpa.flowgraph.IFlowLabel; +import com.ibm.wala.ipa.cha.ClassHierarchyException; +import com.ibm.wala.util.CancelException; + +public class IntraprocTest extends AbstractPtrTest { + + public IntraprocTest() { + super(TestInfo.SCOPE_FILE); + } + + @Test public void testId() throws ClassHierarchyException, IllegalArgumentException, CancelException, IOException { + doPointsToSizeTest(TestInfo.TEST_ID, 0); + } + + @Override + protected StateMachineFactory getStateMachineFactory() { + return new IntraProcFilter.Factory(); + } + +} diff --git a/com.ibm.wala.core.tests/src/com/ibm/wala/core/tests/demandpa/NoRefinePtrTest.java b/com.ibm.wala.core.tests/src/com/ibm/wala/core/tests/demandpa/NoRefinePtrTest.java index a542069b6..882f67700 100644 --- a/com.ibm.wala.core.tests/src/com/ibm/wala/core/tests/demandpa/NoRefinePtrTest.java +++ b/com.ibm.wala.core.tests/src/com/ibm/wala/core/tests/demandpa/NoRefinePtrTest.java @@ -1,154 +1,154 @@ -/******************************************************************************* - * 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. - * - * This file is a derivative of code released by the University of - * California under the terms listed below. - * - * Refinement Analysis Tools is Copyright (c) 2007 The Regents of the - * University of California (Regents). Provided that this notice and - * the following two paragraphs are included in any distribution of - * Refinement Analysis Tools or its derivative work, Regents agrees - * not to assert any of Regents' copyright rights in Refinement - * Analysis Tools against recipient for recipient's reproduction, - * preparation of derivative works, public display, public - * performance, distribution or sublicensing of Refinement Analysis - * Tools and derivative works, in source code and object code form. - * This agreement not to assert does not confer, by implication, - * estoppel, or otherwise any license or rights in any intellectual - * property of Regents, including, but not limited to, any patents - * of Regents or Regents' employees. - * - * IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, - * INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, - * INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE - * AND ITS DOCUMENTATION, EVEN IF REGENTS HAS BEEN ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE AND FURTHER DISCLAIMS ANY STATUTORY - * WARRANTY OF NON-INFRINGEMENT. THE SOFTWARE AND ACCOMPANYING - * DOCUMENTATION, IF ANY, PROVIDED HEREUNDER IS PROVIDED "AS - * IS". REGENTS HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, - * UPDATES, ENHANCEMENTS, OR MODIFICATIONS. - */ -package com.ibm.wala.core.tests.demandpa; - -import java.io.IOException; - -import org.junit.Test; - -import com.ibm.wala.ipa.cha.ClassHierarchyException; -import com.ibm.wala.util.CancelException; - -public class NoRefinePtrTest extends AbstractPtrTest { - - public NoRefinePtrTest() { - super(TestInfo.SCOPE_FILE); - } - - @Test - public void testOnTheFlySimple() throws ClassHierarchyException, IllegalArgumentException, CancelException, IOException { - doPointsToSizeTest(TestInfo.TEST_ONTHEFLY_SIMPLE, 1); - } - - @Test - public void testArraySet() throws ClassHierarchyException, IllegalArgumentException, CancelException, IOException { - doPointsToSizeTest(TestInfo.TEST_ARRAY_SET, 2); - } - - @Test - public void testArraySetIter() throws ClassHierarchyException, IllegalArgumentException, CancelException, IOException { - doPointsToSizeTest(TestInfo.TEST_ARRAY_SET_ITER, 2); - } - - @Test - public void testHashSet() throws ClassHierarchyException, IllegalArgumentException, CancelException, IOException { - doPointsToSizeTest(TestInfo.TEST_HASH_SET, 2); - } - - @Test - public void testMethodRecursion() throws ClassHierarchyException, IllegalArgumentException, CancelException, IOException { - doPointsToSizeTest(TestInfo.TEST_METHOD_RECURSION, 2); - } - - @Test - public void testFooId() throws ClassHierarchyException, IllegalArgumentException, CancelException, IOException { - doPointsToSizeTest(TestInfo.TEST_ID, 2); - } - - @Test - public void testLocals() throws ClassHierarchyException, IllegalArgumentException, CancelException, IOException { - doPointsToSizeTest(TestInfo.TEST_LOCALS, 1); - } - - @Test - public void testArrays() throws ClassHierarchyException, IllegalArgumentException, CancelException, IOException { - doPointsToSizeTest(TestInfo.TEST_ARRAYS, 2); - } - - @Test - public void testFields() throws ClassHierarchyException, IllegalArgumentException, CancelException, IOException { - doPointsToSizeTest(TestInfo.TEST_FIELDS, 2); - } - - @Test - public void testFieldsHarder() throws ClassHierarchyException, IllegalArgumentException, CancelException, IOException { - doPointsToSizeTest(TestInfo.TEST_FIELDS_HARDER, 2); - } - - @Test - public void testGetterSetter() throws ClassHierarchyException, IllegalArgumentException, CancelException, IOException { - doPointsToSizeTest(TestInfo.TEST_GETTER_SETTER, 2); - } - - @Test - public void testException() throws ClassHierarchyException, IllegalArgumentException, CancelException, IOException { - doPointsToSizeTest(TestInfo.TEST_EXCEPTION, 4); - } - - @Test - public void testMultiDim() throws ClassHierarchyException, IllegalArgumentException, CancelException, IOException { - doPointsToSizeTest(TestInfo.TEST_MULTI_DIM, 2); - } - - @Test - public void testGlobal() throws ClassHierarchyException, IllegalArgumentException, CancelException, IOException { - doPointsToSizeTest(TestInfo.TEST_GLOBAL, 1); - } - - @Test - public void testFlowsToLocals() throws ClassHierarchyException, IllegalArgumentException, CancelException, IOException { - // local var, init of FlowsToType, init of Object, and param of TestUtil.makeVarUsed() - doFlowsToSizeTest(TestInfo.FLOWSTO_TEST_LOCALS, 4); - } - - @Test - public void testFlowsToId() throws ClassHierarchyException, IllegalArgumentException, CancelException, IOException { - doFlowsToSizeTest(TestInfo.FLOWSTO_TEST_ID, 8); - } - - @Test - public void testFlowsToFields() throws ClassHierarchyException, IllegalArgumentException, CancelException, IOException { - doFlowsToSizeTest(TestInfo.FLOWSTO_TEST_FIELDS, 6); - } - - @Test - public void testFlowsToFieldsHarder() throws ClassHierarchyException, IllegalArgumentException, CancelException, IOException { - doFlowsToSizeTest(TestInfo.FLOWSTO_TEST_FIELDS_HARDER, 6); - } - - @Test - public void testFlowsToArraySetIter() throws ClassHierarchyException, IllegalArgumentException, CancelException, IOException { - doFlowsToSizeTest(TestInfo.FLOWSTO_TEST_ARRAYSET_ITER, 8); - } - - // don't test this until we have a way to handle different library versions -// @Test -// public void testFlowsToHashSet() throws ClassHierarchyException, IllegalArgumentException, CancelException, IOException { -// doFlowsToSizeTest(TestInfo.FLOWSTO_TEST_HASHSET, 8); -// } -} +/******************************************************************************* + * 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. + * + * This file is a derivative of code released by the University of + * California under the terms listed below. + * + * Refinement Analysis Tools is Copyright (c) 2007 The Regents of the + * University of California (Regents). Provided that this notice and + * the following two paragraphs are included in any distribution of + * Refinement Analysis Tools or its derivative work, Regents agrees + * not to assert any of Regents' copyright rights in Refinement + * Analysis Tools against recipient for recipient's reproduction, + * preparation of derivative works, public display, public + * performance, distribution or sublicensing of Refinement Analysis + * Tools and derivative works, in source code and object code form. + * This agreement not to assert does not confer, by implication, + * estoppel, or otherwise any license or rights in any intellectual + * property of Regents, including, but not limited to, any patents + * of Regents or Regents' employees. + * + * IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, + * INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, + * INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE + * AND ITS DOCUMENTATION, EVEN IF REGENTS HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE AND FURTHER DISCLAIMS ANY STATUTORY + * WARRANTY OF NON-INFRINGEMENT. THE SOFTWARE AND ACCOMPANYING + * DOCUMENTATION, IF ANY, PROVIDED HEREUNDER IS PROVIDED "AS + * IS". REGENTS HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, + * UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + */ +package com.ibm.wala.core.tests.demandpa; + +import java.io.IOException; + +import org.junit.Test; + +import com.ibm.wala.ipa.cha.ClassHierarchyException; +import com.ibm.wala.util.CancelException; + +public class NoRefinePtrTest extends AbstractPtrTest { + + public NoRefinePtrTest() { + super(TestInfo.SCOPE_FILE); + } + + @Test + public void testOnTheFlySimple() throws ClassHierarchyException, IllegalArgumentException, CancelException, IOException { + doPointsToSizeTest(TestInfo.TEST_ONTHEFLY_SIMPLE, 1); + } + + @Test + public void testArraySet() throws ClassHierarchyException, IllegalArgumentException, CancelException, IOException { + doPointsToSizeTest(TestInfo.TEST_ARRAY_SET, 2); + } + + @Test + public void testArraySetIter() throws ClassHierarchyException, IllegalArgumentException, CancelException, IOException { + doPointsToSizeTest(TestInfo.TEST_ARRAY_SET_ITER, 2); + } + + @Test + public void testHashSet() throws ClassHierarchyException, IllegalArgumentException, CancelException, IOException { + doPointsToSizeTest(TestInfo.TEST_HASH_SET, 2); + } + + @Test + public void testMethodRecursion() throws ClassHierarchyException, IllegalArgumentException, CancelException, IOException { + doPointsToSizeTest(TestInfo.TEST_METHOD_RECURSION, 2); + } + + @Test + public void testFooId() throws ClassHierarchyException, IllegalArgumentException, CancelException, IOException { + doPointsToSizeTest(TestInfo.TEST_ID, 2); + } + + @Test + public void testLocals() throws ClassHierarchyException, IllegalArgumentException, CancelException, IOException { + doPointsToSizeTest(TestInfo.TEST_LOCALS, 1); + } + + @Test + public void testArrays() throws ClassHierarchyException, IllegalArgumentException, CancelException, IOException { + doPointsToSizeTest(TestInfo.TEST_ARRAYS, 2); + } + + @Test + public void testFields() throws ClassHierarchyException, IllegalArgumentException, CancelException, IOException { + doPointsToSizeTest(TestInfo.TEST_FIELDS, 2); + } + + @Test + public void testFieldsHarder() throws ClassHierarchyException, IllegalArgumentException, CancelException, IOException { + doPointsToSizeTest(TestInfo.TEST_FIELDS_HARDER, 2); + } + + @Test + public void testGetterSetter() throws ClassHierarchyException, IllegalArgumentException, CancelException, IOException { + doPointsToSizeTest(TestInfo.TEST_GETTER_SETTER, 2); + } + + @Test + public void testException() throws ClassHierarchyException, IllegalArgumentException, CancelException, IOException { + doPointsToSizeTest(TestInfo.TEST_EXCEPTION, 4); + } + + @Test + public void testMultiDim() throws ClassHierarchyException, IllegalArgumentException, CancelException, IOException { + doPointsToSizeTest(TestInfo.TEST_MULTI_DIM, 2); + } + + @Test + public void testGlobal() throws ClassHierarchyException, IllegalArgumentException, CancelException, IOException { + doPointsToSizeTest(TestInfo.TEST_GLOBAL, 1); + } + + @Test + public void testFlowsToLocals() throws ClassHierarchyException, IllegalArgumentException, CancelException, IOException { + // local var, init of FlowsToType, init of Object, and param of TestUtil.makeVarUsed() + doFlowsToSizeTest(TestInfo.FLOWSTO_TEST_LOCALS, 4); + } + + @Test + public void testFlowsToId() throws ClassHierarchyException, IllegalArgumentException, CancelException, IOException { + doFlowsToSizeTest(TestInfo.FLOWSTO_TEST_ID, 8); + } + + @Test + public void testFlowsToFields() throws ClassHierarchyException, IllegalArgumentException, CancelException, IOException { + doFlowsToSizeTest(TestInfo.FLOWSTO_TEST_FIELDS, 6); + } + + @Test + public void testFlowsToFieldsHarder() throws ClassHierarchyException, IllegalArgumentException, CancelException, IOException { + doFlowsToSizeTest(TestInfo.FLOWSTO_TEST_FIELDS_HARDER, 6); + } + + @Test + public void testFlowsToArraySetIter() throws ClassHierarchyException, IllegalArgumentException, CancelException, IOException { + doFlowsToSizeTest(TestInfo.FLOWSTO_TEST_ARRAYSET_ITER, 8); + } + + // don't test this until we have a way to handle different library versions +// @Test +// public void testFlowsToHashSet() throws ClassHierarchyException, IllegalArgumentException, CancelException, IOException { +// doFlowsToSizeTest(TestInfo.FLOWSTO_TEST_HASHSET, 8); +// } +} diff --git a/com.ibm.wala.core.tests/src/com/ibm/wala/core/tests/demandpa/OnTheFlyPtrTest.java b/com.ibm.wala.core.tests/src/com/ibm/wala/core/tests/demandpa/OnTheFlyPtrTest.java index 02c66bcdd..c8ff9dce7 100644 --- a/com.ibm.wala.core.tests/src/com/ibm/wala/core/tests/demandpa/OnTheFlyPtrTest.java +++ b/com.ibm.wala.core.tests/src/com/ibm/wala/core/tests/demandpa/OnTheFlyPtrTest.java @@ -1,71 +1,71 @@ -/******************************************************************************* - * 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. - * - * This file is a derivative of code released by the University of - * California under the terms listed below. - * - * Refinement Analysis Tools is Copyright (c) 2007 The Regents of the - * University of California (Regents). Provided that this notice and - * the following two paragraphs are included in any distribution of - * Refinement Analysis Tools or its derivative work, Regents agrees - * not to assert any of Regents' copyright rights in Refinement - * Analysis Tools against recipient for recipient's reproduction, - * preparation of derivative works, public display, public - * performance, distribution or sublicensing of Refinement Analysis - * Tools and derivative works, in source code and object code form. - * This agreement not to assert does not confer, by implication, - * estoppel, or otherwise any license or rights in any intellectual - * property of Regents, including, but not limited to, any patents - * of Regents or Regents' employees. - * - * IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, - * INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, - * INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE - * AND ITS DOCUMENTATION, EVEN IF REGENTS HAS BEEN ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE AND FURTHER DISCLAIMS ANY STATUTORY - * WARRANTY OF NON-INFRINGEMENT. THE SOFTWARE AND ACCOMPANYING - * DOCUMENTATION, IF ANY, PROVIDED HEREUNDER IS PROVIDED "AS - * IS". REGENTS HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, - * UPDATES, ENHANCEMENTS, OR MODIFICATIONS. - */ -package com.ibm.wala.core.tests.demandpa; - -import java.io.IOException; - -import org.junit.Test; - -import com.ibm.wala.demandpa.alg.DemandRefinementPointsTo; -import com.ibm.wala.demandpa.alg.refinepolicy.AlwaysRefineCGPolicy; -import com.ibm.wala.demandpa.alg.refinepolicy.AlwaysRefineFieldsPolicy; -import com.ibm.wala.demandpa.alg.refinepolicy.SinglePassRefinementPolicy; -import com.ibm.wala.ipa.cha.ClassHierarchyException; -import com.ibm.wala.util.CancelException; - -public class OnTheFlyPtrTest extends AbstractPtrTest { - - public OnTheFlyPtrTest() { - super(TestInfo.SCOPE_FILE); - } - - @Test - public void testOnTheFlySimple() throws ClassHierarchyException, IllegalArgumentException, CancelException, IOException { - doPointsToSizeTest(TestInfo.TEST_ONTHEFLY_SIMPLE, 1); - } - - @Override - protected DemandRefinementPointsTo makeDemandPointerAnalysis(String mainClass) throws ClassHierarchyException, - IllegalArgumentException, CancelException, IOException { - DemandRefinementPointsTo dmp = super.makeDemandPointerAnalysis(mainClass); - dmp.setRefinementPolicyFactory(new SinglePassRefinementPolicy.Factory(new AlwaysRefineFieldsPolicy(), - new AlwaysRefineCGPolicy())); - return dmp; - } - -} +/******************************************************************************* + * 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. + * + * This file is a derivative of code released by the University of + * California under the terms listed below. + * + * Refinement Analysis Tools is Copyright (c) 2007 The Regents of the + * University of California (Regents). Provided that this notice and + * the following two paragraphs are included in any distribution of + * Refinement Analysis Tools or its derivative work, Regents agrees + * not to assert any of Regents' copyright rights in Refinement + * Analysis Tools against recipient for recipient's reproduction, + * preparation of derivative works, public display, public + * performance, distribution or sublicensing of Refinement Analysis + * Tools and derivative works, in source code and object code form. + * This agreement not to assert does not confer, by implication, + * estoppel, or otherwise any license or rights in any intellectual + * property of Regents, including, but not limited to, any patents + * of Regents or Regents' employees. + * + * IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, + * INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, + * INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE + * AND ITS DOCUMENTATION, EVEN IF REGENTS HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE AND FURTHER DISCLAIMS ANY STATUTORY + * WARRANTY OF NON-INFRINGEMENT. THE SOFTWARE AND ACCOMPANYING + * DOCUMENTATION, IF ANY, PROVIDED HEREUNDER IS PROVIDED "AS + * IS". REGENTS HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, + * UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + */ +package com.ibm.wala.core.tests.demandpa; + +import java.io.IOException; + +import org.junit.Test; + +import com.ibm.wala.demandpa.alg.DemandRefinementPointsTo; +import com.ibm.wala.demandpa.alg.refinepolicy.AlwaysRefineCGPolicy; +import com.ibm.wala.demandpa.alg.refinepolicy.AlwaysRefineFieldsPolicy; +import com.ibm.wala.demandpa.alg.refinepolicy.SinglePassRefinementPolicy; +import com.ibm.wala.ipa.cha.ClassHierarchyException; +import com.ibm.wala.util.CancelException; + +public class OnTheFlyPtrTest extends AbstractPtrTest { + + public OnTheFlyPtrTest() { + super(TestInfo.SCOPE_FILE); + } + + @Test + public void testOnTheFlySimple() throws ClassHierarchyException, IllegalArgumentException, CancelException, IOException { + doPointsToSizeTest(TestInfo.TEST_ONTHEFLY_SIMPLE, 1); + } + + @Override + protected DemandRefinementPointsTo makeDemandPointerAnalysis(String mainClass) throws ClassHierarchyException, + IllegalArgumentException, CancelException, IOException { + DemandRefinementPointsTo dmp = super.makeDemandPointerAnalysis(mainClass); + dmp.setRefinementPolicyFactory(new SinglePassRefinementPolicy.Factory(new AlwaysRefineFieldsPolicy(), + new AlwaysRefineCGPolicy())); + return dmp; + } + +} diff --git a/com.ibm.wala.core.tests/src/com/ibm/wala/core/tests/demandpa/RefineFieldsPtrTest.java b/com.ibm.wala.core.tests/src/com/ibm/wala/core/tests/demandpa/RefineFieldsPtrTest.java index 7f26d705a..00a04e5e0 100644 --- a/com.ibm.wala.core.tests/src/com/ibm/wala/core/tests/demandpa/RefineFieldsPtrTest.java +++ b/com.ibm.wala.core.tests/src/com/ibm/wala/core/tests/demandpa/RefineFieldsPtrTest.java @@ -1,122 +1,122 @@ -/******************************************************************************* - * 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. - * - * This file is a derivative of code released by the University of - * California under the terms listed below. - * - * Refinement Analysis Tools is Copyright (c) 2007 The Regents of the - * University of California (Regents). Provided that this notice and - * the following two paragraphs are included in any distribution of - * Refinement Analysis Tools or its derivative work, Regents agrees - * not to assert any of Regents' copyright rights in Refinement - * Analysis Tools against recipient for recipient's reproduction, - * preparation of derivative works, public display, public - * performance, distribution or sublicensing of Refinement Analysis - * Tools and derivative works, in source code and object code form. - * This agreement not to assert does not confer, by implication, - * estoppel, or otherwise any license or rights in any intellectual - * property of Regents, including, but not limited to, any patents - * of Regents or Regents' employees. - * - * IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, - * INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, - * INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE - * AND ITS DOCUMENTATION, EVEN IF REGENTS HAS BEEN ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE AND FURTHER DISCLAIMS ANY STATUTORY - * WARRANTY OF NON-INFRINGEMENT. THE SOFTWARE AND ACCOMPANYING - * DOCUMENTATION, IF ANY, PROVIDED HEREUNDER IS PROVIDED "AS - * IS". REGENTS HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, - * UPDATES, ENHANCEMENTS, OR MODIFICATIONS. - */ -package com.ibm.wala.core.tests.demandpa; - -import java.io.IOException; - -import org.junit.Test; - -import com.ibm.wala.demandpa.alg.DemandRefinementPointsTo; -import com.ibm.wala.demandpa.alg.refinepolicy.AlwaysRefineFieldsPolicy; -import com.ibm.wala.demandpa.alg.refinepolicy.NeverRefineCGPolicy; -import com.ibm.wala.demandpa.alg.refinepolicy.SinglePassRefinementPolicy; -import com.ibm.wala.ipa.cha.ClassHierarchyException; -import com.ibm.wala.util.CancelException; - -public class RefineFieldsPtrTest extends AbstractPtrTest { - - public RefineFieldsPtrTest() { - super(TestInfo.SCOPE_FILE); - } - - @Test - public void testNastyPtrs() throws ClassHierarchyException, IllegalArgumentException, CancelException, IOException { - doPointsToSizeTest(TestInfo.TEST_NASTY_PTRS, 10); - } - - @Test - public void testGlobal() throws ClassHierarchyException, IllegalArgumentException, CancelException, IOException { - doPointsToSizeTest(TestInfo.TEST_GLOBAL, 1); - } - - @Test - public void testFields() throws ClassHierarchyException, IllegalArgumentException, CancelException, IOException { - doPointsToSizeTest(TestInfo.TEST_FIELDS, 1); - } - - @Test - public void testFieldsHarder() throws ClassHierarchyException, IllegalArgumentException, CancelException, IOException { - doPointsToSizeTest(TestInfo.TEST_FIELDS_HARDER, 1); - } - - @Test - public void testArrays() throws ClassHierarchyException, IllegalArgumentException, CancelException, IOException { - doPointsToSizeTest(TestInfo.TEST_ARRAYS, 2); - } - - @Test - public void testGetterSetter() throws ClassHierarchyException, IllegalArgumentException, CancelException, IOException { - doPointsToSizeTest(TestInfo.TEST_GETTER_SETTER, 1); - } - - @Test - public void testArraySet() throws ClassHierarchyException, IllegalArgumentException, CancelException, IOException { - doPointsToSizeTest(TestInfo.TEST_ARRAY_SET, 2); - } - - @Test - public void testArraySetIter() throws ClassHierarchyException, IllegalArgumentException, CancelException, IOException { - doPointsToSizeTest(TestInfo.TEST_ARRAY_SET_ITER, 2); - } - - @Test - public void testMultiDim() throws ClassHierarchyException, IllegalArgumentException, CancelException, IOException { - doPointsToSizeTest(TestInfo.TEST_MULTI_DIM, 2); - } - - @Override - public DemandRefinementPointsTo makeDemandPointerAnalysis(String mainClass) throws ClassHierarchyException, - IllegalArgumentException, CancelException, IOException { - DemandRefinementPointsTo dmp = super.makeDemandPointerAnalysis(mainClass); - dmp - .setRefinementPolicyFactory(new SinglePassRefinementPolicy.Factory(new AlwaysRefineFieldsPolicy(), - new NeverRefineCGPolicy())); - return dmp; - } - - @Test - public void testFlowsToFields() throws ClassHierarchyException, IllegalArgumentException, CancelException, IOException { - doFlowsToSizeTest(TestInfo.FLOWSTO_TEST_FIELDS, 5); - } - - @Test - public void testFlowsToFieldsHarder() throws ClassHierarchyException, IllegalArgumentException, CancelException, IOException { - doFlowsToSizeTest(TestInfo.FLOWSTO_TEST_FIELDS_HARDER, 5); - } - -} +/******************************************************************************* + * 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. + * + * This file is a derivative of code released by the University of + * California under the terms listed below. + * + * Refinement Analysis Tools is Copyright (c) 2007 The Regents of the + * University of California (Regents). Provided that this notice and + * the following two paragraphs are included in any distribution of + * Refinement Analysis Tools or its derivative work, Regents agrees + * not to assert any of Regents' copyright rights in Refinement + * Analysis Tools against recipient for recipient's reproduction, + * preparation of derivative works, public display, public + * performance, distribution or sublicensing of Refinement Analysis + * Tools and derivative works, in source code and object code form. + * This agreement not to assert does not confer, by implication, + * estoppel, or otherwise any license or rights in any intellectual + * property of Regents, including, but not limited to, any patents + * of Regents or Regents' employees. + * + * IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, + * INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, + * INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE + * AND ITS DOCUMENTATION, EVEN IF REGENTS HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE AND FURTHER DISCLAIMS ANY STATUTORY + * WARRANTY OF NON-INFRINGEMENT. THE SOFTWARE AND ACCOMPANYING + * DOCUMENTATION, IF ANY, PROVIDED HEREUNDER IS PROVIDED "AS + * IS". REGENTS HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, + * UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + */ +package com.ibm.wala.core.tests.demandpa; + +import java.io.IOException; + +import org.junit.Test; + +import com.ibm.wala.demandpa.alg.DemandRefinementPointsTo; +import com.ibm.wala.demandpa.alg.refinepolicy.AlwaysRefineFieldsPolicy; +import com.ibm.wala.demandpa.alg.refinepolicy.NeverRefineCGPolicy; +import com.ibm.wala.demandpa.alg.refinepolicy.SinglePassRefinementPolicy; +import com.ibm.wala.ipa.cha.ClassHierarchyException; +import com.ibm.wala.util.CancelException; + +public class RefineFieldsPtrTest extends AbstractPtrTest { + + public RefineFieldsPtrTest() { + super(TestInfo.SCOPE_FILE); + } + + @Test + public void testNastyPtrs() throws ClassHierarchyException, IllegalArgumentException, CancelException, IOException { + doPointsToSizeTest(TestInfo.TEST_NASTY_PTRS, 10); + } + + @Test + public void testGlobal() throws ClassHierarchyException, IllegalArgumentException, CancelException, IOException { + doPointsToSizeTest(TestInfo.TEST_GLOBAL, 1); + } + + @Test + public void testFields() throws ClassHierarchyException, IllegalArgumentException, CancelException, IOException { + doPointsToSizeTest(TestInfo.TEST_FIELDS, 1); + } + + @Test + public void testFieldsHarder() throws ClassHierarchyException, IllegalArgumentException, CancelException, IOException { + doPointsToSizeTest(TestInfo.TEST_FIELDS_HARDER, 1); + } + + @Test + public void testArrays() throws ClassHierarchyException, IllegalArgumentException, CancelException, IOException { + doPointsToSizeTest(TestInfo.TEST_ARRAYS, 2); + } + + @Test + public void testGetterSetter() throws ClassHierarchyException, IllegalArgumentException, CancelException, IOException { + doPointsToSizeTest(TestInfo.TEST_GETTER_SETTER, 1); + } + + @Test + public void testArraySet() throws ClassHierarchyException, IllegalArgumentException, CancelException, IOException { + doPointsToSizeTest(TestInfo.TEST_ARRAY_SET, 2); + } + + @Test + public void testArraySetIter() throws ClassHierarchyException, IllegalArgumentException, CancelException, IOException { + doPointsToSizeTest(TestInfo.TEST_ARRAY_SET_ITER, 2); + } + + @Test + public void testMultiDim() throws ClassHierarchyException, IllegalArgumentException, CancelException, IOException { + doPointsToSizeTest(TestInfo.TEST_MULTI_DIM, 2); + } + + @Override + public DemandRefinementPointsTo makeDemandPointerAnalysis(String mainClass) throws ClassHierarchyException, + IllegalArgumentException, CancelException, IOException { + DemandRefinementPointsTo dmp = super.makeDemandPointerAnalysis(mainClass); + dmp + .setRefinementPolicyFactory(new SinglePassRefinementPolicy.Factory(new AlwaysRefineFieldsPolicy(), + new NeverRefineCGPolicy())); + return dmp; + } + + @Test + public void testFlowsToFields() throws ClassHierarchyException, IllegalArgumentException, CancelException, IOException { + doFlowsToSizeTest(TestInfo.FLOWSTO_TEST_FIELDS, 5); + } + + @Test + public void testFlowsToFieldsHarder() throws ClassHierarchyException, IllegalArgumentException, CancelException, IOException { + doFlowsToSizeTest(TestInfo.FLOWSTO_TEST_FIELDS_HARDER, 5); + } + +} diff --git a/com.ibm.wala.core.tests/src/com/ibm/wala/core/tests/demandpa/TestInfo.java b/com.ibm.wala.core.tests/src/com/ibm/wala/core/tests/demandpa/TestInfo.java index 69efdce35..7a683cdee 100644 --- a/com.ibm.wala.core.tests/src/com/ibm/wala/core/tests/demandpa/TestInfo.java +++ b/com.ibm.wala.core.tests/src/com/ibm/wala/core/tests/demandpa/TestInfo.java @@ -1,108 +1,108 @@ -/******************************************************************************* - * 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. - * - * This file is a derivative of code released by the University of - * California under the terms listed below. - * - * Refinement Analysis Tools is Copyright (c) 2007 The Regents of the - * University of California (Regents). Provided that this notice and - * the following two paragraphs are included in any distribution of - * Refinement Analysis Tools or its derivative work, Regents agrees - * not to assert any of Regents' copyright rights in Refinement - * Analysis Tools against recipient for recipient's reproduction, - * preparation of derivative works, public display, public - * performance, distribution or sublicensing of Refinement Analysis - * Tools and derivative works, in source code and object code form. - * This agreement not to assert does not confer, by implication, - * estoppel, or otherwise any license or rights in any intellectual - * property of Regents, including, but not limited to, any patents - * of Regents or Regents' employees. - * - * IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, - * INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, - * INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE - * AND ITS DOCUMENTATION, EVEN IF REGENTS HAS BEEN ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE AND FURTHER DISCLAIMS ANY STATUTORY - * WARRANTY OF NON-INFRINGEMENT. THE SOFTWARE AND ACCOMPANYING - * DOCUMENTATION, IF ANY, PROVIDED HEREUNDER IS PROVIDED "AS - * IS". REGENTS HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, - * UPDATES, ENHANCEMENTS, OR MODIFICATIONS. - */ -package com.ibm.wala.core.tests.demandpa; - -public class TestInfo { - - public static final String SCOPE_FILE = "wala.testdata.txt"; - - // public static final String TEST1 = "Ldemandpa/Test1"; - - public static final String TEST_FIELDS = "Ldemandpa/TestFields"; - - public static final String TEST_FIELDS_HARDER = "Ldemandpa/TestFieldsHarder"; - - public static final String TEST_GETTER_SETTER = "Ldemandpa/TestGetterSetter"; - - public static final String TEST_ARRAYS = "Ldemandpa/TestArrays"; - - public static final String TEST_EXCEPTION = "Ldemandpa/TestException"; - - public static final String TEST_FACTORY = "Ldemandpa/TestFactory"; - - public static final String TEST_ARRAY_SET = "Ldemandpa/TestArraySet"; - - public static final String TEST_ARRAY_SET_ITER = "Ldemandpa/TestArraySetIter"; - - public static final String TEST_MULTI_DIM = "Ldemandpa/TestMultiDim"; - - public static final String TEST_GLOBAL = "Ldemandpa/TestGlobal"; - - public static final String TEST_ID = "Ldemandpa/TestId"; - - public static final String TEST_LOCALS = "Ldemandpa/TestLocals"; - - public static final String TEST_ONTHEFLY_SIMPLE = "Ldemandpa/TestOnTheFlySimple"; - - public static final String TEST_ONTHEFLY_CS = "Ldemandpa/TestOnTheFlyCS"; - - public static final String TEST_COND = "Ldemandpa/TestCond"; - - public static final String TEST_METHOD_RECURSION = "Ldemandpa/TestMethodRecursion"; - - public static final String TEST_HASH_SET = "Ldemandpa/TestHashSet"; - - public static final String TEST_HASHMAP_GET = "Ldemandpa/TestHashMapGet"; - - public static final String TEST_LINKED_LIST = "Ldemandpa/TestLinkedList"; - - public static final String TEST_LINKEDLIST_ITER = "Ldemandpa/TestLinkedListIter"; - - public static final String TEST_ARRAY_LIST = "Ldemandpa/TestArrayList"; - - public static final String TEST_HASHTABLE_ENUM = "Ldemandpa/TestHashtableEnum"; - - public static final String TEST_NASTY_PTRS = "Ldemandpa/TestNastyPtrs"; - - public static final String TEST_WITHIN_METHOD_CALL = "Ldemandpa/TestWithinMethodCall"; - - public static final String TEST_CLONE = "Ldemandpa/TestClone"; - - public static final String FLOWSTO_TEST_LOCALS = "Ldemandpa/FlowsToTestLocals"; - - public static final String FLOWSTO_TEST_ID = "Ldemandpa/FlowsToTestId"; - - public static final String FLOWSTO_TEST_FIELDS = "Ldemandpa/FlowsToTestFields"; - - public static final String FLOWSTO_TEST_FIELDS_HARDER = "Ldemandpa/FlowsToTestFieldsHarder"; - - public static final String FLOWSTO_TEST_ARRAYSET_ITER = "Ldemandpa/FlowsToTestArraySetIter"; - - public static final String FLOWSTO_TEST_HASHSET = "Ldemandpa/FlowsToTestHashSet"; - -} +/******************************************************************************* + * 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. + * + * This file is a derivative of code released by the University of + * California under the terms listed below. + * + * Refinement Analysis Tools is Copyright (c) 2007 The Regents of the + * University of California (Regents). Provided that this notice and + * the following two paragraphs are included in any distribution of + * Refinement Analysis Tools or its derivative work, Regents agrees + * not to assert any of Regents' copyright rights in Refinement + * Analysis Tools against recipient for recipient's reproduction, + * preparation of derivative works, public display, public + * performance, distribution or sublicensing of Refinement Analysis + * Tools and derivative works, in source code and object code form. + * This agreement not to assert does not confer, by implication, + * estoppel, or otherwise any license or rights in any intellectual + * property of Regents, including, but not limited to, any patents + * of Regents or Regents' employees. + * + * IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, + * INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, + * INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE + * AND ITS DOCUMENTATION, EVEN IF REGENTS HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE AND FURTHER DISCLAIMS ANY STATUTORY + * WARRANTY OF NON-INFRINGEMENT. THE SOFTWARE AND ACCOMPANYING + * DOCUMENTATION, IF ANY, PROVIDED HEREUNDER IS PROVIDED "AS + * IS". REGENTS HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, + * UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + */ +package com.ibm.wala.core.tests.demandpa; + +public class TestInfo { + + public static final String SCOPE_FILE = "wala.testdata.txt"; + + // public static final String TEST1 = "Ldemandpa/Test1"; + + public static final String TEST_FIELDS = "Ldemandpa/TestFields"; + + public static final String TEST_FIELDS_HARDER = "Ldemandpa/TestFieldsHarder"; + + public static final String TEST_GETTER_SETTER = "Ldemandpa/TestGetterSetter"; + + public static final String TEST_ARRAYS = "Ldemandpa/TestArrays"; + + public static final String TEST_EXCEPTION = "Ldemandpa/TestException"; + + public static final String TEST_FACTORY = "Ldemandpa/TestFactory"; + + public static final String TEST_ARRAY_SET = "Ldemandpa/TestArraySet"; + + public static final String TEST_ARRAY_SET_ITER = "Ldemandpa/TestArraySetIter"; + + public static final String TEST_MULTI_DIM = "Ldemandpa/TestMultiDim"; + + public static final String TEST_GLOBAL = "Ldemandpa/TestGlobal"; + + public static final String TEST_ID = "Ldemandpa/TestId"; + + public static final String TEST_LOCALS = "Ldemandpa/TestLocals"; + + public static final String TEST_ONTHEFLY_SIMPLE = "Ldemandpa/TestOnTheFlySimple"; + + public static final String TEST_ONTHEFLY_CS = "Ldemandpa/TestOnTheFlyCS"; + + public static final String TEST_COND = "Ldemandpa/TestCond"; + + public static final String TEST_METHOD_RECURSION = "Ldemandpa/TestMethodRecursion"; + + public static final String TEST_HASH_SET = "Ldemandpa/TestHashSet"; + + public static final String TEST_HASHMAP_GET = "Ldemandpa/TestHashMapGet"; + + public static final String TEST_LINKED_LIST = "Ldemandpa/TestLinkedList"; + + public static final String TEST_LINKEDLIST_ITER = "Ldemandpa/TestLinkedListIter"; + + public static final String TEST_ARRAY_LIST = "Ldemandpa/TestArrayList"; + + public static final String TEST_HASHTABLE_ENUM = "Ldemandpa/TestHashtableEnum"; + + public static final String TEST_NASTY_PTRS = "Ldemandpa/TestNastyPtrs"; + + public static final String TEST_WITHIN_METHOD_CALL = "Ldemandpa/TestWithinMethodCall"; + + public static final String TEST_CLONE = "Ldemandpa/TestClone"; + + public static final String FLOWSTO_TEST_LOCALS = "Ldemandpa/FlowsToTestLocals"; + + public static final String FLOWSTO_TEST_ID = "Ldemandpa/FlowsToTestId"; + + public static final String FLOWSTO_TEST_FIELDS = "Ldemandpa/FlowsToTestFields"; + + public static final String FLOWSTO_TEST_FIELDS_HARDER = "Ldemandpa/FlowsToTestFieldsHarder"; + + public static final String FLOWSTO_TEST_ARRAYSET_ITER = "Ldemandpa/FlowsToTestArraySetIter"; + + public static final String FLOWSTO_TEST_HASHSET = "Ldemandpa/FlowsToTestHashSet"; + +} diff --git a/com.ibm.wala.core.tests/src/com/ibm/wala/core/tests/demandpa/TunedRefinementTest.java b/com.ibm.wala.core.tests/src/com/ibm/wala/core/tests/demandpa/TunedRefinementTest.java index a67a32a7b..195927844 100644 --- a/com.ibm.wala.core.tests/src/com/ibm/wala/core/tests/demandpa/TunedRefinementTest.java +++ b/com.ibm.wala.core.tests/src/com/ibm/wala/core/tests/demandpa/TunedRefinementTest.java @@ -1,151 +1,151 @@ -/******************************************************************************* - * Copyright (c) 2008 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.core.tests.demandpa; - -import java.io.IOException; -import java.util.Collection; - -import org.junit.Assert; -import org.junit.Test; - -import com.ibm.wala.demandpa.alg.ContextSensitiveStateMachine; -import com.ibm.wala.demandpa.alg.DemandRefinementPointsTo; -import com.ibm.wala.demandpa.alg.IDemandPointerAnalysis; -import com.ibm.wala.demandpa.alg.refinepolicy.TunedRefinementPolicy; -import com.ibm.wala.demandpa.alg.statemachine.StateMachineFactory; -import com.ibm.wala.demandpa.flowgraph.IFlowLabel; -import com.ibm.wala.ipa.callgraph.CGNode; -import com.ibm.wala.ipa.callgraph.propagation.InstanceKey; -import com.ibm.wala.ipa.callgraph.propagation.PointerKey; -import com.ibm.wala.ipa.cha.ClassHierarchyException; -import com.ibm.wala.types.Descriptor; -import com.ibm.wala.util.CancelException; -import com.ibm.wala.util.strings.Atom; - -public class TunedRefinementTest extends AbstractPtrTest { - - public TunedRefinementTest() { - super(TestInfo.SCOPE_FILE); - // TODO Auto-generated constructor stub - } - - @Test - public void testArraySet() throws ClassHierarchyException, IllegalArgumentException, CancelException, IOException { - doPointsToSizeTest(TestInfo.TEST_ARRAY_SET, 1); - } - - @Test - public void testClone() throws ClassHierarchyException, IllegalArgumentException, CancelException, IOException { - doPointsToSizeTest(TestInfo.TEST_CLONE, 1); - } - - @Test - public void testFooId() throws ClassHierarchyException, IllegalArgumentException, CancelException, IOException { - doPointsToSizeTest(TestInfo.TEST_ID, 1); - } - - @Test - public void testHashtableEnum() throws ClassHierarchyException, IllegalArgumentException, CancelException, IOException { - // 3 because - // can't tell between key and value enumerators in Hashtable - doPointsToSizeTest(TestInfo.TEST_HASHTABLE_ENUM, 2); - } - - // we know this one fails... - // @Test public void testOnTheFlyCS() throws ClassHierarchyException { - // String mainClass = TestInfo.TEST_ONTHEFLY_CS; - // final IDemandPointerAnalysis dmp = - // makeDemandPointerAnalysis(TestInfo.SCOPE_FILE, mainClass); - // CGNode testMethod = - // AbstractPtrTest.findInstanceMethod(dmp.getBaseCallGraph(), - // dmp.getClassHierarchy().lookupClass( - // TypeReference.findOrCreate(ClassLoaderReference.Application, - // "Ltestdata/TestOnTheFlyCS$C2")), Atom - // .findOrCreateUnicodeAtom("doSomething"), - // Descriptor.findOrCreateUTF8("(Ljava/lang/Object;)V")); - // PointerKey keyToQuery = AbstractPtrTest.getParam(testMethod, "testThisVar", - // dmp.getHeapModel()); - // Collection pointsTo = dmp.getPointsTo(keyToQuery); - // if (debug) { - // System.err.println("points-to for " + mainClass + ": " + pointsTo); - // } - // assertEquals(1, pointsTo.size()); - // } - - @Test - public void testWithinMethodCall() throws ClassHierarchyException, IllegalArgumentException, CancelException, IOException { - String mainClass = TestInfo.TEST_WITHIN_METHOD_CALL; - final IDemandPointerAnalysis dmp = makeDemandPointerAnalysis(mainClass); - - CGNode testMethod = AbstractPtrTest.findStaticMethod(dmp.getBaseCallGraph(), Atom.findOrCreateUnicodeAtom("testMethod"), - Descriptor.findOrCreateUTF8("(Ljava/lang/Object;)V")); - PointerKey keyToQuery = AbstractPtrTest.getParam(testMethod, "testThisVar", dmp.getHeapModel()); - Collection pointsTo = dmp.getPointsTo(keyToQuery); - if (debug) { - System.err.println("points-to for " + mainClass + ": " + pointsTo); - } - Assert.assertEquals(1, pointsTo.size()); - } - - @Test - public void testLinkedListIter() throws ClassHierarchyException, IllegalArgumentException, CancelException, IOException { - doPointsToSizeTest(TestInfo.TEST_LINKEDLIST_ITER, 1); - } - - @Test - public void testGlobal() throws ClassHierarchyException, IllegalArgumentException, CancelException, IOException { - doPointsToSizeTest(TestInfo.TEST_GLOBAL, 1); - } - - @Test - public void testHashSet() throws ClassHierarchyException, IllegalArgumentException, CancelException, IOException { - doPointsToSizeTest(TestInfo.TEST_HASH_SET, 1); - } - - @Test - public void testHashMapGet() throws ClassHierarchyException, IllegalArgumentException, CancelException, IOException { - doPointsToSizeTest(TestInfo.TEST_HASHMAP_GET, 1); - } - - @Test - public void testMethodRecursion() throws ClassHierarchyException, IllegalArgumentException, CancelException, IOException { - doPointsToSizeTest(TestInfo.TEST_METHOD_RECURSION, 2); - } - - @Test - public void testArraySetIter() throws ClassHierarchyException, IllegalArgumentException, CancelException, IOException { - doPointsToSizeTest(TestInfo.TEST_ARRAY_SET_ITER, 1); - } - - @Test - public void testArrayList() throws ClassHierarchyException, IllegalArgumentException, CancelException, IOException { - doPointsToSizeTest(TestInfo.TEST_ARRAY_LIST, 1); - } - - @Test - public void testLinkedList() throws ClassHierarchyException, IllegalArgumentException, CancelException, IOException { - doPointsToSizeTest(TestInfo.TEST_LINKED_LIST, 1); - } - - @Override - protected StateMachineFactory getStateMachineFactory() { - return new ContextSensitiveStateMachine.Factory(); - } - - @Override - protected DemandRefinementPointsTo makeDemandPointerAnalysis(String mainClass) throws ClassHierarchyException, - IllegalArgumentException, CancelException, IOException { - DemandRefinementPointsTo dmp = super.makeDemandPointerAnalysis(mainClass); - dmp.setRefinementPolicyFactory(new TunedRefinementPolicy.Factory(dmp.getClassHierarchy())); - return dmp; - } - -} +/******************************************************************************* + * Copyright (c) 2008 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.core.tests.demandpa; + +import java.io.IOException; +import java.util.Collection; + +import org.junit.Assert; +import org.junit.Test; + +import com.ibm.wala.demandpa.alg.ContextSensitiveStateMachine; +import com.ibm.wala.demandpa.alg.DemandRefinementPointsTo; +import com.ibm.wala.demandpa.alg.IDemandPointerAnalysis; +import com.ibm.wala.demandpa.alg.refinepolicy.TunedRefinementPolicy; +import com.ibm.wala.demandpa.alg.statemachine.StateMachineFactory; +import com.ibm.wala.demandpa.flowgraph.IFlowLabel; +import com.ibm.wala.ipa.callgraph.CGNode; +import com.ibm.wala.ipa.callgraph.propagation.InstanceKey; +import com.ibm.wala.ipa.callgraph.propagation.PointerKey; +import com.ibm.wala.ipa.cha.ClassHierarchyException; +import com.ibm.wala.types.Descriptor; +import com.ibm.wala.util.CancelException; +import com.ibm.wala.util.strings.Atom; + +public class TunedRefinementTest extends AbstractPtrTest { + + public TunedRefinementTest() { + super(TestInfo.SCOPE_FILE); + // TODO Auto-generated constructor stub + } + + @Test + public void testArraySet() throws ClassHierarchyException, IllegalArgumentException, CancelException, IOException { + doPointsToSizeTest(TestInfo.TEST_ARRAY_SET, 1); + } + + @Test + public void testClone() throws ClassHierarchyException, IllegalArgumentException, CancelException, IOException { + doPointsToSizeTest(TestInfo.TEST_CLONE, 1); + } + + @Test + public void testFooId() throws ClassHierarchyException, IllegalArgumentException, CancelException, IOException { + doPointsToSizeTest(TestInfo.TEST_ID, 1); + } + + @Test + public void testHashtableEnum() throws ClassHierarchyException, IllegalArgumentException, CancelException, IOException { + // 3 because + // can't tell between key and value enumerators in Hashtable + doPointsToSizeTest(TestInfo.TEST_HASHTABLE_ENUM, 2); + } + + // we know this one fails... + // @Test public void testOnTheFlyCS() throws ClassHierarchyException { + // String mainClass = TestInfo.TEST_ONTHEFLY_CS; + // final IDemandPointerAnalysis dmp = + // makeDemandPointerAnalysis(TestInfo.SCOPE_FILE, mainClass); + // CGNode testMethod = + // AbstractPtrTest.findInstanceMethod(dmp.getBaseCallGraph(), + // dmp.getClassHierarchy().lookupClass( + // TypeReference.findOrCreate(ClassLoaderReference.Application, + // "Ltestdata/TestOnTheFlyCS$C2")), Atom + // .findOrCreateUnicodeAtom("doSomething"), + // Descriptor.findOrCreateUTF8("(Ljava/lang/Object;)V")); + // PointerKey keyToQuery = AbstractPtrTest.getParam(testMethod, "testThisVar", + // dmp.getHeapModel()); + // Collection pointsTo = dmp.getPointsTo(keyToQuery); + // if (debug) { + // System.err.println("points-to for " + mainClass + ": " + pointsTo); + // } + // assertEquals(1, pointsTo.size()); + // } + + @Test + public void testWithinMethodCall() throws ClassHierarchyException, IllegalArgumentException, CancelException, IOException { + String mainClass = TestInfo.TEST_WITHIN_METHOD_CALL; + final IDemandPointerAnalysis dmp = makeDemandPointerAnalysis(mainClass); + + CGNode testMethod = AbstractPtrTest.findStaticMethod(dmp.getBaseCallGraph(), Atom.findOrCreateUnicodeAtom("testMethod"), + Descriptor.findOrCreateUTF8("(Ljava/lang/Object;)V")); + PointerKey keyToQuery = AbstractPtrTest.getParam(testMethod, "testThisVar", dmp.getHeapModel()); + Collection pointsTo = dmp.getPointsTo(keyToQuery); + if (debug) { + System.err.println("points-to for " + mainClass + ": " + pointsTo); + } + Assert.assertEquals(1, pointsTo.size()); + } + + @Test + public void testLinkedListIter() throws ClassHierarchyException, IllegalArgumentException, CancelException, IOException { + doPointsToSizeTest(TestInfo.TEST_LINKEDLIST_ITER, 1); + } + + @Test + public void testGlobal() throws ClassHierarchyException, IllegalArgumentException, CancelException, IOException { + doPointsToSizeTest(TestInfo.TEST_GLOBAL, 1); + } + + @Test + public void testHashSet() throws ClassHierarchyException, IllegalArgumentException, CancelException, IOException { + doPointsToSizeTest(TestInfo.TEST_HASH_SET, 1); + } + + @Test + public void testHashMapGet() throws ClassHierarchyException, IllegalArgumentException, CancelException, IOException { + doPointsToSizeTest(TestInfo.TEST_HASHMAP_GET, 1); + } + + @Test + public void testMethodRecursion() throws ClassHierarchyException, IllegalArgumentException, CancelException, IOException { + doPointsToSizeTest(TestInfo.TEST_METHOD_RECURSION, 2); + } + + @Test + public void testArraySetIter() throws ClassHierarchyException, IllegalArgumentException, CancelException, IOException { + doPointsToSizeTest(TestInfo.TEST_ARRAY_SET_ITER, 1); + } + + @Test + public void testArrayList() throws ClassHierarchyException, IllegalArgumentException, CancelException, IOException { + doPointsToSizeTest(TestInfo.TEST_ARRAY_LIST, 1); + } + + @Test + public void testLinkedList() throws ClassHierarchyException, IllegalArgumentException, CancelException, IOException { + doPointsToSizeTest(TestInfo.TEST_LINKED_LIST, 1); + } + + @Override + protected StateMachineFactory getStateMachineFactory() { + return new ContextSensitiveStateMachine.Factory(); + } + + @Override + protected DemandRefinementPointsTo makeDemandPointerAnalysis(String mainClass) throws ClassHierarchyException, + IllegalArgumentException, CancelException, IOException { + DemandRefinementPointsTo dmp = super.makeDemandPointerAnalysis(mainClass); + dmp.setRefinementPolicyFactory(new TunedRefinementPolicy.Factory(dmp.getClassHierarchy())); + return dmp; + } + +} diff --git a/com.ibm.wala.core.tests/src/com/ibm/wala/core/tests/ir/AnnotationTest.java b/com.ibm.wala.core.tests/src/com/ibm/wala/core/tests/ir/AnnotationTest.java index 52b1d0e22..3493fc8c2 100644 --- a/com.ibm.wala.core.tests/src/com/ibm/wala/core/tests/ir/AnnotationTest.java +++ b/com.ibm.wala.core.tests/src/com/ibm/wala/core/tests/ir/AnnotationTest.java @@ -1,145 +1,145 @@ -package com.ibm.wala.core.tests.ir; - -import java.io.IOException; -import java.util.Collection; -import java.util.Collections; - -import org.junit.AfterClass; -import org.junit.Assert; -import org.junit.BeforeClass; -import org.junit.Test; - -import com.ibm.wala.classLoader.IClass; -import com.ibm.wala.classLoader.IMethod; -import com.ibm.wala.classLoader.ShrikeCTMethod; -import com.ibm.wala.classLoader.ShrikeClass; -import com.ibm.wala.core.tests.callGraph.CallGraphTestUtil; -import com.ibm.wala.core.tests.util.TestConstants; -import com.ibm.wala.core.tests.util.WalaTestCase; -import com.ibm.wala.ipa.callgraph.AnalysisScope; -import com.ibm.wala.ipa.cha.ClassHierarchy; -import com.ibm.wala.ipa.cha.ClassHierarchyException; -import com.ibm.wala.ipa.cha.IClassHierarchy; -import com.ibm.wala.shrikeCT.InvalidClassFileException; -import com.ibm.wala.types.ClassLoaderReference; -import com.ibm.wala.types.MethodReference; -import com.ibm.wala.types.Selector; -import com.ibm.wala.types.TypeReference; -import com.ibm.wala.types.annotations.Annotation; -import com.ibm.wala.util.collections.HashSetFactory; -import com.ibm.wala.util.config.AnalysisScopeReader; -import com.ibm.wala.util.io.FileProvider; - -public class AnnotationTest extends WalaTestCase { - - public static void main(String[] args) { - justThisTest(AnnotationTest.class); - } - - private static IClassHierarchy cha; - - @BeforeClass - public static void before() throws IOException, ClassHierarchyException { - AnalysisScope scope = AnalysisScopeReader.readJavaScope(TestConstants.WALA_TESTDATA, - (new FileProvider()).getFile(CallGraphTestUtil.REGRESSION_EXCLUSIONS), AnnotationTest.class.getClassLoader()); - cha = ClassHierarchy.make(scope); - } - - @AfterClass - public static void after() { - cha = null; - - } - @Test - public void testClassAnnotations1() throws Exception { - TypeReference typeUnderTest = TypeReference.findOrCreate(ClassLoaderReference.Application, "Lannotations/AnnotatedClass1"); - - Collection expectedRuntimeInvisibleAnnotations = HashSetFactory.make(); - expectedRuntimeInvisibleAnnotations.add(Annotation.make(TypeReference.findOrCreate(ClassLoaderReference.Application, - "Lannotations/RuntimeInvisableAnnotation"))); - expectedRuntimeInvisibleAnnotations.add(Annotation.make(TypeReference.findOrCreate(ClassLoaderReference.Application, - "Lannotations/DefaultVisableAnnotation"))); - - Collection expectedRuntimeVisibleAnnotations = HashSetFactory.make(); - expectedRuntimeVisibleAnnotations.add(Annotation.make(TypeReference.findOrCreate(ClassLoaderReference.Application, - "Lannotations/RuntimeVisableAnnotation"))); - - testClassAnnotations(typeUnderTest, expectedRuntimeInvisibleAnnotations, expectedRuntimeVisibleAnnotations); - } - - @Test - public void testClassAnnotations2() throws Exception { - TypeReference typeUnderTest = TypeReference.findOrCreate(ClassLoaderReference.Application, "Lannotations/AnnotatedClass2"); - - Collection expectedRuntimeInvisibleAnnotations = HashSetFactory.make(); - expectedRuntimeInvisibleAnnotations.add(Annotation.make(TypeReference.findOrCreate(ClassLoaderReference.Application, - "Lannotations/RuntimeInvisableAnnotation"))); - expectedRuntimeInvisibleAnnotations.add(Annotation.make(TypeReference.findOrCreate(ClassLoaderReference.Application, - "Lannotations/RuntimeInvisableAnnotation2"))); - - Collection expectedRuntimeVisibleAnnotations = HashSetFactory.make(); - expectedRuntimeVisibleAnnotations.add(Annotation.make(TypeReference.findOrCreate(ClassLoaderReference.Application, - "Lannotations/RuntimeVisableAnnotation"))); - expectedRuntimeVisibleAnnotations.add(Annotation.make(TypeReference.findOrCreate(ClassLoaderReference.Application, - "Lannotations/RuntimeVisableAnnotation2"))); - - testClassAnnotations(typeUnderTest, expectedRuntimeInvisibleAnnotations, expectedRuntimeVisibleAnnotations); - } - - private void testClassAnnotations(TypeReference typeUnderTest, Collection expectedRuntimeInvisibleAnnotations, - Collection expectedRuntimeVisibleAnnotations) throws IOException, ClassHierarchyException, - InvalidClassFileException { - IClass classUnderTest = cha.lookupClass(typeUnderTest); - Assert.assertNotNull(typeUnderTest.toString() + " not found", classUnderTest); - Assert.assertTrue(classUnderTest instanceof ShrikeClass); - ShrikeClass shrikeClassUnderTest = (ShrikeClass) classUnderTest; - - Collection runtimeInvisibleAnnotations = shrikeClassUnderTest.getRuntimeInvisibleAnnotations(); - assertEqualCollections(expectedRuntimeInvisibleAnnotations, runtimeInvisibleAnnotations); - - Collection runtimeVisibleAnnotations = shrikeClassUnderTest.getRuntimeVisibleAnnotations(); - assertEqualCollections(expectedRuntimeVisibleAnnotations, runtimeVisibleAnnotations); - } - - private void assertEqualCollections(Collection expected, Collection actual) { - if (expected == null) { - expected = Collections.emptySet(); - } - if (actual == null) { - actual = Collections.emptySet(); - } - - if (expected.size() != actual.size()) { - Assert.assertTrue("expected=" + expected + " actual=" + actual, false); - } - for (T a : expected) { - Assert.assertTrue("missing " + a.toString(), actual.contains(a)); - } - } - - @Test - public void testClassAnnotations3() throws Exception { - - TypeReference typeRef = TypeReference.findOrCreate(ClassLoaderReference.Application, "Lannotations/AnnotatedClass3"); - IClass klass = cha.lookupClass(typeRef); - Assert.assertNotNull(klass); - ShrikeClass shrikeClass = (ShrikeClass) klass; - Collection classAnnotations = shrikeClass.getAnnotations(true); - Assert.assertEquals("[Annotation type {strParam=classStrParam}]", - classAnnotations.toString()); - - MethodReference methodRefUnderTest = MethodReference.findOrCreate(typeRef, Selector.make("foo()V")); - - IMethod methodUnderTest = cha.resolveMethod(methodRefUnderTest); - Assert.assertNotNull(methodRefUnderTest.toString() + " not found", methodUnderTest); - Assert.assertTrue(methodUnderTest instanceof ShrikeCTMethod); - ShrikeCTMethod shrikeCTMethodUnderTest = (ShrikeCTMethod) methodUnderTest; - - Collection runtimeInvisibleAnnotations = shrikeCTMethodUnderTest.getAnnotations(true); - Assert - .assertEquals( - "[Annotation type {enumParam=EnumElementValue [type=Lannotations/AnnotationEnum;, val=VAL1], strArrParam=ArrayElementValue [vals=[biz, boz]], annotParam=AnnotationElementValue [type=Lannotations/AnnotationWithSingleParam;, elementValues={value=sdfevs}], strParam=sdfsevs, intParam=25, klassParam=Ljava/lang/Integer;}]", - runtimeInvisibleAnnotations.toString()); - - } -} +package com.ibm.wala.core.tests.ir; + +import java.io.IOException; +import java.util.Collection; +import java.util.Collections; + +import org.junit.AfterClass; +import org.junit.Assert; +import org.junit.BeforeClass; +import org.junit.Test; + +import com.ibm.wala.classLoader.IClass; +import com.ibm.wala.classLoader.IMethod; +import com.ibm.wala.classLoader.ShrikeCTMethod; +import com.ibm.wala.classLoader.ShrikeClass; +import com.ibm.wala.core.tests.callGraph.CallGraphTestUtil; +import com.ibm.wala.core.tests.util.TestConstants; +import com.ibm.wala.core.tests.util.WalaTestCase; +import com.ibm.wala.ipa.callgraph.AnalysisScope; +import com.ibm.wala.ipa.cha.ClassHierarchy; +import com.ibm.wala.ipa.cha.ClassHierarchyException; +import com.ibm.wala.ipa.cha.IClassHierarchy; +import com.ibm.wala.shrikeCT.InvalidClassFileException; +import com.ibm.wala.types.ClassLoaderReference; +import com.ibm.wala.types.MethodReference; +import com.ibm.wala.types.Selector; +import com.ibm.wala.types.TypeReference; +import com.ibm.wala.types.annotations.Annotation; +import com.ibm.wala.util.collections.HashSetFactory; +import com.ibm.wala.util.config.AnalysisScopeReader; +import com.ibm.wala.util.io.FileProvider; + +public class AnnotationTest extends WalaTestCase { + + public static void main(String[] args) { + justThisTest(AnnotationTest.class); + } + + private static IClassHierarchy cha; + + @BeforeClass + public static void before() throws IOException, ClassHierarchyException { + AnalysisScope scope = AnalysisScopeReader.readJavaScope(TestConstants.WALA_TESTDATA, + (new FileProvider()).getFile(CallGraphTestUtil.REGRESSION_EXCLUSIONS), AnnotationTest.class.getClassLoader()); + cha = ClassHierarchy.make(scope); + } + + @AfterClass + public static void after() { + cha = null; + + } + @Test + public void testClassAnnotations1() throws Exception { + TypeReference typeUnderTest = TypeReference.findOrCreate(ClassLoaderReference.Application, "Lannotations/AnnotatedClass1"); + + Collection expectedRuntimeInvisibleAnnotations = HashSetFactory.make(); + expectedRuntimeInvisibleAnnotations.add(Annotation.make(TypeReference.findOrCreate(ClassLoaderReference.Application, + "Lannotations/RuntimeInvisableAnnotation"))); + expectedRuntimeInvisibleAnnotations.add(Annotation.make(TypeReference.findOrCreate(ClassLoaderReference.Application, + "Lannotations/DefaultVisableAnnotation"))); + + Collection expectedRuntimeVisibleAnnotations = HashSetFactory.make(); + expectedRuntimeVisibleAnnotations.add(Annotation.make(TypeReference.findOrCreate(ClassLoaderReference.Application, + "Lannotations/RuntimeVisableAnnotation"))); + + testClassAnnotations(typeUnderTest, expectedRuntimeInvisibleAnnotations, expectedRuntimeVisibleAnnotations); + } + + @Test + public void testClassAnnotations2() throws Exception { + TypeReference typeUnderTest = TypeReference.findOrCreate(ClassLoaderReference.Application, "Lannotations/AnnotatedClass2"); + + Collection expectedRuntimeInvisibleAnnotations = HashSetFactory.make(); + expectedRuntimeInvisibleAnnotations.add(Annotation.make(TypeReference.findOrCreate(ClassLoaderReference.Application, + "Lannotations/RuntimeInvisableAnnotation"))); + expectedRuntimeInvisibleAnnotations.add(Annotation.make(TypeReference.findOrCreate(ClassLoaderReference.Application, + "Lannotations/RuntimeInvisableAnnotation2"))); + + Collection expectedRuntimeVisibleAnnotations = HashSetFactory.make(); + expectedRuntimeVisibleAnnotations.add(Annotation.make(TypeReference.findOrCreate(ClassLoaderReference.Application, + "Lannotations/RuntimeVisableAnnotation"))); + expectedRuntimeVisibleAnnotations.add(Annotation.make(TypeReference.findOrCreate(ClassLoaderReference.Application, + "Lannotations/RuntimeVisableAnnotation2"))); + + testClassAnnotations(typeUnderTest, expectedRuntimeInvisibleAnnotations, expectedRuntimeVisibleAnnotations); + } + + private void testClassAnnotations(TypeReference typeUnderTest, Collection expectedRuntimeInvisibleAnnotations, + Collection expectedRuntimeVisibleAnnotations) throws IOException, ClassHierarchyException, + InvalidClassFileException { + IClass classUnderTest = cha.lookupClass(typeUnderTest); + Assert.assertNotNull(typeUnderTest.toString() + " not found", classUnderTest); + Assert.assertTrue(classUnderTest instanceof ShrikeClass); + ShrikeClass shrikeClassUnderTest = (ShrikeClass) classUnderTest; + + Collection runtimeInvisibleAnnotations = shrikeClassUnderTest.getRuntimeInvisibleAnnotations(); + assertEqualCollections(expectedRuntimeInvisibleAnnotations, runtimeInvisibleAnnotations); + + Collection runtimeVisibleAnnotations = shrikeClassUnderTest.getRuntimeVisibleAnnotations(); + assertEqualCollections(expectedRuntimeVisibleAnnotations, runtimeVisibleAnnotations); + } + + private void assertEqualCollections(Collection expected, Collection actual) { + if (expected == null) { + expected = Collections.emptySet(); + } + if (actual == null) { + actual = Collections.emptySet(); + } + + if (expected.size() != actual.size()) { + Assert.assertTrue("expected=" + expected + " actual=" + actual, false); + } + for (T a : expected) { + Assert.assertTrue("missing " + a.toString(), actual.contains(a)); + } + } + + @Test + public void testClassAnnotations3() throws Exception { + + TypeReference typeRef = TypeReference.findOrCreate(ClassLoaderReference.Application, "Lannotations/AnnotatedClass3"); + IClass klass = cha.lookupClass(typeRef); + Assert.assertNotNull(klass); + ShrikeClass shrikeClass = (ShrikeClass) klass; + Collection classAnnotations = shrikeClass.getAnnotations(true); + Assert.assertEquals("[Annotation type {strParam=classStrParam}]", + classAnnotations.toString()); + + MethodReference methodRefUnderTest = MethodReference.findOrCreate(typeRef, Selector.make("foo()V")); + + IMethod methodUnderTest = cha.resolveMethod(methodRefUnderTest); + Assert.assertNotNull(methodRefUnderTest.toString() + " not found", methodUnderTest); + Assert.assertTrue(methodUnderTest instanceof ShrikeCTMethod); + ShrikeCTMethod shrikeCTMethodUnderTest = (ShrikeCTMethod) methodUnderTest; + + Collection runtimeInvisibleAnnotations = shrikeCTMethodUnderTest.getAnnotations(true); + Assert + .assertEquals( + "[Annotation type {enumParam=EnumElementValue [type=Lannotations/AnnotationEnum;, val=VAL1], strArrParam=ArrayElementValue [vals=[biz, boz]], annotParam=AnnotationElementValue [type=Lannotations/AnnotationWithSingleParam;, elementValues={value=sdfevs}], strParam=sdfsevs, intParam=25, klassParam=Ljava/lang/Integer;}]", + runtimeInvisibleAnnotations.toString()); + + } +} diff --git a/com.ibm.wala.core.tests/src/com/ibm/wala/core/tests/ir/CFGSanitizerTest.java b/com.ibm.wala.core.tests/src/com/ibm/wala/core/tests/ir/CFGSanitizerTest.java index 59cff7f41..2076ccf81 100644 --- a/com.ibm.wala.core.tests/src/com/ibm/wala/core/tests/ir/CFGSanitizerTest.java +++ b/com.ibm.wala.core.tests/src/com/ibm/wala/core/tests/ir/CFGSanitizerTest.java @@ -1,83 +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.core.tests.ir; - -import java.io.IOException; -import java.io.InputStream; -import java.util.Map; - -import junit.framework.Assert; - -import org.junit.Test; - -import com.ibm.wala.cfg.CFGSanitizer; -import com.ibm.wala.classLoader.IMethod; -import com.ibm.wala.core.tests.callGraph.CallGraphTestUtil; -import com.ibm.wala.core.tests.util.WalaTestCase; -import com.ibm.wala.ipa.callgraph.AnalysisOptions; -import com.ibm.wala.ipa.callgraph.AnalysisScope; -import com.ibm.wala.ipa.callgraph.impl.Everywhere; -import com.ibm.wala.ipa.cha.ClassHierarchy; -import com.ibm.wala.ipa.summaries.MethodSummary; -import com.ibm.wala.ipa.summaries.SummarizedMethod; -import com.ibm.wala.ipa.summaries.XMLMethodSummaryReader; -import com.ibm.wala.ssa.IR; -import com.ibm.wala.ssa.ISSABasicBlock; -import com.ibm.wala.ssa.SSACFG.BasicBlock; -import com.ibm.wala.types.MethodReference; -import com.ibm.wala.util.WalaException; -import com.ibm.wala.util.config.AnalysisScopeReader; -import com.ibm.wala.util.graph.Graph; -import com.ibm.wala.util.io.FileProvider; - -/** - * Test integrity of CFGs - */ -public class CFGSanitizerTest extends WalaTestCase { - - /** - * check that for all synthetic methods coming from the native specifications, the exit block is not disconnected from the rest of - * the sanitized graph - * - * @throws IOException - * @throws IllegalArgumentException - * @throws WalaException - */ - @Test - public void testSyntheticEdgeToExit() throws IOException, IllegalArgumentException, WalaException { - AnalysisScope scope = AnalysisScopeReader.makePrimordialScope((new FileProvider()).getFile(CallGraphTestUtil.REGRESSION_EXCLUSIONS)); - - ClassHierarchy cha = ClassHierarchy.make(scope); - ClassLoader cl = CFGSanitizerTest.class.getClassLoader(); - InputStream s = cl.getResourceAsStream("natives.xml"); - XMLMethodSummaryReader summary = new XMLMethodSummaryReader(s, scope); - AnalysisOptions options = new AnalysisOptions(scope, null); - Map summaries = summary.getSummaries(); - for (MethodReference mr : summaries.keySet()) { - IMethod m = cha.resolveMethod(mr); - if (m == null) { - continue; - } - System.out.println(m.getSignature()); - MethodSummary methodSummary = summaries.get(mr); - SummarizedMethod summMethod = new SummarizedMethod(mr, methodSummary, m.getDeclaringClass()); - IR ir = summMethod.makeIR(Everywhere.EVERYWHERE, options.getSSAOptions()); - System.out.println(ir); - Graph graph = CFGSanitizer.sanitize(ir, cha); - System.out.println(graph); - BasicBlock exit = ir.getControlFlowGraph().exit(); - if (!exit.equals(ir.getControlFlowGraph().entry())) { - Assert.assertTrue(graph.getPredNodeCount(exit) > 0); - } - } - } - -} +/******************************************************************************* + * 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.core.tests.ir; + +import java.io.IOException; +import java.io.InputStream; +import java.util.Map; + +import junit.framework.Assert; + +import org.junit.Test; + +import com.ibm.wala.cfg.CFGSanitizer; +import com.ibm.wala.classLoader.IMethod; +import com.ibm.wala.core.tests.callGraph.CallGraphTestUtil; +import com.ibm.wala.core.tests.util.WalaTestCase; +import com.ibm.wala.ipa.callgraph.AnalysisOptions; +import com.ibm.wala.ipa.callgraph.AnalysisScope; +import com.ibm.wala.ipa.callgraph.impl.Everywhere; +import com.ibm.wala.ipa.cha.ClassHierarchy; +import com.ibm.wala.ipa.summaries.MethodSummary; +import com.ibm.wala.ipa.summaries.SummarizedMethod; +import com.ibm.wala.ipa.summaries.XMLMethodSummaryReader; +import com.ibm.wala.ssa.IR; +import com.ibm.wala.ssa.ISSABasicBlock; +import com.ibm.wala.ssa.SSACFG.BasicBlock; +import com.ibm.wala.types.MethodReference; +import com.ibm.wala.util.WalaException; +import com.ibm.wala.util.config.AnalysisScopeReader; +import com.ibm.wala.util.graph.Graph; +import com.ibm.wala.util.io.FileProvider; + +/** + * Test integrity of CFGs + */ +public class CFGSanitizerTest extends WalaTestCase { + + /** + * check that for all synthetic methods coming from the native specifications, the exit block is not disconnected from the rest of + * the sanitized graph + * + * @throws IOException + * @throws IllegalArgumentException + * @throws WalaException + */ + @Test + public void testSyntheticEdgeToExit() throws IOException, IllegalArgumentException, WalaException { + AnalysisScope scope = AnalysisScopeReader.makePrimordialScope((new FileProvider()).getFile(CallGraphTestUtil.REGRESSION_EXCLUSIONS)); + + ClassHierarchy cha = ClassHierarchy.make(scope); + ClassLoader cl = CFGSanitizerTest.class.getClassLoader(); + InputStream s = cl.getResourceAsStream("natives.xml"); + XMLMethodSummaryReader summary = new XMLMethodSummaryReader(s, scope); + AnalysisOptions options = new AnalysisOptions(scope, null); + Map summaries = summary.getSummaries(); + for (MethodReference mr : summaries.keySet()) { + IMethod m = cha.resolveMethod(mr); + if (m == null) { + continue; + } + System.out.println(m.getSignature()); + MethodSummary methodSummary = summaries.get(mr); + SummarizedMethod summMethod = new SummarizedMethod(mr, methodSummary, m.getDeclaringClass()); + IR ir = summMethod.makeIR(Everywhere.EVERYWHERE, options.getSSAOptions()); + System.out.println(ir); + Graph graph = CFGSanitizer.sanitize(ir, cha); + System.out.println(graph); + BasicBlock exit = ir.getControlFlowGraph().exit(); + if (!exit.equals(ir.getControlFlowGraph().entry())) { + Assert.assertTrue(graph.getPredNodeCount(exit) > 0); + } + } + } + +} diff --git a/com.ibm.wala.core.tests/src/com/ibm/wala/core/tests/ir/CFGTest.java b/com.ibm.wala.core.tests/src/com/ibm/wala/core/tests/ir/CFGTest.java index c04e5a357..82ab91622 100644 --- a/com.ibm.wala.core.tests/src/com/ibm/wala/core/tests/ir/CFGTest.java +++ b/com.ibm.wala.core.tests/src/com/ibm/wala/core/tests/ir/CFGTest.java @@ -1,178 +1,178 @@ -/******************************************************************************* - * 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.core.tests.ir; - -import org.junit.AfterClass; -import org.junit.Assert; -import org.junit.BeforeClass; -import org.junit.Test; - -import com.ibm.wala.cfg.ControlFlowGraph; -import com.ibm.wala.classLoader.ClassLoaderFactory; -import com.ibm.wala.classLoader.ClassLoaderFactoryImpl; -import com.ibm.wala.classLoader.IMethod; -import com.ibm.wala.classLoader.Language; -import com.ibm.wala.core.tests.util.TestConstants; -import com.ibm.wala.core.tests.util.WalaTestCase; -import com.ibm.wala.ipa.callgraph.AnalysisCache; -import com.ibm.wala.ipa.callgraph.AnalysisOptions; -import com.ibm.wala.ipa.callgraph.AnalysisScope; -import com.ibm.wala.ipa.callgraph.impl.Everywhere; -import com.ibm.wala.ipa.cha.ClassHierarchy; -import com.ibm.wala.ipa.cha.ClassHierarchyException; -import com.ibm.wala.ssa.IR; -import com.ibm.wala.ssa.ISSABasicBlock; -import com.ibm.wala.ssa.SSACFG; -import com.ibm.wala.ssa.SSAInstruction; -import com.ibm.wala.ssa.SSAOptions; -import com.ibm.wala.types.MethodReference; -import com.ibm.wala.util.config.AnalysisScopeReader; -import com.ibm.wala.util.debug.Assertions; -import com.ibm.wala.util.graph.GraphIntegrity; -import com.ibm.wala.util.graph.GraphIntegrity.UnsoundGraphException; -import com.ibm.wala.util.intset.IntSet; -import com.ibm.wala.util.io.FileProvider; -import com.ibm.wala.util.strings.StringStuff; -import com.ibm.wala.util.warnings.Warnings; - -/** - * Test integrity of CFGs - */ -public class CFGTest extends WalaTestCase { - - private static AnalysisScope scope; - - private static ClassHierarchy cha; - - @BeforeClass - public static void beforeClass() throws Exception { - - scope = AnalysisScopeReader.readJavaScope(TestConstants.WALA_TESTDATA, - (new FileProvider()).getFile("J2SEClassHierarchyExclusions.txt"), CFGTest.class.getClassLoader()); - ClassLoaderFactory factory = new ClassLoaderFactoryImpl(scope.getExclusions()); - - try { - cha = ClassHierarchy.make(scope, factory); - } catch (ClassHierarchyException e) { - throw new Exception(); - } - } - - @AfterClass - public static void afterClass() throws Exception { - Warnings.clear(); - scope = null; - cha = null; - } - - public static void main(String[] args) { - justThisTest(CFGTest.class); - } - - /** - * Build an IR, then check integrity on two flavors of CFG - */ - private void doMethod(String methodSig) { - try { - MethodReference mr = StringStuff.makeMethodReference(Language.JAVA, methodSig); - - IMethod m = cha.resolveMethod(mr); - if (m == null) { - Assertions.UNREACHABLE("could not resolve " + mr); - } - AnalysisOptions options = new AnalysisOptions(); - AnalysisCache cache = new AnalysisCache(); - options.getSSAOptions().setPiNodePolicy(SSAOptions.getAllBuiltInPiNodes()); - IR ir = cache.getSSACache().findOrCreateIR(m, Everywhere.EVERYWHERE, options.getSSAOptions()); - - ControlFlowGraph cfg = ir.getControlFlowGraph(); - try { - GraphIntegrity.check(cfg); - } catch (UnsoundGraphException e) { - e.printStackTrace(); - System.err.println(ir); - Assert.assertTrue(" failed cfg integrity check for " + methodSig, false); - } - - try { - GraphIntegrity.check(cfg); - } catch (UnsoundGraphException e) { - e.printStackTrace(); - System.err.println(ir); - System.err.println(cfg); - Assert.assertTrue(" failed 2-exit cfg integrity check for " + methodSig, false); - } - } catch (Exception e) { - e.printStackTrace(); - Assertions.UNREACHABLE(); - } - } - - /** - * this method does not exist in 1.5 libraries @Test public void - * testFDBigInt() { - * doMethod("java.lang.FDBigInt.class$(Ljava/lang/String;)Ljava/lang/Class;"); - * } - */ - - @Test - public void testResolveProxyClass() { - doMethod("java.io.ObjectInputStream.resolveProxyClass([Ljava/lang/String;)Ljava/lang/Class;"); - } - - @Test - public void testSync1() { - MethodReference mr = StringStuff.makeMethodReference("cfg.MonitorTest.sync1()V"); - - IMethod m = cha.resolveMethod(mr); - AnalysisCache cache = new AnalysisCache(); - IR ir = cache.getIR(m); - System.out.println(ir); - SSACFG controlFlowGraph = ir.getControlFlowGraph(); - Assert.assertEquals(1, controlFlowGraph.getSuccNodeCount(controlFlowGraph.getBlockForInstruction(21))); - } - - @Test - public void testSync2() { - MethodReference mr = StringStuff.makeMethodReference("cfg.MonitorTest.sync2()V"); - - IMethod m = cha.resolveMethod(mr); - AnalysisCache cache = new AnalysisCache(); - IR ir = cache.getIR(m); - System.out.println(ir); - SSACFG controlFlowGraph = ir.getControlFlowGraph(); - IntSet succs = controlFlowGraph.getSuccNodeNumbers(controlFlowGraph.getBlockForInstruction(13)); - Assert.assertEquals(2, succs.size()); - Assert.assertTrue(succs.contains(6)); - Assert.assertTrue(succs.contains(7)); - } - - @Test - public void testSync3() { - MethodReference mr = StringStuff.makeMethodReference("cfg.MonitorTest.sync3()V"); - - IMethod m = cha.resolveMethod(mr); - AnalysisCache cache = new AnalysisCache(); - IR ir = cache.getIR(m); - SSACFG controlFlowGraph = ir.getControlFlowGraph(); - Assert.assertEquals(1, controlFlowGraph.getSuccNodeCount(controlFlowGraph.getBlockForInstruction(33))); - } - - public static void testCFG(SSACFG cfg, int[][] assertions) { - for(int i = 0; i < assertions.length; i++) { - SSACFG.BasicBlock bb= cfg.getNode(i); - Assert.assertEquals("basic block " + i, assertions[i].length, cfg.getSuccNodeCount(bb)); - for(int j = 0; j < assertions[i].length; j++) { - Assert.assertTrue(cfg.hasEdge(bb, cfg.getNode(assertions[i][j]))); - } - } - } -} +/******************************************************************************* + * 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.core.tests.ir; + +import org.junit.AfterClass; +import org.junit.Assert; +import org.junit.BeforeClass; +import org.junit.Test; + +import com.ibm.wala.cfg.ControlFlowGraph; +import com.ibm.wala.classLoader.ClassLoaderFactory; +import com.ibm.wala.classLoader.ClassLoaderFactoryImpl; +import com.ibm.wala.classLoader.IMethod; +import com.ibm.wala.classLoader.Language; +import com.ibm.wala.core.tests.util.TestConstants; +import com.ibm.wala.core.tests.util.WalaTestCase; +import com.ibm.wala.ipa.callgraph.AnalysisCache; +import com.ibm.wala.ipa.callgraph.AnalysisOptions; +import com.ibm.wala.ipa.callgraph.AnalysisScope; +import com.ibm.wala.ipa.callgraph.impl.Everywhere; +import com.ibm.wala.ipa.cha.ClassHierarchy; +import com.ibm.wala.ipa.cha.ClassHierarchyException; +import com.ibm.wala.ssa.IR; +import com.ibm.wala.ssa.ISSABasicBlock; +import com.ibm.wala.ssa.SSACFG; +import com.ibm.wala.ssa.SSAInstruction; +import com.ibm.wala.ssa.SSAOptions; +import com.ibm.wala.types.MethodReference; +import com.ibm.wala.util.config.AnalysisScopeReader; +import com.ibm.wala.util.debug.Assertions; +import com.ibm.wala.util.graph.GraphIntegrity; +import com.ibm.wala.util.graph.GraphIntegrity.UnsoundGraphException; +import com.ibm.wala.util.intset.IntSet; +import com.ibm.wala.util.io.FileProvider; +import com.ibm.wala.util.strings.StringStuff; +import com.ibm.wala.util.warnings.Warnings; + +/** + * Test integrity of CFGs + */ +public class CFGTest extends WalaTestCase { + + private static AnalysisScope scope; + + private static ClassHierarchy cha; + + @BeforeClass + public static void beforeClass() throws Exception { + + scope = AnalysisScopeReader.readJavaScope(TestConstants.WALA_TESTDATA, + (new FileProvider()).getFile("J2SEClassHierarchyExclusions.txt"), CFGTest.class.getClassLoader()); + ClassLoaderFactory factory = new ClassLoaderFactoryImpl(scope.getExclusions()); + + try { + cha = ClassHierarchy.make(scope, factory); + } catch (ClassHierarchyException e) { + throw new Exception(); + } + } + + @AfterClass + public static void afterClass() throws Exception { + Warnings.clear(); + scope = null; + cha = null; + } + + public static void main(String[] args) { + justThisTest(CFGTest.class); + } + + /** + * Build an IR, then check integrity on two flavors of CFG + */ + private void doMethod(String methodSig) { + try { + MethodReference mr = StringStuff.makeMethodReference(Language.JAVA, methodSig); + + IMethod m = cha.resolveMethod(mr); + if (m == null) { + Assertions.UNREACHABLE("could not resolve " + mr); + } + AnalysisOptions options = new AnalysisOptions(); + AnalysisCache cache = new AnalysisCache(); + options.getSSAOptions().setPiNodePolicy(SSAOptions.getAllBuiltInPiNodes()); + IR ir = cache.getSSACache().findOrCreateIR(m, Everywhere.EVERYWHERE, options.getSSAOptions()); + + ControlFlowGraph cfg = ir.getControlFlowGraph(); + try { + GraphIntegrity.check(cfg); + } catch (UnsoundGraphException e) { + e.printStackTrace(); + System.err.println(ir); + Assert.assertTrue(" failed cfg integrity check for " + methodSig, false); + } + + try { + GraphIntegrity.check(cfg); + } catch (UnsoundGraphException e) { + e.printStackTrace(); + System.err.println(ir); + System.err.println(cfg); + Assert.assertTrue(" failed 2-exit cfg integrity check for " + methodSig, false); + } + } catch (Exception e) { + e.printStackTrace(); + Assertions.UNREACHABLE(); + } + } + + /** + * this method does not exist in 1.5 libraries @Test public void + * testFDBigInt() { + * doMethod("java.lang.FDBigInt.class$(Ljava/lang/String;)Ljava/lang/Class;"); + * } + */ + + @Test + public void testResolveProxyClass() { + doMethod("java.io.ObjectInputStream.resolveProxyClass([Ljava/lang/String;)Ljava/lang/Class;"); + } + + @Test + public void testSync1() { + MethodReference mr = StringStuff.makeMethodReference("cfg.MonitorTest.sync1()V"); + + IMethod m = cha.resolveMethod(mr); + AnalysisCache cache = new AnalysisCache(); + IR ir = cache.getIR(m); + System.out.println(ir); + SSACFG controlFlowGraph = ir.getControlFlowGraph(); + Assert.assertEquals(1, controlFlowGraph.getSuccNodeCount(controlFlowGraph.getBlockForInstruction(21))); + } + + @Test + public void testSync2() { + MethodReference mr = StringStuff.makeMethodReference("cfg.MonitorTest.sync2()V"); + + IMethod m = cha.resolveMethod(mr); + AnalysisCache cache = new AnalysisCache(); + IR ir = cache.getIR(m); + System.out.println(ir); + SSACFG controlFlowGraph = ir.getControlFlowGraph(); + IntSet succs = controlFlowGraph.getSuccNodeNumbers(controlFlowGraph.getBlockForInstruction(13)); + Assert.assertEquals(2, succs.size()); + Assert.assertTrue(succs.contains(6)); + Assert.assertTrue(succs.contains(7)); + } + + @Test + public void testSync3() { + MethodReference mr = StringStuff.makeMethodReference("cfg.MonitorTest.sync3()V"); + + IMethod m = cha.resolveMethod(mr); + AnalysisCache cache = new AnalysisCache(); + IR ir = cache.getIR(m); + SSACFG controlFlowGraph = ir.getControlFlowGraph(); + Assert.assertEquals(1, controlFlowGraph.getSuccNodeCount(controlFlowGraph.getBlockForInstruction(33))); + } + + public static void testCFG(SSACFG cfg, int[][] assertions) { + for(int i = 0; i < assertions.length; i++) { + SSACFG.BasicBlock bb= cfg.getNode(i); + Assert.assertEquals("basic block " + i, assertions[i].length, cfg.getSuccNodeCount(bb)); + for(int j = 0; j < assertions[i].length; j++) { + Assert.assertTrue(cfg.hasEdge(bb, cfg.getNode(assertions[i][j]))); + } + } + } +} diff --git a/com.ibm.wala.core.tests/src/com/ibm/wala/core/tests/ir/CornerCasesTest.java b/com.ibm.wala.core.tests/src/com/ibm/wala/core/tests/ir/CornerCasesTest.java index dd77575d2..8274d8f8b 100644 --- a/com.ibm.wala.core.tests/src/com/ibm/wala/core/tests/ir/CornerCasesTest.java +++ b/com.ibm.wala.core.tests/src/com/ibm/wala/core/tests/ir/CornerCasesTest.java @@ -1,87 +1,87 @@ -/******************************************************************************* - * Copyright (c) 2002 - 2006 IBM Corporation. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * IBM Corporation - initial API and implementation - *******************************************************************************/ -package com.ibm.wala.core.tests.ir; - -import java.io.IOException; - -import org.junit.Assert; -import org.junit.Test; - -import com.ibm.wala.analysis.typeInference.TypeInference; -import com.ibm.wala.classLoader.IClass; -import com.ibm.wala.classLoader.IMethod; -import com.ibm.wala.classLoader.ShrikeCTMethod; -import com.ibm.wala.core.tests.util.TestConstants; -import com.ibm.wala.core.tests.util.WalaTestCase; -import com.ibm.wala.ipa.callgraph.AnalysisCache; -import com.ibm.wala.ipa.callgraph.AnalysisOptions; -import com.ibm.wala.ipa.callgraph.AnalysisScope; -import com.ibm.wala.ipa.callgraph.impl.Everywhere; -import com.ibm.wala.ipa.cha.ClassHierarchy; -import com.ibm.wala.ipa.cha.ClassHierarchyException; -import com.ibm.wala.ssa.IR; -import com.ibm.wala.types.Descriptor; -import com.ibm.wala.types.Selector; -import com.ibm.wala.types.TypeReference; -import com.ibm.wala.util.config.AnalysisScopeReader; -import com.ibm.wala.util.io.FileProvider; -import com.ibm.wala.util.strings.Atom; - -/** - * tests for weird corner cases, such as when the input program doesn't verify - * - * @author sfink - */ -public class CornerCasesTest extends WalaTestCase { - - private static final ClassLoader MY_CLASSLOADER = CornerCasesTest.class.getClassLoader(); - - /** - * test that getMethod() works even if a declared ancestor interface doesn't - * exist - * - * @throws ClassHierarchyException - * @throws IOException - */ - @Test public void testBug38484() throws ClassHierarchyException, IOException { - AnalysisScope scope = null; - scope = AnalysisScopeReader.readJavaScope(TestConstants.WALA_TESTDATA, (new FileProvider()).getFile("J2SEClassHierarchyExclusions.txt"), MY_CLASSLOADER); - ClassHierarchy cha = ClassHierarchy.make(scope); - TypeReference t = TypeReference.findOrCreateClass(scope.getApplicationLoader(), "cornerCases", "YuckyInterface"); - IClass klass = cha.lookupClass(t); - Assert.assertTrue(klass != null); - IMethod m = klass.getMethod(new Selector(Atom.findOrCreateAsciiAtom("x"), Descriptor.findOrCreateUTF8("()V"))); - Assert.assertTrue(m == null); - } - - /** - * test that type inference works in the presence of a getfield where the - * field's declared type cannot be loaded - * - * @throws ClassHierarchyException - * @throws IOException - */ - @Test public void testBug38540() throws ClassHierarchyException, IOException { - AnalysisScope scope = null; - scope = AnalysisScopeReader.readJavaScope(TestConstants.WALA_TESTDATA, (new FileProvider()).getFile("J2SEClassHierarchyExclusions.txt"), MY_CLASSLOADER); - AnalysisOptions options = new AnalysisOptions(); - ClassHierarchy cha = ClassHierarchy.make(scope); - TypeReference t = TypeReference.findOrCreateClass(scope.getApplicationLoader(), "cornerCases", "Main"); - IClass klass = cha.lookupClass(t); - Assert.assertTrue(klass != null); - ShrikeCTMethod m = (ShrikeCTMethod) klass.getMethod(new Selector(Atom.findOrCreateAsciiAtom("foo"), Descriptor - .findOrCreateUTF8("()Ljava/lang/Object;"))); - Assert.assertTrue(m != null); - IR ir = new AnalysisCache().getSSACache().findOrCreateIR(m, Everywhere.EVERYWHERE, options.getSSAOptions()); - TypeInference.make(ir, false); - } - -} +/******************************************************************************* + * 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.core.tests.ir; + +import java.io.IOException; + +import org.junit.Assert; +import org.junit.Test; + +import com.ibm.wala.analysis.typeInference.TypeInference; +import com.ibm.wala.classLoader.IClass; +import com.ibm.wala.classLoader.IMethod; +import com.ibm.wala.classLoader.ShrikeCTMethod; +import com.ibm.wala.core.tests.util.TestConstants; +import com.ibm.wala.core.tests.util.WalaTestCase; +import com.ibm.wala.ipa.callgraph.AnalysisCache; +import com.ibm.wala.ipa.callgraph.AnalysisOptions; +import com.ibm.wala.ipa.callgraph.AnalysisScope; +import com.ibm.wala.ipa.callgraph.impl.Everywhere; +import com.ibm.wala.ipa.cha.ClassHierarchy; +import com.ibm.wala.ipa.cha.ClassHierarchyException; +import com.ibm.wala.ssa.IR; +import com.ibm.wala.types.Descriptor; +import com.ibm.wala.types.Selector; +import com.ibm.wala.types.TypeReference; +import com.ibm.wala.util.config.AnalysisScopeReader; +import com.ibm.wala.util.io.FileProvider; +import com.ibm.wala.util.strings.Atom; + +/** + * tests for weird corner cases, such as when the input program doesn't verify + * + * @author sfink + */ +public class CornerCasesTest extends WalaTestCase { + + private static final ClassLoader MY_CLASSLOADER = CornerCasesTest.class.getClassLoader(); + + /** + * test that getMethod() works even if a declared ancestor interface doesn't + * exist + * + * @throws ClassHierarchyException + * @throws IOException + */ + @Test public void testBug38484() throws ClassHierarchyException, IOException { + AnalysisScope scope = null; + scope = AnalysisScopeReader.readJavaScope(TestConstants.WALA_TESTDATA, (new FileProvider()).getFile("J2SEClassHierarchyExclusions.txt"), MY_CLASSLOADER); + ClassHierarchy cha = ClassHierarchy.make(scope); + TypeReference t = TypeReference.findOrCreateClass(scope.getApplicationLoader(), "cornerCases", "YuckyInterface"); + IClass klass = cha.lookupClass(t); + Assert.assertTrue(klass != null); + IMethod m = klass.getMethod(new Selector(Atom.findOrCreateAsciiAtom("x"), Descriptor.findOrCreateUTF8("()V"))); + Assert.assertTrue(m == null); + } + + /** + * test that type inference works in the presence of a getfield where the + * field's declared type cannot be loaded + * + * @throws ClassHierarchyException + * @throws IOException + */ + @Test public void testBug38540() throws ClassHierarchyException, IOException { + AnalysisScope scope = null; + scope = AnalysisScopeReader.readJavaScope(TestConstants.WALA_TESTDATA, (new FileProvider()).getFile("J2SEClassHierarchyExclusions.txt"), MY_CLASSLOADER); + AnalysisOptions options = new AnalysisOptions(); + ClassHierarchy cha = ClassHierarchy.make(scope); + TypeReference t = TypeReference.findOrCreateClass(scope.getApplicationLoader(), "cornerCases", "Main"); + IClass klass = cha.lookupClass(t); + Assert.assertTrue(klass != null); + ShrikeCTMethod m = (ShrikeCTMethod) klass.getMethod(new Selector(Atom.findOrCreateAsciiAtom("foo"), Descriptor + .findOrCreateUTF8("()Ljava/lang/Object;"))); + Assert.assertTrue(m != null); + IR ir = new AnalysisCache().getSSACache().findOrCreateIR(m, Everywhere.EVERYWHERE, options.getSSAOptions()); + TypeInference.make(ir, false); + } + +} diff --git a/com.ibm.wala.core.tests/src/com/ibm/wala/core/tests/ir/DeterministicIRTest.java b/com.ibm.wala.core.tests/src/com/ibm/wala/core/tests/ir/DeterministicIRTest.java index b2601aa47..260205f64 100644 --- a/com.ibm.wala.core.tests/src/com/ibm/wala/core/tests/ir/DeterministicIRTest.java +++ b/com.ibm.wala.core.tests/src/com/ibm/wala/core/tests/ir/DeterministicIRTest.java @@ -1,173 +1,173 @@ -/******************************************************************************* - * 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.core.tests.ir; - -import java.util.Iterator; - -import org.junit.AfterClass; -import org.junit.Assert; -import org.junit.BeforeClass; -import org.junit.Test; - -import com.ibm.wala.classLoader.ClassLoaderFactory; -import com.ibm.wala.classLoader.ClassLoaderFactoryImpl; -import com.ibm.wala.classLoader.IMethod; -import com.ibm.wala.core.tests.util.TestConstants; -import com.ibm.wala.core.tests.util.WalaTestCase; -import com.ibm.wala.ipa.callgraph.AnalysisCache; -import com.ibm.wala.ipa.callgraph.AnalysisOptions; -import com.ibm.wala.ipa.callgraph.AnalysisScope; -import com.ibm.wala.ipa.callgraph.impl.Everywhere; -import com.ibm.wala.ipa.cha.ClassHierarchy; -import com.ibm.wala.ipa.cha.ClassHierarchyException; -import com.ibm.wala.ssa.IR; -import com.ibm.wala.ssa.SSAInstruction; -import com.ibm.wala.types.MethodReference; -import com.ibm.wala.util.config.AnalysisScopeReader; -import com.ibm.wala.util.graph.GraphIntegrity; -import com.ibm.wala.util.graph.GraphIntegrity.UnsoundGraphException; -import com.ibm.wala.util.io.FileProvider; -import com.ibm.wala.util.strings.Atom; -import com.ibm.wala.util.strings.ImmutableByteArray; -import com.ibm.wala.util.strings.UTF8Convert; -import com.ibm.wala.util.warnings.Warnings; - -/** - * Test that the SSA-numbering of variables in the IR is deterministic. - * - * Introduced 05-AUG-03; the default implementation of hashCode was being invoked. Object.hashCode is a source of random numbers and - * has no place in a deterministic program. - */ -public class DeterministicIRTest extends WalaTestCase { - - private static final ClassLoader MY_CLASSLOADER = DeterministicIRTest.class.getClassLoader(); - - private static AnalysisScope scope; - - private static ClassHierarchy cha; - - private static AnalysisOptions options; - - private static AnalysisCache cache; - - public static void main(String[] args) { - justThisTest(DeterministicIRTest.class); - } - - @BeforeClass - public static void beforeClass() throws Exception { - - scope = AnalysisScopeReader.readJavaScope(TestConstants.WALA_TESTDATA, - (new FileProvider()).getFile("J2SEClassHierarchyExclusions.txt"), MY_CLASSLOADER); - options = new AnalysisOptions(scope, null); - cache = new AnalysisCache(); - ClassLoaderFactory factory = new ClassLoaderFactoryImpl(scope.getExclusions()); - - try { - cha = ClassHierarchy.make(scope, factory); - } catch (ClassHierarchyException e) { - throw new Exception(); - } - } - - @AfterClass - public static void afterClass() throws Exception { - Warnings.clear(); - scope = null; - cha = null; - options = null; - cache = null; - } - - /** - * @param method - */ - private IR doMethod(MethodReference method) { - Assert.assertNotNull("method not found", method); - IMethod imethod = cha.resolveMethod(method); - Assert.assertNotNull("imethod not found", imethod); - IR ir1 = cache.getIRFactory().makeIR(imethod, Everywhere.EVERYWHERE, options.getSSAOptions()); - cache.getSSACache().wipe(); - - checkNotAllNull(ir1.getInstructions()); - checkNoneNull(ir1.iterateAllInstructions()); - try { - GraphIntegrity.check(ir1.getControlFlowGraph()); - } catch (UnsoundGraphException e) { - System.err.println(ir1); - e.printStackTrace(); - Assert.assertTrue("unsound CFG for ir1", false); - } - - IR ir2 = cache.getIRFactory().makeIR(imethod, Everywhere.EVERYWHERE, options.getSSAOptions()); - cache.getSSACache().wipe(); - - try { - GraphIntegrity.check(ir2.getControlFlowGraph()); - } catch (UnsoundGraphException e1) { - System.err.println(ir2); - e1.printStackTrace(); - Assert.assertTrue("unsound CFG for ir2", false); - } - - Assert.assertEquals(ir1.toString(), ir2.toString()); - return ir1; - } - - // The Tests /////////////////////////////////////////////////////// - - /** - * @param iterator - */ - private void checkNoneNull(Iterator iterator) { - while (iterator.hasNext()) { - Assert.assertTrue(iterator.next() != null); - } - - } - - /** - * @param instructions - */ - private static void checkNotAllNull(SSAInstruction[] instructions) { - for (int i = 0; i < instructions.length; i++) { - if (instructions[i] != null) { - return; - } - } - Assert.assertTrue("no instructions generated", false); - } - - @Test public void testIR1() { - // 'remove' is a nice short method - doMethod(scope.findMethod(AnalysisScope.APPLICATION, "Ljava/util/HashMap", Atom.findOrCreateUnicodeAtom("remove"), - new ImmutableByteArray(UTF8Convert.toUTF8("(Ljava/lang/Object;)Ljava/lang/Object;")))); - } - - @Test public void testIR2() { - // 'equals' is a nice medium-sized method - doMethod(scope.findMethod(AnalysisScope.APPLICATION, "Ljava/lang/String", Atom.findOrCreateUnicodeAtom("equals"), - new ImmutableByteArray(UTF8Convert.toUTF8("(Ljava/lang/Object;)Z")))); - } - - @Test public void testIR3() { - // 'resolveProxyClass' is a nice long method (at least in Sun libs) - doMethod(scope.findMethod(AnalysisScope.APPLICATION, "Ljava/io/ObjectInputStream", Atom - .findOrCreateUnicodeAtom("resolveProxyClass"), new ImmutableByteArray(UTF8Convert - .toUTF8("([Ljava/lang/String;)Ljava/lang/Class;")))); - } - - @Test public void testIR4() { - // test some corner cases with try-finally - doMethod(scope.findMethod(AnalysisScope.APPLICATION, "LcornerCases/TryFinally", Atom.findOrCreateUnicodeAtom("test1"), - new ImmutableByteArray(UTF8Convert.toUTF8("(Ljava/io/InputStream;Ljava/io/InputStream;)V")))); - } -} +/******************************************************************************* + * 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.core.tests.ir; + +import java.util.Iterator; + +import org.junit.AfterClass; +import org.junit.Assert; +import org.junit.BeforeClass; +import org.junit.Test; + +import com.ibm.wala.classLoader.ClassLoaderFactory; +import com.ibm.wala.classLoader.ClassLoaderFactoryImpl; +import com.ibm.wala.classLoader.IMethod; +import com.ibm.wala.core.tests.util.TestConstants; +import com.ibm.wala.core.tests.util.WalaTestCase; +import com.ibm.wala.ipa.callgraph.AnalysisCache; +import com.ibm.wala.ipa.callgraph.AnalysisOptions; +import com.ibm.wala.ipa.callgraph.AnalysisScope; +import com.ibm.wala.ipa.callgraph.impl.Everywhere; +import com.ibm.wala.ipa.cha.ClassHierarchy; +import com.ibm.wala.ipa.cha.ClassHierarchyException; +import com.ibm.wala.ssa.IR; +import com.ibm.wala.ssa.SSAInstruction; +import com.ibm.wala.types.MethodReference; +import com.ibm.wala.util.config.AnalysisScopeReader; +import com.ibm.wala.util.graph.GraphIntegrity; +import com.ibm.wala.util.graph.GraphIntegrity.UnsoundGraphException; +import com.ibm.wala.util.io.FileProvider; +import com.ibm.wala.util.strings.Atom; +import com.ibm.wala.util.strings.ImmutableByteArray; +import com.ibm.wala.util.strings.UTF8Convert; +import com.ibm.wala.util.warnings.Warnings; + +/** + * Test that the SSA-numbering of variables in the IR is deterministic. + * + * Introduced 05-AUG-03; the default implementation of hashCode was being invoked. Object.hashCode is a source of random numbers and + * has no place in a deterministic program. + */ +public class DeterministicIRTest extends WalaTestCase { + + private static final ClassLoader MY_CLASSLOADER = DeterministicIRTest.class.getClassLoader(); + + private static AnalysisScope scope; + + private static ClassHierarchy cha; + + private static AnalysisOptions options; + + private static AnalysisCache cache; + + public static void main(String[] args) { + justThisTest(DeterministicIRTest.class); + } + + @BeforeClass + public static void beforeClass() throws Exception { + + scope = AnalysisScopeReader.readJavaScope(TestConstants.WALA_TESTDATA, + (new FileProvider()).getFile("J2SEClassHierarchyExclusions.txt"), MY_CLASSLOADER); + options = new AnalysisOptions(scope, null); + cache = new AnalysisCache(); + ClassLoaderFactory factory = new ClassLoaderFactoryImpl(scope.getExclusions()); + + try { + cha = ClassHierarchy.make(scope, factory); + } catch (ClassHierarchyException e) { + throw new Exception(); + } + } + + @AfterClass + public static void afterClass() throws Exception { + Warnings.clear(); + scope = null; + cha = null; + options = null; + cache = null; + } + + /** + * @param method + */ + private IR doMethod(MethodReference method) { + Assert.assertNotNull("method not found", method); + IMethod imethod = cha.resolveMethod(method); + Assert.assertNotNull("imethod not found", imethod); + IR ir1 = cache.getIRFactory().makeIR(imethod, Everywhere.EVERYWHERE, options.getSSAOptions()); + cache.getSSACache().wipe(); + + checkNotAllNull(ir1.getInstructions()); + checkNoneNull(ir1.iterateAllInstructions()); + try { + GraphIntegrity.check(ir1.getControlFlowGraph()); + } catch (UnsoundGraphException e) { + System.err.println(ir1); + e.printStackTrace(); + Assert.assertTrue("unsound CFG for ir1", false); + } + + IR ir2 = cache.getIRFactory().makeIR(imethod, Everywhere.EVERYWHERE, options.getSSAOptions()); + cache.getSSACache().wipe(); + + try { + GraphIntegrity.check(ir2.getControlFlowGraph()); + } catch (UnsoundGraphException e1) { + System.err.println(ir2); + e1.printStackTrace(); + Assert.assertTrue("unsound CFG for ir2", false); + } + + Assert.assertEquals(ir1.toString(), ir2.toString()); + return ir1; + } + + // The Tests /////////////////////////////////////////////////////// + + /** + * @param iterator + */ + private void checkNoneNull(Iterator iterator) { + while (iterator.hasNext()) { + Assert.assertTrue(iterator.next() != null); + } + + } + + /** + * @param instructions + */ + private static void checkNotAllNull(SSAInstruction[] instructions) { + for (int i = 0; i < instructions.length; i++) { + if (instructions[i] != null) { + return; + } + } + Assert.assertTrue("no instructions generated", false); + } + + @Test public void testIR1() { + // 'remove' is a nice short method + doMethod(scope.findMethod(AnalysisScope.APPLICATION, "Ljava/util/HashMap", Atom.findOrCreateUnicodeAtom("remove"), + new ImmutableByteArray(UTF8Convert.toUTF8("(Ljava/lang/Object;)Ljava/lang/Object;")))); + } + + @Test public void testIR2() { + // 'equals' is a nice medium-sized method + doMethod(scope.findMethod(AnalysisScope.APPLICATION, "Ljava/lang/String", Atom.findOrCreateUnicodeAtom("equals"), + new ImmutableByteArray(UTF8Convert.toUTF8("(Ljava/lang/Object;)Z")))); + } + + @Test public void testIR3() { + // 'resolveProxyClass' is a nice long method (at least in Sun libs) + doMethod(scope.findMethod(AnalysisScope.APPLICATION, "Ljava/io/ObjectInputStream", Atom + .findOrCreateUnicodeAtom("resolveProxyClass"), new ImmutableByteArray(UTF8Convert + .toUTF8("([Ljava/lang/String;)Ljava/lang/Class;")))); + } + + @Test public void testIR4() { + // test some corner cases with try-finally + doMethod(scope.findMethod(AnalysisScope.APPLICATION, "LcornerCases/TryFinally", Atom.findOrCreateUnicodeAtom("test1"), + new ImmutableByteArray(UTF8Convert.toUTF8("(Ljava/io/InputStream;Ljava/io/InputStream;)V")))); + } +} diff --git a/com.ibm.wala.core.tests/src/com/ibm/wala/core/tests/ir/LocalNamesTest.java b/com.ibm.wala.core.tests/src/com/ibm/wala/core/tests/ir/LocalNamesTest.java index f3cec2325..5d35bb208 100644 --- a/com.ibm.wala.core.tests/src/com/ibm/wala/core/tests/ir/LocalNamesTest.java +++ b/com.ibm.wala.core.tests/src/com/ibm/wala/core/tests/ir/LocalNamesTest.java @@ -1,190 +1,190 @@ -/******************************************************************************* - * 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.core.tests.ir; - -import org.junit.AfterClass; -import org.junit.Assert; -import org.junit.BeforeClass; -import org.junit.Test; - -import com.ibm.wala.classLoader.ClassLoaderFactory; -import com.ibm.wala.classLoader.ClassLoaderFactoryImpl; -import com.ibm.wala.classLoader.IClass; -import com.ibm.wala.classLoader.IMethod; -import com.ibm.wala.core.tests.util.TestConstants; -import com.ibm.wala.core.tests.util.WalaTestCase; -import com.ibm.wala.ipa.callgraph.AnalysisCache; -import com.ibm.wala.ipa.callgraph.AnalysisOptions; -import com.ibm.wala.ipa.callgraph.AnalysisScope; -import com.ibm.wala.ipa.callgraph.impl.Everywhere; -import com.ibm.wala.ipa.cha.ClassHierarchy; -import com.ibm.wala.ipa.cha.ClassHierarchyException; -import com.ibm.wala.ssa.IR; -import com.ibm.wala.ssa.SSAInstruction; -import com.ibm.wala.ssa.SSAOptions; -import com.ibm.wala.ssa.SSAPiNodePolicy; -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.config.AnalysisScopeReader; -import com.ibm.wala.util.debug.Assertions; -import com.ibm.wala.util.io.FileProvider; -import com.ibm.wala.util.strings.Atom; -import com.ibm.wala.util.strings.ImmutableByteArray; -import com.ibm.wala.util.strings.UTF8Convert; - -/** - * Test IR's getLocalNames. - */ -public class LocalNamesTest extends WalaTestCase { - - private static final ClassLoader MY_CLASSLOADER = LocalNamesTest.class.getClassLoader(); - - private static AnalysisScope scope; - - private static ClassHierarchy cha; - - private static AnalysisOptions options; - - private static AnalysisCache cache; - - public static void main(String[] args) { - justThisTest(LocalNamesTest.class); - } - - /* - * @see junit.framework.TestCase#setUp() - */ - @BeforeClass - public static void beforeClass() throws Exception { - - scope = AnalysisScopeReader.readJavaScope(TestConstants.WALA_TESTDATA, - (new FileProvider()).getFile("J2SEClassHierarchyExclusions.txt"), MY_CLASSLOADER); - - options = new AnalysisOptions(scope, null); - cache = new AnalysisCache(); - ClassLoaderFactory factory = new ClassLoaderFactoryImpl(scope.getExclusions()); - - try { - cha = ClassHierarchy.make(scope, factory); - } catch (ClassHierarchyException e) { - throw new Exception(); - } - } - - /* - * (non-Javadoc) - * - * @see junit.framework.TestCase#tearDown() - */ - @AfterClass - public static void afterClass() throws Exception { - scope = null; - cha = null; - options = null; - cache = null; - } - - /** - * Build an IR, then check getLocalNames - */ - @Test - public void testAliasNames() { - try { - AnalysisScope scope = AnalysisScopeReader.readJavaScope(TestConstants.WALA_TESTDATA, (new FileProvider()) - .getFile("J2SEClassHierarchyExclusions.txt"), MY_CLASSLOADER); - ClassHierarchy cha = ClassHierarchy.make(scope); - TypeReference t = TypeReference.findOrCreateClass(scope.getApplicationLoader(), "cornerCases", "AliasNames"); - IClass klass = cha.lookupClass(t); - Assert.assertTrue(klass != null); - IMethod m = klass.getMethod(new Selector(Atom.findOrCreateAsciiAtom("foo"), Descriptor - .findOrCreateUTF8("([Ljava/lang/String;)V"))); - - AnalysisOptions options = new AnalysisOptions(); - options.getSSAOptions().setPiNodePolicy(SSAOptions.getAllBuiltInPiNodes()); - IR ir = cache.getSSACache().findOrCreateIR(m, Everywhere.EVERYWHERE, options.getSSAOptions()); - - for (int offsetIndex = 0; offsetIndex < ir.getInstructions().length; offsetIndex++) { - SSAInstruction instr = ir.getInstructions()[offsetIndex]; - if (instr != null) { - String[] localNames = ir.getLocalNames(offsetIndex, instr.getDef()); - if (localNames != null && localNames.length > 0 && localNames[0] == null) { - System.err.println(ir); - Assert.assertTrue(" getLocalNames() returned [null,...] for the def of instruction at offset " + offsetIndex - + "\n\tinstr", false); - } - } - } - } catch (Exception e) { - e.printStackTrace(); - Assertions.UNREACHABLE(); - } - } - - @Test - public void testLocalNamesWithoutPiNodes() { - SSAPiNodePolicy save = options.getSSAOptions().getPiNodePolicy(); - options.getSSAOptions().setPiNodePolicy(null); - MethodReference mref = scope.findMethod(AnalysisScope.APPLICATION, "LcornerCases/Locals", Atom.findOrCreateUnicodeAtom("foo"), - new ImmutableByteArray(UTF8Convert.toUTF8("([Ljava/lang/String;)V"))); - Assert.assertNotNull("method not found", mref); - IMethod imethod = cha.resolveMethod(mref); - Assert.assertNotNull("imethod not found", imethod); - IR ir = cache.getIRFactory().makeIR(imethod, Everywhere.EVERYWHERE, options.getSSAOptions()); - options.getSSAOptions().setPiNodePolicy(save); - - // v1 should be the parameter "a" at pc 0 - String[] names = ir.getLocalNames(0, 1); - Assert.assertTrue("failed local name resolution for v1@0", names != null); - Assert.assertTrue("incorrect number of local names for v1@0: " + names.length, names.length == 1); - Assert.assertTrue("incorrect local name resolution for v1@0: " + names[0], names[0].equals("a")); - - // v2 is a compiler-induced temporary - Assert.assertTrue("didn't expect name for v2 at pc 2", ir.getLocalNames(2, 2) == null); - - // at pc 5, v1 should represent the locals "a" and "b" - names = ir.getLocalNames(5, 1); - Assert.assertTrue("failed local name resolution for v1@5", names != null); - Assert.assertTrue("incorrect number of local names for v1@5: " + names.length, names.length == 2); - Assert.assertTrue("incorrect local name resolution #0 for v1@5: " + names[0], names[0].equals("a")); - Assert.assertTrue("incorrect local name resolution #1 for v1@5: " + names[1], names[1].equals("b")); - } - - @Test - public void testLocalNamesWithPiNodes() { - SSAPiNodePolicy save = options.getSSAOptions().getPiNodePolicy(); - options.getSSAOptions().setPiNodePolicy(SSAOptions.getAllBuiltInPiNodes()); - MethodReference mref = scope.findMethod(AnalysisScope.APPLICATION, "LcornerCases/Locals", Atom.findOrCreateUnicodeAtom("foo"), - new ImmutableByteArray(UTF8Convert.toUTF8("([Ljava/lang/String;)V"))); - Assert.assertNotNull("method not found", mref); - IMethod imethod = cha.resolveMethod(mref); - Assert.assertNotNull("imethod not found", imethod); - IR ir = cache.getIRFactory().makeIR(imethod, Everywhere.EVERYWHERE, options.getSSAOptions()); - options.getSSAOptions().setPiNodePolicy(save); - - // v1 should be the parameter "a" at pc 0 - String[] names = ir.getLocalNames(0, 1); - Assert.assertTrue("failed local name resolution for v1@0", names != null); - Assert.assertTrue("incorrect number of local names for v1@0: " + names.length, names.length == 1); - Assert.assertTrue("incorrect local name resolution for v1@0: " + names[0], names[0].equals("a")); - - // v2 is a compiler-induced temporary - Assert.assertTrue("didn't expect name for v2 at pc 2", ir.getLocalNames(2, 2) == null); - - // at pc 5, v1 should represent the locals "a" and "b" - names = ir.getLocalNames(5, 1); - Assert.assertTrue("failed local name resolution for v1@5", names != null); - Assert.assertTrue("incorrect number of local names for v1@5: " + names.length, names.length == 2); - Assert.assertTrue("incorrect local name resolution #0 for v1@5: " + names[0], names[0].equals("a")); - Assert.assertTrue("incorrect local name resolution #1 for v1@5: " + names[1], names[1].equals("b")); - } -} +/******************************************************************************* + * 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.core.tests.ir; + +import org.junit.AfterClass; +import org.junit.Assert; +import org.junit.BeforeClass; +import org.junit.Test; + +import com.ibm.wala.classLoader.ClassLoaderFactory; +import com.ibm.wala.classLoader.ClassLoaderFactoryImpl; +import com.ibm.wala.classLoader.IClass; +import com.ibm.wala.classLoader.IMethod; +import com.ibm.wala.core.tests.util.TestConstants; +import com.ibm.wala.core.tests.util.WalaTestCase; +import com.ibm.wala.ipa.callgraph.AnalysisCache; +import com.ibm.wala.ipa.callgraph.AnalysisOptions; +import com.ibm.wala.ipa.callgraph.AnalysisScope; +import com.ibm.wala.ipa.callgraph.impl.Everywhere; +import com.ibm.wala.ipa.cha.ClassHierarchy; +import com.ibm.wala.ipa.cha.ClassHierarchyException; +import com.ibm.wala.ssa.IR; +import com.ibm.wala.ssa.SSAInstruction; +import com.ibm.wala.ssa.SSAOptions; +import com.ibm.wala.ssa.SSAPiNodePolicy; +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.config.AnalysisScopeReader; +import com.ibm.wala.util.debug.Assertions; +import com.ibm.wala.util.io.FileProvider; +import com.ibm.wala.util.strings.Atom; +import com.ibm.wala.util.strings.ImmutableByteArray; +import com.ibm.wala.util.strings.UTF8Convert; + +/** + * Test IR's getLocalNames. + */ +public class LocalNamesTest extends WalaTestCase { + + private static final ClassLoader MY_CLASSLOADER = LocalNamesTest.class.getClassLoader(); + + private static AnalysisScope scope; + + private static ClassHierarchy cha; + + private static AnalysisOptions options; + + private static AnalysisCache cache; + + public static void main(String[] args) { + justThisTest(LocalNamesTest.class); + } + + /* + * @see junit.framework.TestCase#setUp() + */ + @BeforeClass + public static void beforeClass() throws Exception { + + scope = AnalysisScopeReader.readJavaScope(TestConstants.WALA_TESTDATA, + (new FileProvider()).getFile("J2SEClassHierarchyExclusions.txt"), MY_CLASSLOADER); + + options = new AnalysisOptions(scope, null); + cache = new AnalysisCache(); + ClassLoaderFactory factory = new ClassLoaderFactoryImpl(scope.getExclusions()); + + try { + cha = ClassHierarchy.make(scope, factory); + } catch (ClassHierarchyException e) { + throw new Exception(); + } + } + + /* + * (non-Javadoc) + * + * @see junit.framework.TestCase#tearDown() + */ + @AfterClass + public static void afterClass() throws Exception { + scope = null; + cha = null; + options = null; + cache = null; + } + + /** + * Build an IR, then check getLocalNames + */ + @Test + public void testAliasNames() { + try { + AnalysisScope scope = AnalysisScopeReader.readJavaScope(TestConstants.WALA_TESTDATA, (new FileProvider()) + .getFile("J2SEClassHierarchyExclusions.txt"), MY_CLASSLOADER); + ClassHierarchy cha = ClassHierarchy.make(scope); + TypeReference t = TypeReference.findOrCreateClass(scope.getApplicationLoader(), "cornerCases", "AliasNames"); + IClass klass = cha.lookupClass(t); + Assert.assertTrue(klass != null); + IMethod m = klass.getMethod(new Selector(Atom.findOrCreateAsciiAtom("foo"), Descriptor + .findOrCreateUTF8("([Ljava/lang/String;)V"))); + + AnalysisOptions options = new AnalysisOptions(); + options.getSSAOptions().setPiNodePolicy(SSAOptions.getAllBuiltInPiNodes()); + IR ir = cache.getSSACache().findOrCreateIR(m, Everywhere.EVERYWHERE, options.getSSAOptions()); + + for (int offsetIndex = 0; offsetIndex < ir.getInstructions().length; offsetIndex++) { + SSAInstruction instr = ir.getInstructions()[offsetIndex]; + if (instr != null) { + String[] localNames = ir.getLocalNames(offsetIndex, instr.getDef()); + if (localNames != null && localNames.length > 0 && localNames[0] == null) { + System.err.println(ir); + Assert.assertTrue(" getLocalNames() returned [null,...] for the def of instruction at offset " + offsetIndex + + "\n\tinstr", false); + } + } + } + } catch (Exception e) { + e.printStackTrace(); + Assertions.UNREACHABLE(); + } + } + + @Test + public void testLocalNamesWithoutPiNodes() { + SSAPiNodePolicy save = options.getSSAOptions().getPiNodePolicy(); + options.getSSAOptions().setPiNodePolicy(null); + MethodReference mref = scope.findMethod(AnalysisScope.APPLICATION, "LcornerCases/Locals", Atom.findOrCreateUnicodeAtom("foo"), + new ImmutableByteArray(UTF8Convert.toUTF8("([Ljava/lang/String;)V"))); + Assert.assertNotNull("method not found", mref); + IMethod imethod = cha.resolveMethod(mref); + Assert.assertNotNull("imethod not found", imethod); + IR ir = cache.getIRFactory().makeIR(imethod, Everywhere.EVERYWHERE, options.getSSAOptions()); + options.getSSAOptions().setPiNodePolicy(save); + + // v1 should be the parameter "a" at pc 0 + String[] names = ir.getLocalNames(0, 1); + Assert.assertTrue("failed local name resolution for v1@0", names != null); + Assert.assertTrue("incorrect number of local names for v1@0: " + names.length, names.length == 1); + Assert.assertTrue("incorrect local name resolution for v1@0: " + names[0], names[0].equals("a")); + + // v2 is a compiler-induced temporary + Assert.assertTrue("didn't expect name for v2 at pc 2", ir.getLocalNames(2, 2) == null); + + // at pc 5, v1 should represent the locals "a" and "b" + names = ir.getLocalNames(5, 1); + Assert.assertTrue("failed local name resolution for v1@5", names != null); + Assert.assertTrue("incorrect number of local names for v1@5: " + names.length, names.length == 2); + Assert.assertTrue("incorrect local name resolution #0 for v1@5: " + names[0], names[0].equals("a")); + Assert.assertTrue("incorrect local name resolution #1 for v1@5: " + names[1], names[1].equals("b")); + } + + @Test + public void testLocalNamesWithPiNodes() { + SSAPiNodePolicy save = options.getSSAOptions().getPiNodePolicy(); + options.getSSAOptions().setPiNodePolicy(SSAOptions.getAllBuiltInPiNodes()); + MethodReference mref = scope.findMethod(AnalysisScope.APPLICATION, "LcornerCases/Locals", Atom.findOrCreateUnicodeAtom("foo"), + new ImmutableByteArray(UTF8Convert.toUTF8("([Ljava/lang/String;)V"))); + Assert.assertNotNull("method not found", mref); + IMethod imethod = cha.resolveMethod(mref); + Assert.assertNotNull("imethod not found", imethod); + IR ir = cache.getIRFactory().makeIR(imethod, Everywhere.EVERYWHERE, options.getSSAOptions()); + options.getSSAOptions().setPiNodePolicy(save); + + // v1 should be the parameter "a" at pc 0 + String[] names = ir.getLocalNames(0, 1); + Assert.assertTrue("failed local name resolution for v1@0", names != null); + Assert.assertTrue("incorrect number of local names for v1@0: " + names.length, names.length == 1); + Assert.assertTrue("incorrect local name resolution for v1@0: " + names[0], names[0].equals("a")); + + // v2 is a compiler-induced temporary + Assert.assertTrue("didn't expect name for v2 at pc 2", ir.getLocalNames(2, 2) == null); + + // at pc 5, v1 should represent the locals "a" and "b" + names = ir.getLocalNames(5, 1); + Assert.assertTrue("failed local name resolution for v1@5", names != null); + Assert.assertTrue("incorrect number of local names for v1@5: " + names.length, names.length == 2); + Assert.assertTrue("incorrect local name resolution #0 for v1@5: " + names[0], names[0].equals("a")); + Assert.assertTrue("incorrect local name resolution #1 for v1@5: " + names[1], names[1].equals("b")); + } +} diff --git a/com.ibm.wala.core.tests/src/com/ibm/wala/core/tests/plugin/CoreTestsPlugin.java b/com.ibm.wala.core.tests/src/com/ibm/wala/core/tests/plugin/CoreTestsPlugin.java index 5b7357129..427245bcb 100644 --- a/com.ibm.wala.core.tests/src/com/ibm/wala/core/tests/plugin/CoreTestsPlugin.java +++ b/com.ibm.wala.core.tests/src/com/ibm/wala/core/tests/plugin/CoreTestsPlugin.java @@ -1,60 +1,60 @@ -/******************************************************************************* - * 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.core.tests.plugin; - -import org.eclipse.core.runtime.Plugin; -import org.osgi.framework.BundleContext; - - -/** - * The main plugin class to be used in the desktop. - */ -public class CoreTestsPlugin extends Plugin { - - // The shared instance. - private static CoreTestsPlugin plugin; - - /** - * The constructor. - */ - public CoreTestsPlugin() { - plugin = this; - } - - /** - * This method is called upon plug-in activation - * @throws IllegalArgumentException if context is null - */ - @Override - public void start(BundleContext context) throws Exception { - if (context == null) { - throw new IllegalArgumentException("context is null"); - } - super.start(context); - } - - /** - * This method is called when the plug-in is stopped - */ - @Override - public void stop(BundleContext context) throws Exception { - super.stop(context); - plugin = null; - } - - /** - * Returns the shared instance. - */ - public static CoreTestsPlugin getDefault() { - return plugin; - } - -} +/******************************************************************************* + * 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.core.tests.plugin; + +import org.eclipse.core.runtime.Plugin; +import org.osgi.framework.BundleContext; + + +/** + * The main plugin class to be used in the desktop. + */ +public class CoreTestsPlugin extends Plugin { + + // The shared instance. + private static CoreTestsPlugin plugin; + + /** + * The constructor. + */ + public CoreTestsPlugin() { + plugin = this; + } + + /** + * This method is called upon plug-in activation + * @throws IllegalArgumentException if context is null + */ + @Override + public void start(BundleContext context) throws Exception { + if (context == null) { + throw new IllegalArgumentException("context is null"); + } + super.start(context); + } + + /** + * This method is called when the plug-in is stopped + */ + @Override + public void stop(BundleContext context) throws Exception { + super.stop(context); + plugin = null; + } + + /** + * Returns the shared instance. + */ + public static CoreTestsPlugin getDefault() { + return plugin; + } + +} diff --git a/com.ibm.wala.core.tests/src/com/ibm/wala/core/tests/ptrs/MultiDimArrayTest.java b/com.ibm.wala.core.tests/src/com/ibm/wala/core/tests/ptrs/MultiDimArrayTest.java index 8fcf0cb9e..86cdfeee2 100644 --- a/com.ibm.wala.core.tests/src/com/ibm/wala/core/tests/ptrs/MultiDimArrayTest.java +++ b/com.ibm.wala.core.tests/src/com/ibm/wala/core/tests/ptrs/MultiDimArrayTest.java @@ -1,87 +1,87 @@ -/******************************************************************************* - * 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 com.ibm.wala.core.tests.ptrs; - -import java.io.IOException; -import java.util.Iterator; - -import org.junit.Assert; -import org.junit.Test; - -import com.ibm.wala.core.tests.callGraph.CallGraphTestUtil; -import com.ibm.wala.core.tests.util.TestConstants; -import com.ibm.wala.core.tests.util.WalaTestCase; -import com.ibm.wala.ipa.callgraph.AnalysisCache; -import com.ibm.wala.ipa.callgraph.AnalysisOptions; -import com.ibm.wala.ipa.callgraph.AnalysisScope; -import com.ibm.wala.ipa.callgraph.CGNode; -import com.ibm.wala.ipa.callgraph.CallGraph; -import com.ibm.wala.ipa.callgraph.CallGraphBuilder; -import com.ibm.wala.ipa.callgraph.Entrypoint; -import com.ibm.wala.ipa.callgraph.impl.Util; -import com.ibm.wala.ipa.callgraph.propagation.InstanceKey; -import com.ibm.wala.ipa.callgraph.propagation.PointerAnalysis; -import com.ibm.wala.ipa.callgraph.propagation.PointerKey; -import com.ibm.wala.ipa.cha.ClassHierarchy; -import com.ibm.wala.ipa.cha.ClassHierarchyException; -import com.ibm.wala.util.CancelException; -import com.ibm.wala.util.debug.Assertions; -import com.ibm.wala.util.intset.OrdinalSet; - -/** - * - * Test for pointer analysis of multidimensional arrays - * - * @author sfink - */ - -public class MultiDimArrayTest extends WalaTestCase { - - - public static void main(String[] args) { - justThisTest(MultiDimArrayTest.class); - } - - - - public MultiDimArrayTest() { - - } - - @Test public void testMultiDim() throws ClassHierarchyException, IllegalArgumentException, CancelException, IOException { - AnalysisScope scope = CallGraphTestUtil.makeJ2SEAnalysisScope(TestConstants.WALA_TESTDATA, CallGraphTestUtil.REGRESSION_EXCLUSIONS); - ClassHierarchy cha = ClassHierarchy.make(scope); - Iterable entrypoints = com.ibm.wala.ipa.callgraph.impl.Util - .makeMainEntrypoints(scope, cha, TestConstants.MULTI_DIM_MAIN); - AnalysisOptions options = CallGraphTestUtil.makeAnalysisOptions(scope, entrypoints); - - CallGraphBuilder builder = Util.makeVanillaZeroOneCFABuilder(options, new AnalysisCache(),cha, scope); - CallGraph cg = builder.makeCallGraph(options, null); - PointerAnalysis pa = builder.getPointerAnalysis(); - System.err.println(pa); - - CGNode node = findDoNothingNode(cg); - PointerKey pk = pa.getHeapModel().getPointerKeyForLocal(node, 1); - OrdinalSet ptsTo = pa.getPointsToSet(pk); - Assert.assertEquals(1, ptsTo.size()); - } - - private final static CGNode findDoNothingNode(CallGraph cg) { - for (Iterator it = cg.iterator(); it.hasNext(); ) { - CGNode n = it.next(); - if (n.getMethod().getName().toString().equals("doNothing")) { - return n; - } - } - Assertions.UNREACHABLE("Unexpected: failed to find doNothing node"); - return null; - } -} +/******************************************************************************* + * 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 com.ibm.wala.core.tests.ptrs; + +import java.io.IOException; +import java.util.Iterator; + +import org.junit.Assert; +import org.junit.Test; + +import com.ibm.wala.core.tests.callGraph.CallGraphTestUtil; +import com.ibm.wala.core.tests.util.TestConstants; +import com.ibm.wala.core.tests.util.WalaTestCase; +import com.ibm.wala.ipa.callgraph.AnalysisCache; +import com.ibm.wala.ipa.callgraph.AnalysisOptions; +import com.ibm.wala.ipa.callgraph.AnalysisScope; +import com.ibm.wala.ipa.callgraph.CGNode; +import com.ibm.wala.ipa.callgraph.CallGraph; +import com.ibm.wala.ipa.callgraph.CallGraphBuilder; +import com.ibm.wala.ipa.callgraph.Entrypoint; +import com.ibm.wala.ipa.callgraph.impl.Util; +import com.ibm.wala.ipa.callgraph.propagation.InstanceKey; +import com.ibm.wala.ipa.callgraph.propagation.PointerAnalysis; +import com.ibm.wala.ipa.callgraph.propagation.PointerKey; +import com.ibm.wala.ipa.cha.ClassHierarchy; +import com.ibm.wala.ipa.cha.ClassHierarchyException; +import com.ibm.wala.util.CancelException; +import com.ibm.wala.util.debug.Assertions; +import com.ibm.wala.util.intset.OrdinalSet; + +/** + * + * Test for pointer analysis of multidimensional arrays + * + * @author sfink + */ + +public class MultiDimArrayTest extends WalaTestCase { + + + public static void main(String[] args) { + justThisTest(MultiDimArrayTest.class); + } + + + + public MultiDimArrayTest() { + + } + + @Test public void testMultiDim() throws ClassHierarchyException, IllegalArgumentException, CancelException, IOException { + AnalysisScope scope = CallGraphTestUtil.makeJ2SEAnalysisScope(TestConstants.WALA_TESTDATA, CallGraphTestUtil.REGRESSION_EXCLUSIONS); + ClassHierarchy cha = ClassHierarchy.make(scope); + Iterable entrypoints = com.ibm.wala.ipa.callgraph.impl.Util + .makeMainEntrypoints(scope, cha, TestConstants.MULTI_DIM_MAIN); + AnalysisOptions options = CallGraphTestUtil.makeAnalysisOptions(scope, entrypoints); + + CallGraphBuilder builder = Util.makeVanillaZeroOneCFABuilder(options, new AnalysisCache(),cha, scope); + CallGraph cg = builder.makeCallGraph(options, null); + PointerAnalysis pa = builder.getPointerAnalysis(); + System.err.println(pa); + + CGNode node = findDoNothingNode(cg); + PointerKey pk = pa.getHeapModel().getPointerKeyForLocal(node, 1); + OrdinalSet ptsTo = pa.getPointsToSet(pk); + Assert.assertEquals(1, ptsTo.size()); + } + + private final static CGNode findDoNothingNode(CallGraph cg) { + for (Iterator it = cg.iterator(); it.hasNext(); ) { + CGNode n = it.next(); + if (n.getMethod().getName().toString().equals("doNothing")) { + return n; + } + } + Assertions.UNREACHABLE("Unexpected: failed to find doNothing node"); + return null; + } +} diff --git a/com.ibm.wala.core.tests/src/com/ibm/wala/core/tests/ptrs/TypeBasedArrayAliasTest.java b/com.ibm.wala.core.tests/src/com/ibm/wala/core/tests/ptrs/TypeBasedArrayAliasTest.java index 4dab1062e..29c3ff88b 100644 --- a/com.ibm.wala.core.tests/src/com/ibm/wala/core/tests/ptrs/TypeBasedArrayAliasTest.java +++ b/com.ibm.wala.core.tests/src/com/ibm/wala/core/tests/ptrs/TypeBasedArrayAliasTest.java @@ -1,96 +1,96 @@ -/******************************************************************************* - * Copyright (c) 2008 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.core.tests.ptrs; - -import java.io.IOException; -import java.util.Iterator; - -import org.junit.Assert; -import org.junit.Test; - -import com.ibm.wala.core.tests.callGraph.CallGraphTestUtil; -import com.ibm.wala.core.tests.util.TestConstants; -import com.ibm.wala.core.tests.util.WalaTestCase; -import com.ibm.wala.ipa.callgraph.AnalysisCache; -import com.ibm.wala.ipa.callgraph.AnalysisOptions; -import com.ibm.wala.ipa.callgraph.AnalysisScope; -import com.ibm.wala.ipa.callgraph.CGNode; -import com.ibm.wala.ipa.callgraph.CallGraph; -import com.ibm.wala.ipa.callgraph.CallGraphBuilder; -import com.ibm.wala.ipa.callgraph.Entrypoint; -import com.ibm.wala.ipa.callgraph.impl.Util; -import com.ibm.wala.ipa.callgraph.propagation.InstanceKey; -import com.ibm.wala.ipa.callgraph.propagation.PointerAnalysis; -import com.ibm.wala.ipa.callgraph.propagation.PointerKey; -import com.ibm.wala.ipa.cha.ClassHierarchy; -import com.ibm.wala.ipa.cha.ClassHierarchyException; -import com.ibm.wala.util.CancelException; -import com.ibm.wala.util.debug.Assertions; -import com.ibm.wala.util.intset.OrdinalSet; - -public class TypeBasedArrayAliasTest extends WalaTestCase { - - @Test public void testTypeBasedArrayAlias() throws ClassHierarchyException, IllegalArgumentException, CancelException, IOException { - AnalysisScope scope = CallGraphTestUtil.makeJ2SEAnalysisScope(TestConstants.WALA_TESTDATA, CallGraphTestUtil.REGRESSION_EXCLUSIONS); - ClassHierarchy cha = ClassHierarchy.make(scope); - Iterable entrypoints = com.ibm.wala.ipa.callgraph.impl.Util - .makeMainEntrypoints(scope, cha, TestConstants.ARRAY_ALIAS_MAIN); - AnalysisOptions options = CallGraphTestUtil.makeAnalysisOptions(scope, entrypoints); - - // RTA yields a TypeBasedPointerAnalysis - CallGraphBuilder builder = Util.makeRTABuilder(options, new AnalysisCache(),cha, scope); - CallGraph cg = builder.makeCallGraph(options, null); - PointerAnalysis pa = builder.getPointerAnalysis(); - - CGNode node = findNode(cg, "testMayAlias1"); - PointerKey pk1 = pa.getHeapModel().getPointerKeyForLocal(node, 1); - PointerKey pk2 = pa.getHeapModel().getPointerKeyForLocal(node, 2); - Assert.assertTrue(mayAliased(pk1, pk2, pa)); - - node = findNode(cg, "testMayAlias2"); - pk1 = pa.getHeapModel().getPointerKeyForLocal(node, 1); - pk2 = pa.getHeapModel().getPointerKeyForLocal(node, 2); - Assert.assertTrue(mayAliased(pk1, pk2, pa)); - - node = findNode(cg, "testMayAlias3"); - pk1 = pa.getHeapModel().getPointerKeyForLocal(node, 1); - pk2 = pa.getHeapModel().getPointerKeyForLocal(node, 2); - Assert.assertTrue(mayAliased(pk1, pk2, pa)); - } - - private final static CGNode findNode(CallGraph cg, String methodName) { - for (Iterator it = cg.iterator(); it.hasNext(); ) { - CGNode n = it.next(); - if (n.getMethod().getName().toString().equals(methodName)) { - return n; - } - } - Assertions.UNREACHABLE("Unexpected: failed to find " + methodName + " node"); - return null; - } - - private static boolean mayAliased(PointerKey pk1, PointerKey pk2, PointerAnalysis pa) { - OrdinalSet ptsTo1 = pa.getPointsToSet(pk1); - OrdinalSet ptsTo2 = pa.getPointsToSet(pk2); - boolean foundIntersection = false; - outer: for (InstanceKey i : ptsTo1) { - for (InstanceKey j : ptsTo2) { - if (i.equals(j)) { - foundIntersection = true; - break outer; - } - } - } - return foundIntersection; - } - - -} +/******************************************************************************* + * Copyright (c) 2008 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.core.tests.ptrs; + +import java.io.IOException; +import java.util.Iterator; + +import org.junit.Assert; +import org.junit.Test; + +import com.ibm.wala.core.tests.callGraph.CallGraphTestUtil; +import com.ibm.wala.core.tests.util.TestConstants; +import com.ibm.wala.core.tests.util.WalaTestCase; +import com.ibm.wala.ipa.callgraph.AnalysisCache; +import com.ibm.wala.ipa.callgraph.AnalysisOptions; +import com.ibm.wala.ipa.callgraph.AnalysisScope; +import com.ibm.wala.ipa.callgraph.CGNode; +import com.ibm.wala.ipa.callgraph.CallGraph; +import com.ibm.wala.ipa.callgraph.CallGraphBuilder; +import com.ibm.wala.ipa.callgraph.Entrypoint; +import com.ibm.wala.ipa.callgraph.impl.Util; +import com.ibm.wala.ipa.callgraph.propagation.InstanceKey; +import com.ibm.wala.ipa.callgraph.propagation.PointerAnalysis; +import com.ibm.wala.ipa.callgraph.propagation.PointerKey; +import com.ibm.wala.ipa.cha.ClassHierarchy; +import com.ibm.wala.ipa.cha.ClassHierarchyException; +import com.ibm.wala.util.CancelException; +import com.ibm.wala.util.debug.Assertions; +import com.ibm.wala.util.intset.OrdinalSet; + +public class TypeBasedArrayAliasTest extends WalaTestCase { + + @Test public void testTypeBasedArrayAlias() throws ClassHierarchyException, IllegalArgumentException, CancelException, IOException { + AnalysisScope scope = CallGraphTestUtil.makeJ2SEAnalysisScope(TestConstants.WALA_TESTDATA, CallGraphTestUtil.REGRESSION_EXCLUSIONS); + ClassHierarchy cha = ClassHierarchy.make(scope); + Iterable entrypoints = com.ibm.wala.ipa.callgraph.impl.Util + .makeMainEntrypoints(scope, cha, TestConstants.ARRAY_ALIAS_MAIN); + AnalysisOptions options = CallGraphTestUtil.makeAnalysisOptions(scope, entrypoints); + + // RTA yields a TypeBasedPointerAnalysis + CallGraphBuilder builder = Util.makeRTABuilder(options, new AnalysisCache(),cha, scope); + CallGraph cg = builder.makeCallGraph(options, null); + PointerAnalysis pa = builder.getPointerAnalysis(); + + CGNode node = findNode(cg, "testMayAlias1"); + PointerKey pk1 = pa.getHeapModel().getPointerKeyForLocal(node, 1); + PointerKey pk2 = pa.getHeapModel().getPointerKeyForLocal(node, 2); + Assert.assertTrue(mayAliased(pk1, pk2, pa)); + + node = findNode(cg, "testMayAlias2"); + pk1 = pa.getHeapModel().getPointerKeyForLocal(node, 1); + pk2 = pa.getHeapModel().getPointerKeyForLocal(node, 2); + Assert.assertTrue(mayAliased(pk1, pk2, pa)); + + node = findNode(cg, "testMayAlias3"); + pk1 = pa.getHeapModel().getPointerKeyForLocal(node, 1); + pk2 = pa.getHeapModel().getPointerKeyForLocal(node, 2); + Assert.assertTrue(mayAliased(pk1, pk2, pa)); + } + + private final static CGNode findNode(CallGraph cg, String methodName) { + for (Iterator it = cg.iterator(); it.hasNext(); ) { + CGNode n = it.next(); + if (n.getMethod().getName().toString().equals(methodName)) { + return n; + } + } + Assertions.UNREACHABLE("Unexpected: failed to find " + methodName + " node"); + return null; + } + + private static boolean mayAliased(PointerKey pk1, PointerKey pk2, PointerAnalysis pa) { + OrdinalSet ptsTo1 = pa.getPointsToSet(pk1); + OrdinalSet ptsTo2 = pa.getPointsToSet(pk2); + boolean foundIntersection = false; + outer: for (InstanceKey i : ptsTo1) { + for (InstanceKey j : ptsTo2) { + if (i.equals(j)) { + foundIntersection = true; + break outer; + } + } + } + return foundIntersection; + } + + +} diff --git a/com.ibm.wala.core.tests/src/com/ibm/wala/core/tests/slicer/SlicerTest.java b/com.ibm.wala.core.tests/src/com/ibm/wala/core/tests/slicer/SlicerTest.java index e8804377e..2e243fbeb 100644 --- a/com.ibm.wala.core.tests/src/com/ibm/wala/core/tests/slicer/SlicerTest.java +++ b/com.ibm.wala.core.tests/src/com/ibm/wala/core/tests/slicer/SlicerTest.java @@ -1,929 +1,929 @@ -/******************************************************************************* - * 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 com.ibm.wala.core.tests.slicer; - -import java.io.File; -import java.io.FileNotFoundException; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.PrintWriter; -import java.util.Collection; -import java.util.Collections; -import java.util.Iterator; - -import org.junit.AfterClass; -import org.junit.Assert; -import org.junit.Test; - -import com.ibm.wala.core.tests.callGraph.CallGraphTestUtil; -import com.ibm.wala.core.tests.util.TestConstants; -import com.ibm.wala.examples.drivers.PDFSlice; -import com.ibm.wala.ipa.callgraph.AnalysisCache; -import com.ibm.wala.ipa.callgraph.AnalysisOptions; -import com.ibm.wala.ipa.callgraph.AnalysisScope; -import com.ibm.wala.ipa.callgraph.CGNode; -import com.ibm.wala.ipa.callgraph.CallGraph; -import com.ibm.wala.ipa.callgraph.CallGraphBuilder; -import com.ibm.wala.ipa.callgraph.Entrypoint; -import com.ibm.wala.ipa.callgraph.impl.PartialCallGraph; -import com.ibm.wala.ipa.callgraph.impl.Util; -import com.ibm.wala.ipa.cha.ClassHierarchy; -import com.ibm.wala.ipa.cha.ClassHierarchyException; -import com.ibm.wala.ipa.cha.IClassHierarchy; -import com.ibm.wala.ipa.slicer.MethodEntryStatement; -import com.ibm.wala.ipa.slicer.NormalStatement; -import com.ibm.wala.ipa.slicer.SDG; -import com.ibm.wala.ipa.slicer.Slicer; -import com.ibm.wala.ipa.slicer.Slicer.ControlDependenceOptions; -import com.ibm.wala.ipa.slicer.Slicer.DataDependenceOptions; -import com.ibm.wala.ipa.slicer.Statement; -import com.ibm.wala.ipa.slicer.thin.ThinSlicer; -import com.ibm.wala.ssa.IR; -import com.ibm.wala.ssa.SSAAbstractInvokeInstruction; -import com.ibm.wala.ssa.SSAAbstractThrowInstruction; -import com.ibm.wala.ssa.SSAArrayLoadInstruction; -import com.ibm.wala.ssa.SSAConditionalBranchInstruction; -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.SSAPutInstruction; -import com.ibm.wala.types.ClassLoaderReference; -import com.ibm.wala.types.Descriptor; -import com.ibm.wala.util.CancelException; -import com.ibm.wala.util.debug.Assertions; -import com.ibm.wala.util.graph.GraphIntegrity; -import com.ibm.wala.util.graph.GraphIntegrity.UnsoundGraphException; -import com.ibm.wala.util.intset.IntSet; -import com.ibm.wala.util.strings.Atom; - -public class SlicerTest { - - private static AnalysisScope cachedScope; - - private static AnalysisScope findOrCreateAnalysisScope() throws IOException { - if (cachedScope == null) { - cachedScope = CallGraphTestUtil.makeJ2SEAnalysisScope(TestConstants.WALA_TESTDATA, "Java60RegressionExclusions.txt"); - } - return cachedScope; - } - - private static IClassHierarchy cachedCHA; - - private static IClassHierarchy findOrCreateCHA(AnalysisScope scope) throws ClassHierarchyException { - if (cachedCHA == null) { - cachedCHA = ClassHierarchy.make(scope); - } - return cachedCHA; - } - - @AfterClass - public static void afterClass() { - cachedCHA = null; - cachedScope = null; - } - - @Test - public void testSlice1() throws ClassHierarchyException, IllegalArgumentException, CancelException, IOException { - AnalysisScope scope = findOrCreateAnalysisScope(); - IClassHierarchy cha = findOrCreateCHA(scope); - Iterable entrypoints = com.ibm.wala.ipa.callgraph.impl.Util.makeMainEntrypoints(scope, cha, - TestConstants.SLICE1_MAIN); - AnalysisOptions options = CallGraphTestUtil.makeAnalysisOptions(scope, entrypoints); - - CallGraphBuilder builder = Util.makeZeroOneCFABuilder(options, new AnalysisCache(), cha, scope); - CallGraph cg = builder.makeCallGraph(options, null); - - CGNode main = findMainMethod(cg); - - Statement s = findCallTo(main, "println"); - System.err.println("Statement: " + s); - // compute a data slice - Collection computeBackwardSlice = Slicer.computeBackwardSlice(s, cg, builder.getPointerAnalysis(), - DataDependenceOptions.FULL, ControlDependenceOptions.NONE); - Collection slice = computeBackwardSlice; - dumpSlice(slice); - - int i = 0; - for (Statement st : slice) { - if (st.getNode().getMethod().getDeclaringClass().getClassLoader().getReference().equals(ClassLoaderReference.Application)) { - i++; - } - } - Assert.assertEquals(16, i); - } - - @Test - public void testSlice2() throws ClassHierarchyException, IllegalArgumentException, CancelException, IOException { - AnalysisScope scope = findOrCreateAnalysisScope(); - IClassHierarchy cha = findOrCreateCHA(scope); - Iterable entrypoints = com.ibm.wala.ipa.callgraph.impl.Util.makeMainEntrypoints(scope, cha, - TestConstants.SLICE2_MAIN); - AnalysisOptions options = CallGraphTestUtil.makeAnalysisOptions(scope, entrypoints); - - CallGraphBuilder builder = Util.makeZeroOneCFABuilder(options, new AnalysisCache(), cha, scope); - CallGraph cg = builder.makeCallGraph(options, null); - - CGNode main = findMethod(cg, "baz"); - - Statement s = findCallTo(main, "println"); - System.err.println("Statement: " + s); - // compute a data slice - Collection computeBackwardSlice = Slicer.computeBackwardSlice(s, cg, builder.getPointerAnalysis(), - DataDependenceOptions.FULL, ControlDependenceOptions.NONE); - Collection slice = computeBackwardSlice; - dumpSlice(slice); - - Assert.assertEquals(9, countNormals(slice)); - } - - @Test - public void testSlice3() throws ClassHierarchyException, IllegalArgumentException, CancelException, IOException { - AnalysisScope scope = findOrCreateAnalysisScope(); - IClassHierarchy cha = findOrCreateCHA(scope); - Iterable entrypoints = com.ibm.wala.ipa.callgraph.impl.Util.makeMainEntrypoints(scope, cha, - TestConstants.SLICE3_MAIN); - AnalysisOptions options = CallGraphTestUtil.makeAnalysisOptions(scope, entrypoints); - - CallGraphBuilder builder = Util.makeZeroOneCFABuilder(options, new AnalysisCache(), cha, scope); - CallGraph cg = builder.makeCallGraph(options, null); - - CGNode main = findMethod(cg, "main"); - - Statement s = findCallTo(main, "doNothing"); - System.err.println("Statement: " + s); - // compute a data slice - Collection slice = Slicer.computeBackwardSlice(s, cg, builder.getPointerAnalysis(), DataDependenceOptions.FULL, - ControlDependenceOptions.NONE); - dumpSlice(slice); - Assert.assertEquals(1, countAllocations(slice)); - } - - @Test - public void testSlice4() throws ClassHierarchyException, IllegalArgumentException, CancelException, IOException { - AnalysisScope scope = findOrCreateAnalysisScope(); - - IClassHierarchy cha = findOrCreateCHA(scope); - Iterable entrypoints = com.ibm.wala.ipa.callgraph.impl.Util.makeMainEntrypoints(scope, cha, - TestConstants.SLICE4_MAIN); - AnalysisOptions options = CallGraphTestUtil.makeAnalysisOptions(scope, entrypoints); - - CallGraphBuilder builder = Util.makeZeroOneCFABuilder(options, new AnalysisCache(), cha, scope); - CallGraph cg = builder.makeCallGraph(options, null); - - CGNode main = findMainMethod(cg); - Statement s = findCallTo(main, "foo"); - s = PDFSlice.getReturnStatementForCall(s); - System.err.println("Statement: " + s); - // compute a data slice - Collection slice = Slicer.computeForwardSlice(s, cg, builder.getPointerAnalysis(), DataDependenceOptions.FULL, - ControlDependenceOptions.NONE); - dumpSlice(slice); - Assert.assertEquals(4, slice.size()); - } - - @Test - public void testSlice5() throws ClassHierarchyException, IllegalArgumentException, CancelException, IOException { - AnalysisScope scope = findOrCreateAnalysisScope(); - - IClassHierarchy cha = findOrCreateCHA(scope); - Iterable entrypoints = com.ibm.wala.ipa.callgraph.impl.Util.makeMainEntrypoints(scope, cha, - TestConstants.SLICE5_MAIN); - AnalysisOptions options = CallGraphTestUtil.makeAnalysisOptions(scope, entrypoints); - - CallGraphBuilder builder = Util.makeZeroOneCFABuilder(options, new AnalysisCache(), cha, scope); - CallGraph cg = builder.makeCallGraph(options, null); - - CGNode n = findMethod(cg, "baz"); - Statement s = findCallTo(n, "foo"); - s = PDFSlice.getReturnStatementForCall(s); - System.err.println("Statement: " + s); - // compute a data slice - Collection slice = Slicer.computeForwardSlice(s, cg, builder.getPointerAnalysis(), DataDependenceOptions.FULL, - ControlDependenceOptions.NONE); - dumpSlice(slice); - Assert.assertEquals(7, slice.size()); - } - - /** - * test unreproduced bug reported on mailing list by Sameer Madan, 7/3/2007 - * - * @throws CancelException - * @throws IllegalArgumentException - * @throws IOException - */ - @Test - public void testSlice7() throws ClassHierarchyException, IllegalArgumentException, CancelException, IOException { - AnalysisScope scope = findOrCreateAnalysisScope(); - - IClassHierarchy cha = findOrCreateCHA(scope); - Iterable entrypoints = com.ibm.wala.ipa.callgraph.impl.Util.makeMainEntrypoints(scope, cha, - TestConstants.SLICE7_MAIN); - AnalysisOptions options = CallGraphTestUtil.makeAnalysisOptions(scope, entrypoints); - - CallGraphBuilder builder = Util.makeZeroOneContainerCFABuilder(options, new AnalysisCache(), cha, scope); - CallGraph cg = builder.makeCallGraph(options, null); - - CGNode main = findMainMethod(cg); - Statement s = findFirstAllocation(main); - System.err.println("Statement: " + s); - // compute a data slice - Collection slice = Slicer.computeForwardSlice(s, cg, builder.getPointerAnalysis(), DataDependenceOptions.FULL, - ControlDependenceOptions.NONE); - dumpSlice(slice); - } - - /** - * test bug reported on mailing list by Ravi Chandhran, 4/16/2010 - * - * @throws CancelException - * @throws IllegalArgumentException - * @throws IOException - */ - @Test - public void testSlice8() throws ClassHierarchyException, IllegalArgumentException, CancelException, IOException { - AnalysisScope scope = findOrCreateAnalysisScope(); - - IClassHierarchy cha = findOrCreateCHA(scope); - Iterable entrypoints = com.ibm.wala.ipa.callgraph.impl.Util.makeMainEntrypoints(scope, cha, - TestConstants.SLICE8_MAIN); - AnalysisOptions options = CallGraphTestUtil.makeAnalysisOptions(scope, entrypoints); - - CallGraphBuilder builder = Util.makeVanillaZeroOneContainerCFABuilder(options, new AnalysisCache(), cha, scope); - CallGraph cg = builder.makeCallGraph(options, null); - - CGNode process = findMethod(cg, Descriptor.findOrCreateUTF8("()V"), Atom.findOrCreateUnicodeAtom("process")); - Statement s = findCallToDoNothing(process); - System.err.println("Statement: " + s); - // compute a backward slice, with data dependence and no exceptional control dependence - Collection slice = Slicer.computeBackwardSlice(s, cg, builder.getPointerAnalysis(), DataDependenceOptions.FULL, - ControlDependenceOptions.NO_EXCEPTIONAL_EDGES); - dumpSlice(slice); - Assert.assertEquals(4, countInvokes(slice)); - // should only get 4 statements total when ignoring control dependences completely - slice = Slicer.computeBackwardSlice(s, cg, builder.getPointerAnalysis(), DataDependenceOptions.FULL, - ControlDependenceOptions.NONE); - Assert.assertEquals(4, slice.size()); - } - - @Test - public void testTestCD1() throws ClassHierarchyException, IllegalArgumentException, CancelException, IOException { - AnalysisScope scope = findOrCreateAnalysisScope(); - - IClassHierarchy cha = findOrCreateCHA(scope); - Iterable entrypoints = com.ibm.wala.ipa.callgraph.impl.Util.makeMainEntrypoints(scope, cha, - TestConstants.SLICE_TESTCD1); - AnalysisOptions options = CallGraphTestUtil.makeAnalysisOptions(scope, entrypoints); - - CallGraphBuilder builder = Util.makeZeroOneCFABuilder(options, new AnalysisCache(), cha, scope); - CallGraph cg = builder.makeCallGraph(options, null); - - CGNode main = findMainMethod(cg); - - Statement s = findCallToDoNothing(main); - System.err.println("Statement: " + s); - // compute a data slice - Collection slice = Slicer.computeBackwardSlice(s, cg, builder.getPointerAnalysis(), DataDependenceOptions.NONE, - ControlDependenceOptions.FULL); - dumpSlice(slice); - Assert.assertEquals(2, countConditionals(slice)); - } - - @Test - public void testTestCD2() throws ClassHierarchyException, IllegalArgumentException, CancelException, IOException { - AnalysisScope scope = findOrCreateAnalysisScope(); - - IClassHierarchy cha = findOrCreateCHA(scope); - Iterable entrypoints = com.ibm.wala.ipa.callgraph.impl.Util.makeMainEntrypoints(scope, cha, - TestConstants.SLICE_TESTCD2); - AnalysisOptions options = CallGraphTestUtil.makeAnalysisOptions(scope, entrypoints); - - CallGraphBuilder builder = Util.makeZeroOneCFABuilder(options, new AnalysisCache(), cha, scope); - CallGraph cg = builder.makeCallGraph(options, null); - - CGNode main = findMainMethod(cg); - - Statement s = findCallToDoNothing(main); - System.err.println("Statement: " + s); - // compute a data slice - Collection slice = Slicer.computeBackwardSlice(s, cg, builder.getPointerAnalysis(), DataDependenceOptions.NONE, - ControlDependenceOptions.FULL); - dumpSlice(slice); - Assert.assertEquals(1, countConditionals(slice)); - } - - @Test - public void testTestCD3() throws ClassHierarchyException, IllegalArgumentException, CancelException, IOException { - AnalysisScope scope = findOrCreateAnalysisScope(); - - IClassHierarchy cha = findOrCreateCHA(scope); - Iterable entrypoints = com.ibm.wala.ipa.callgraph.impl.Util.makeMainEntrypoints(scope, cha, - TestConstants.SLICE_TESTCD3); - AnalysisOptions options = CallGraphTestUtil.makeAnalysisOptions(scope, entrypoints); - - CallGraphBuilder builder = Util.makeZeroOneCFABuilder(options, new AnalysisCache(), cha, scope); - CallGraph cg = builder.makeCallGraph(options, null); - - CGNode main = findMainMethod(cg); - - Statement s = findCallToDoNothing(main); - System.err.println("Statement: " + s); - // compute a data slice - Collection slice = Slicer.computeBackwardSlice(s, cg, builder.getPointerAnalysis(), DataDependenceOptions.NONE, - ControlDependenceOptions.FULL); - dumpSlice(slice); - Assert.assertEquals(0, countConditionals(slice)); - } - - @Test - public void testTestCD4() throws ClassHierarchyException, IllegalArgumentException, CancelException, IOException { - AnalysisScope scope = findOrCreateAnalysisScope(); - - IClassHierarchy cha = findOrCreateCHA(scope); - Iterable entrypoints = com.ibm.wala.ipa.callgraph.impl.Util.makeMainEntrypoints(scope, cha, - TestConstants.SLICE_TESTCD4); - AnalysisOptions options = CallGraphTestUtil.makeAnalysisOptions(scope, entrypoints); - - CallGraphBuilder builder = Util.makeZeroOneCFABuilder(options, new AnalysisCache(), cha, scope); - CallGraph cg = builder.makeCallGraph(options, null); - - CGNode main = findMainMethod(cg); - - Statement s = findCallToDoNothing(main); - System.err.println("Statement: " + s); - - // compute a no-data slice - Collection slice = Slicer.computeBackwardSlice(s, cg, builder.getPointerAnalysis(), DataDependenceOptions.NONE, - ControlDependenceOptions.FULL); - dumpSlice(slice); - Assert.assertEquals(0, countConditionals(slice)); - - // compute a full slice - slice = Slicer.computeBackwardSlice(s, cg, builder.getPointerAnalysis(), DataDependenceOptions.FULL, - ControlDependenceOptions.FULL); - dumpSlice(slice); - Assert.assertEquals(1, countConditionals(slice)); - } - - @Test - public void testTestCD5() throws ClassHierarchyException, IllegalArgumentException, CancelException, IOException { - AnalysisScope scope = findOrCreateAnalysisScope(); - - IClassHierarchy cha = findOrCreateCHA(scope); - Iterable entrypoints = com.ibm.wala.ipa.callgraph.impl.Util.makeMainEntrypoints(scope, cha, - TestConstants.SLICE_TESTCD5); - AnalysisOptions options = CallGraphTestUtil.makeAnalysisOptions(scope, entrypoints); - - CallGraphBuilder builder = Util.makeZeroOneCFABuilder(options, new AnalysisCache(), cha, scope); - CallGraph cg = builder.makeCallGraph(options, null); - - CGNode main = findMainMethod(cg); - - Statement s = new MethodEntryStatement(main); - System.err.println("Statement: " + s); - - // compute a no-data slice - Collection slice = Slicer.computeForwardSlice(s, cg, builder.getPointerAnalysis(), DataDependenceOptions.NONE, - ControlDependenceOptions.NO_EXCEPTIONAL_EDGES); - dumpSlice(slice); - Assert.assertTrue(slice.size() > 1); - } - - @Test - public void testTestCD6() throws ClassHierarchyException, IllegalArgumentException, CancelException, IOException { - AnalysisScope scope = findOrCreateAnalysisScope(); - - IClassHierarchy cha = findOrCreateCHA(scope); - Iterable entrypoints = com.ibm.wala.ipa.callgraph.impl.Util.makeMainEntrypoints(scope, cha, - TestConstants.SLICE_TESTCD6); - AnalysisOptions options = CallGraphTestUtil.makeAnalysisOptions(scope, entrypoints); - - CallGraphBuilder builder = Util.makeZeroOneCFABuilder(options, new AnalysisCache(), cha, scope); - CallGraph cg = builder.makeCallGraph(options, null); - - CGNode main = findMainMethod(cg); - - Statement s = new MethodEntryStatement(main); - System.err.println("Statement: " + s); - - // compute a no-data slice - Collection slice = Slicer.computeForwardSlice(s, cg, builder.getPointerAnalysis(), DataDependenceOptions.NONE, - ControlDependenceOptions.NO_EXCEPTIONAL_EDGES); - dumpSlice(slice); - Assert.assertEquals(2, countInvokes(slice)); - } - - @Test - public void testTestId() throws ClassHierarchyException, IllegalArgumentException, CancelException, IOException { - AnalysisScope scope = findOrCreateAnalysisScope(); - - IClassHierarchy cha = findOrCreateCHA(scope); - Iterable entrypoints = com.ibm.wala.ipa.callgraph.impl.Util.makeMainEntrypoints(scope, cha, - TestConstants.SLICE_TESTID); - AnalysisOptions options = CallGraphTestUtil.makeAnalysisOptions(scope, entrypoints); - - CallGraphBuilder builder = Util.makeZeroOneCFABuilder(options, new AnalysisCache(), cha, scope); - CallGraph cg = builder.makeCallGraph(options, null); - - CGNode main = findMainMethod(cg); - - Statement s = findCallToDoNothing(main); - System.err.println("Statement: " + s); - // compute a data slice - Collection slice = Slicer.computeBackwardSlice(s, cg, builder.getPointerAnalysis(), DataDependenceOptions.FULL, - ControlDependenceOptions.NONE); - dumpSlice(slice); - Assert.assertEquals(1, countAllocations(slice)); - } - - @Test - public void testTestArrays() throws ClassHierarchyException, IllegalArgumentException, CancelException, IOException { - AnalysisScope scope = findOrCreateAnalysisScope(); - - IClassHierarchy cha = findOrCreateCHA(scope); - Iterable entrypoints = com.ibm.wala.ipa.callgraph.impl.Util.makeMainEntrypoints(scope, cha, - TestConstants.SLICE_TESTARRAYS); - AnalysisOptions options = CallGraphTestUtil.makeAnalysisOptions(scope, entrypoints); - - CallGraphBuilder builder = Util.makeZeroOneCFABuilder(options, new AnalysisCache(), cha, scope); - CallGraph cg = builder.makeCallGraph(options, null); - - CGNode main = findMainMethod(cg); - - Statement s = findCallToDoNothing(main); - System.err.println("Statement: " + s); - // compute a data slice - Collection slice = Slicer.computeBackwardSlice(s, cg, builder.getPointerAnalysis(), DataDependenceOptions.FULL, - ControlDependenceOptions.NONE); - dumpSlice(slice); - Assert.assertEquals(2, countAllocations(slice)); - Assert.assertEquals(1, countAloads(slice)); - } - - @Test - public void testTestFields() throws ClassHierarchyException, IllegalArgumentException, CancelException, IOException { - AnalysisScope scope = findOrCreateAnalysisScope(); - - IClassHierarchy cha = findOrCreateCHA(scope); - Iterable entrypoints = com.ibm.wala.ipa.callgraph.impl.Util.makeMainEntrypoints(scope, cha, - TestConstants.SLICE_TESTFIELDS); - AnalysisOptions options = CallGraphTestUtil.makeAnalysisOptions(scope, entrypoints); - - CallGraphBuilder builder = Util.makeZeroOneCFABuilder(options, new AnalysisCache(), cha, scope); - CallGraph cg = builder.makeCallGraph(options, null); - - CGNode main = findMainMethod(cg); - - Statement s = findCallToDoNothing(main); - System.err.println("Statement: " + s); - // compute a data slice - Collection slice = Slicer.computeBackwardSlice(s, cg, builder.getPointerAnalysis(), DataDependenceOptions.FULL, - ControlDependenceOptions.NONE); - dumpSlice(slice); - Assert.assertEquals(2, countAllocations(slice)); - Assert.assertEquals(1, countPutfields(slice)); - } - - @Test - public void testThin1() throws ClassHierarchyException, IllegalArgumentException, CancelException, IOException { - AnalysisScope scope = findOrCreateAnalysisScope(); - - IClassHierarchy cha = findOrCreateCHA(scope); - Iterable entrypoints = com.ibm.wala.ipa.callgraph.impl.Util.makeMainEntrypoints(scope, cha, - TestConstants.SLICE_TESTTHIN1); - AnalysisOptions options = CallGraphTestUtil.makeAnalysisOptions(scope, entrypoints); - - CallGraphBuilder builder = Util.makeZeroOneCFABuilder(options, new AnalysisCache(), cha, scope); - CallGraph cg = builder.makeCallGraph(options, null); - - CGNode main = findMainMethod(cg); - - Statement s = findCallToDoNothing(main); - System.err.println("Statement: " + s); - - // compute normal data slice - // compute a data slice - Collection slice = Slicer.computeBackwardSlice(s, cg, builder.getPointerAnalysis(), DataDependenceOptions.FULL, - ControlDependenceOptions.NONE); - dumpSlice(slice); - Assert.assertEquals(3, countAllocations(slice)); - Assert.assertEquals(2, countPutfields(slice)); - - // compute thin slice .. ignore base pointers - Collection computeBackwardSlice = Slicer.computeBackwardSlice(s, cg, builder.getPointerAnalysis(), - DataDependenceOptions.NO_BASE_PTRS, ControlDependenceOptions.NONE); - slice = computeBackwardSlice; - dumpSlice(slice); - Assert.assertEquals(2, countAllocations(slice)); - Assert.assertEquals(1, countPutfields(slice)); - } - - @Test - public void testTestGlobal() throws ClassHierarchyException, IllegalArgumentException, CancelException, IOException { - AnalysisScope scope = findOrCreateAnalysisScope(); - - IClassHierarchy cha = findOrCreateCHA(scope); - Iterable entrypoints = com.ibm.wala.ipa.callgraph.impl.Util.makeMainEntrypoints(scope, cha, - TestConstants.SLICE_TESTGLOBAL); - AnalysisOptions options = CallGraphTestUtil.makeAnalysisOptions(scope, entrypoints); - - CallGraphBuilder builder = Util.makeZeroOneCFABuilder(options, new AnalysisCache(), cha, scope); - CallGraph cg = builder.makeCallGraph(options, null); - - CGNode main = findMainMethod(cg); - - Statement s = findCallToDoNothing(main); - System.err.println("Statement: " + s); - // compute a data slice - Collection slice = Slicer.computeBackwardSlice(s, cg, builder.getPointerAnalysis(), DataDependenceOptions.FULL, - ControlDependenceOptions.NONE); - dumpSlice(slice); - Assert.assertEquals(1, countAllocations(slice)); - Assert.assertEquals(2, countPutstatics(slice)); - Assert.assertEquals(2, countGetstatics(slice)); - } - - @Test - public void testTestMultiTarget() throws ClassHierarchyException, IllegalArgumentException, CancelException, IOException { - AnalysisScope scope = findOrCreateAnalysisScope(); - - IClassHierarchy cha = findOrCreateCHA(scope); - Iterable entrypoints = com.ibm.wala.ipa.callgraph.impl.Util.makeMainEntrypoints(scope, cha, - TestConstants.SLICE_TESTMULTITARGET); - AnalysisOptions options = CallGraphTestUtil.makeAnalysisOptions(scope, entrypoints); - - CallGraphBuilder builder = Util.makeZeroOneCFABuilder(options, new AnalysisCache(), cha, scope); - CallGraph cg = builder.makeCallGraph(options, null); - - CGNode main = findMainMethod(cg); - - Statement s = findCallToDoNothing(main); - System.err.println("Statement: " + s); - // compute a data slice - Collection slice = Slicer.computeBackwardSlice(s, cg, builder.getPointerAnalysis(), DataDependenceOptions.FULL, - ControlDependenceOptions.NONE); - dumpSlice(slice); - Assert.assertEquals(2, countAllocations(slice)); - } - - @Test - public void testTestRecursion() throws ClassHierarchyException, IllegalArgumentException, CancelException, IOException { - AnalysisScope scope = findOrCreateAnalysisScope(); - - IClassHierarchy cha = findOrCreateCHA(scope); - Iterable entrypoints = com.ibm.wala.ipa.callgraph.impl.Util.makeMainEntrypoints(scope, cha, - TestConstants.SLICE_TESTRECURSION); - AnalysisOptions options = CallGraphTestUtil.makeAnalysisOptions(scope, entrypoints); - - CallGraphBuilder builder = Util.makeZeroOneCFABuilder(options, new AnalysisCache(), cha, scope); - CallGraph cg = builder.makeCallGraph(options, null); - - CGNode main = findMainMethod(cg); - - Statement s = findCallToDoNothing(main); - System.err.println("Statement: " + s); - - // compute a data slice - Collection slice = Slicer.computeBackwardSlice(s, cg, builder.getPointerAnalysis(), DataDependenceOptions.FULL, - ControlDependenceOptions.NONE); - dumpSlice(slice); - Assert.assertEquals(3, countAllocations(slice)); - Assert.assertEquals(2, countPutfields(slice)); - } - - @Test - public void testPrimGetterSetter() throws ClassHierarchyException, IllegalArgumentException, CancelException, IOException { - AnalysisScope scope = findOrCreateAnalysisScope(); - - IClassHierarchy cha = findOrCreateCHA(scope); - Iterable entrypoints = com.ibm.wala.ipa.callgraph.impl.Util.makeMainEntrypoints(scope, cha, - TestConstants.SLICE_TEST_PRIM_GETTER_SETTER); - AnalysisOptions options = CallGraphTestUtil.makeAnalysisOptions(scope, entrypoints); - - CallGraphBuilder builder = Util.makeZeroOneCFABuilder(options, new AnalysisCache(), cha, scope); - CallGraph cg = builder.makeCallGraph(options, null); - - CGNode test = findMethod(cg, "test"); - - PartialCallGraph pcg = PartialCallGraph.make(cg, Collections.singleton(test)); - - Statement s = findCallToDoNothing(test); - System.err.println("Statement: " + s); - - // compute full slice - Collection slice = Slicer.computeBackwardSlice(s, pcg, builder.getPointerAnalysis(), DataDependenceOptions.FULL, - ControlDependenceOptions.FULL); - dumpSlice(slice); - Assert.assertEquals(0, countAllocations(slice)); - Assert.assertEquals(1, countPutfields(slice)); - } - - @Test - public void testTestThrowCatch() throws ClassHierarchyException, IllegalArgumentException, CancelException, IOException { - AnalysisScope scope = findOrCreateAnalysisScope(); - - IClassHierarchy cha = findOrCreateCHA(scope); - Iterable entrypoints = com.ibm.wala.ipa.callgraph.impl.Util.makeMainEntrypoints(scope, cha, - TestConstants.SLICE_TESTTHROWCATCH); - AnalysisOptions options = CallGraphTestUtil.makeAnalysisOptions(scope, entrypoints); - - CallGraphBuilder builder = Util.makeZeroOneCFABuilder(options, new AnalysisCache(), cha, scope); - CallGraph cg = builder.makeCallGraph(options, null); - - CGNode main = findMainMethod(cg); - - Statement s = findCallToDoNothing(main); - System.err.println("Statement: " + s); - // compute a data slice - Collection slice = Slicer.computeBackwardSlice(s, cg, builder.getPointerAnalysis(), DataDependenceOptions.FULL, - ControlDependenceOptions.NONE); - dumpSlice(slice); - Assert.assertEquals(1, countAllocations(slice)); - Assert.assertEquals(1, countThrows(slice)); - Assert.assertEquals(1, countGetfields(slice)); - } - - @Test - public void testTestMessageFormat() throws ClassHierarchyException, IllegalArgumentException, CancelException, IOException { - AnalysisScope scope = findOrCreateAnalysisScope(); - - IClassHierarchy cha = findOrCreateCHA(scope); - Iterable entrypoints = com.ibm.wala.ipa.callgraph.impl.Util.makeMainEntrypoints(scope, cha, - TestConstants.SLICE_TESTMESSAGEFORMAT); - AnalysisOptions options = CallGraphTestUtil.makeAnalysisOptions(scope, entrypoints); - - CallGraphBuilder builder = Util.makeZeroCFABuilder(options, new AnalysisCache(), cha, scope); - CallGraph cg = builder.makeCallGraph(options, null); - - CGNode main = findMainMethod(cg); - Statement seed = new NormalStatement(main, 2); - - System.err.println("Statement: " + seed); - // compute a backwards thin slice - ThinSlicer ts = new ThinSlicer(cg, builder.getPointerAnalysis()); - Collection slice = ts.computeBackwardThinSlice(seed); - dumpSlice(slice); - - } - - /** - * test for bug reported on mailing list by Joshua Garcia, 5/16/2010 - */ - @Test - public void testTestInetAddr() throws ClassHierarchyException, IllegalArgumentException, CancelException, IOException, UnsoundGraphException { - AnalysisScope scope = findOrCreateAnalysisScope(); - - IClassHierarchy cha = findOrCreateCHA(scope); - Iterable entrypoints = com.ibm.wala.ipa.callgraph.impl.Util.makeMainEntrypoints(scope, cha, - TestConstants.SLICE_TESTINETADDR); - AnalysisOptions options = CallGraphTestUtil.makeAnalysisOptions(scope, entrypoints); - - CallGraphBuilder builder = Util.makeZeroOneCFABuilder(options, new AnalysisCache(), cha, scope); - CallGraph cg = builder.makeCallGraph(options, null); - SDG sdg = new SDG(cg, builder.getPointerAnalysis(), DataDependenceOptions.NO_BASE_NO_HEAP, ControlDependenceOptions.FULL); - GraphIntegrity.check(sdg); - } - - public static int countAllocations(Collection slice) { - int count = 0; - for (Statement s : slice) { - if (s.getKind().equals(Statement.Kind.NORMAL)) { - NormalStatement ns = (NormalStatement) s; - if (ns.getInstruction() instanceof SSANewInstruction) { - count++; - } - } - } - return count; - } - - public static int countThrows(Collection slice) { - int count = 0; - for (Statement s : slice) { - if (s.getKind().equals(Statement.Kind.NORMAL)) { - NormalStatement ns = (NormalStatement) s; - if (ns.getInstruction() instanceof SSAAbstractThrowInstruction) { - count++; - } - } - } - return count; - } - - public static int countAloads(Collection slice) { - int count = 0; - for (Statement s : slice) { - if (s.getKind().equals(Statement.Kind.NORMAL)) { - NormalStatement ns = (NormalStatement) s; - if (ns.getInstruction() instanceof SSAArrayLoadInstruction) { - count++; - } - } - } - return count; - } - - public static int countNormals(Collection slice) { - int count = 0; - for (Statement s : slice) { - if (s.getKind().equals(Statement.Kind.NORMAL)) { - count++; - } - } - return count; - } - - public static int countConditionals(Collection slice) { - int count = 0; - for (Statement s : slice) { - if (s.getKind().equals(Statement.Kind.NORMAL)) { - NormalStatement ns = (NormalStatement) s; - if (ns.getInstruction() instanceof SSAConditionalBranchInstruction) { - count++; - } - } - } - return count; - } - - public static int countInvokes(Collection slice) { - int count = 0; - for (Statement s : slice) { - if (s.getKind().equals(Statement.Kind.NORMAL)) { - NormalStatement ns = (NormalStatement) s; - if (ns.getInstruction() instanceof SSAAbstractInvokeInstruction) { - count++; - } - } - } - return count; - } - - public static int countPutfields(Collection slice) { - int count = 0; - for (Statement s : slice) { - if (s.getKind().equals(Statement.Kind.NORMAL)) { - NormalStatement ns = (NormalStatement) s; - if (ns.getInstruction() instanceof SSAPutInstruction) { - SSAPutInstruction p = (SSAPutInstruction) ns.getInstruction(); - if (!p.isStatic()) { - count++; - } - } - } - } - return count; - } - - public static int countGetfields(Collection slice) { - int count = 0; - for (Statement s : slice) { - if (s.getKind().equals(Statement.Kind.NORMAL)) { - NormalStatement ns = (NormalStatement) s; - if (ns.getInstruction() instanceof SSAGetInstruction) { - SSAGetInstruction p = (SSAGetInstruction) ns.getInstruction(); - if (!p.isStatic()) { - count++; - } - } - } - } - return count; - } - - public static int countPutstatics(Collection slice) { - int count = 0; - for (Statement s : slice) { - if (s.getKind().equals(Statement.Kind.NORMAL)) { - NormalStatement ns = (NormalStatement) s; - if (ns.getInstruction() instanceof SSAPutInstruction) { - SSAPutInstruction p = (SSAPutInstruction) ns.getInstruction(); - if (p.isStatic()) { - count++; - } - } - } - } - return count; - } - - public static int countGetstatics(Collection slice) { - int count = 0; - for (Statement s : slice) { - if (s.getKind().equals(Statement.Kind.NORMAL)) { - NormalStatement ns = (NormalStatement) s; - if (ns.getInstruction() instanceof SSAGetInstruction) { - SSAGetInstruction p = (SSAGetInstruction) ns.getInstruction(); - if (p.isStatic()) { - count++; - } - } - } - } - return count; - } - - public static void dumpSlice(Collection slice) { - dumpSlice(slice, new PrintWriter(System.err)); - } - - public static void dumpSlice(Collection slice, PrintWriter w) { - w.println("SLICE:\n"); - int i = 1; - for (Statement s : slice) { - String line = (i++) + " " + s; - w.println(line); - w.flush(); - } - } - - public static void dumpSliceToFile(Collection slice, String fileName) throws FileNotFoundException { - File f = new File(fileName); - FileOutputStream fo = new FileOutputStream(f); - PrintWriter w = new PrintWriter(fo); - dumpSlice(slice, w); - } - - public static CGNode findMainMethod(CallGraph cg) { - Descriptor d = Descriptor.findOrCreateUTF8("([Ljava/lang/String;)V"); - Atom name = Atom.findOrCreateUnicodeAtom("main"); - return findMethod(cg, d, name); - } - - /** - * @param cg - * @param d - * @param name - * @return - */ - private static CGNode findMethod(CallGraph cg, Descriptor d, Atom name) { - for (Iterator it = cg.getSuccNodes(cg.getFakeRootNode()); it.hasNext();) { - CGNode n = it.next(); - if (n.getMethod().getName().equals(name) && n.getMethod().getDescriptor().equals(d)) { - return n; - } - } - // if it's not a successor of fake root, just iterate over everything - for (CGNode n : cg) { - if (n.getMethod().getName().equals(name) && n.getMethod().getDescriptor().equals(d)) { - return n; - } - } - Assertions.UNREACHABLE("failed to find method " + name); - return null; - } - - public static CGNode findMethod(CallGraph cg, String name) { - Atom a = Atom.findOrCreateUnicodeAtom(name); - for (Iterator it = cg.iterator(); it.hasNext();) { - CGNode n = it.next(); - if (n.getMethod().getName().equals(a)) { - return n; - } - } - System.err.println("call graph " + cg); - Assertions.UNREACHABLE("failed to find method " + name); - return null; - } - - public static Statement findCallTo(CGNode n, String methodName) { - IR ir = n.getIR(); - for (Iterator it = ir.iterateAllInstructions(); it.hasNext();) { - SSAInstruction s = it.next(); - if (s instanceof SSAInvokeInstruction) { - SSAInvokeInstruction call = (SSAInvokeInstruction) s; - if (call.getCallSite().getDeclaredTarget().getName().toString().equals(methodName)) { - IntSet indices = ir.getCallInstructionIndices(((SSAInvokeInstruction) s).getCallSite()); - Assertions.productionAssertion(indices.size() == 1, "expected 1 but got " + indices.size()); - return new NormalStatement(n, indices.intIterator().next()); - } - } - } - Assertions.UNREACHABLE("failed to find call to " + methodName + " in " + n); - return null; - } - - public static Statement findFirstAllocation(CGNode n) { - IR ir = n.getIR(); - for (int i = 0; i < ir.getInstructions().length; i++) { - SSAInstruction s = ir.getInstructions()[i]; - if (s instanceof SSANewInstruction) { - return new NormalStatement(n, i); - } - } - Assertions.UNREACHABLE("failed to find allocation in " + n); - return null; - } - - private static Statement findCallToDoNothing(CGNode n) { - return findCallTo(n, "doNothing"); - } -} +/******************************************************************************* + * 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 com.ibm.wala.core.tests.slicer; + +import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.PrintWriter; +import java.util.Collection; +import java.util.Collections; +import java.util.Iterator; + +import org.junit.AfterClass; +import org.junit.Assert; +import org.junit.Test; + +import com.ibm.wala.core.tests.callGraph.CallGraphTestUtil; +import com.ibm.wala.core.tests.util.TestConstants; +import com.ibm.wala.examples.drivers.PDFSlice; +import com.ibm.wala.ipa.callgraph.AnalysisCache; +import com.ibm.wala.ipa.callgraph.AnalysisOptions; +import com.ibm.wala.ipa.callgraph.AnalysisScope; +import com.ibm.wala.ipa.callgraph.CGNode; +import com.ibm.wala.ipa.callgraph.CallGraph; +import com.ibm.wala.ipa.callgraph.CallGraphBuilder; +import com.ibm.wala.ipa.callgraph.Entrypoint; +import com.ibm.wala.ipa.callgraph.impl.PartialCallGraph; +import com.ibm.wala.ipa.callgraph.impl.Util; +import com.ibm.wala.ipa.cha.ClassHierarchy; +import com.ibm.wala.ipa.cha.ClassHierarchyException; +import com.ibm.wala.ipa.cha.IClassHierarchy; +import com.ibm.wala.ipa.slicer.MethodEntryStatement; +import com.ibm.wala.ipa.slicer.NormalStatement; +import com.ibm.wala.ipa.slicer.SDG; +import com.ibm.wala.ipa.slicer.Slicer; +import com.ibm.wala.ipa.slicer.Slicer.ControlDependenceOptions; +import com.ibm.wala.ipa.slicer.Slicer.DataDependenceOptions; +import com.ibm.wala.ipa.slicer.Statement; +import com.ibm.wala.ipa.slicer.thin.ThinSlicer; +import com.ibm.wala.ssa.IR; +import com.ibm.wala.ssa.SSAAbstractInvokeInstruction; +import com.ibm.wala.ssa.SSAAbstractThrowInstruction; +import com.ibm.wala.ssa.SSAArrayLoadInstruction; +import com.ibm.wala.ssa.SSAConditionalBranchInstruction; +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.SSAPutInstruction; +import com.ibm.wala.types.ClassLoaderReference; +import com.ibm.wala.types.Descriptor; +import com.ibm.wala.util.CancelException; +import com.ibm.wala.util.debug.Assertions; +import com.ibm.wala.util.graph.GraphIntegrity; +import com.ibm.wala.util.graph.GraphIntegrity.UnsoundGraphException; +import com.ibm.wala.util.intset.IntSet; +import com.ibm.wala.util.strings.Atom; + +public class SlicerTest { + + private static AnalysisScope cachedScope; + + private static AnalysisScope findOrCreateAnalysisScope() throws IOException { + if (cachedScope == null) { + cachedScope = CallGraphTestUtil.makeJ2SEAnalysisScope(TestConstants.WALA_TESTDATA, "Java60RegressionExclusions.txt"); + } + return cachedScope; + } + + private static IClassHierarchy cachedCHA; + + private static IClassHierarchy findOrCreateCHA(AnalysisScope scope) throws ClassHierarchyException { + if (cachedCHA == null) { + cachedCHA = ClassHierarchy.make(scope); + } + return cachedCHA; + } + + @AfterClass + public static void afterClass() { + cachedCHA = null; + cachedScope = null; + } + + @Test + public void testSlice1() throws ClassHierarchyException, IllegalArgumentException, CancelException, IOException { + AnalysisScope scope = findOrCreateAnalysisScope(); + IClassHierarchy cha = findOrCreateCHA(scope); + Iterable entrypoints = com.ibm.wala.ipa.callgraph.impl.Util.makeMainEntrypoints(scope, cha, + TestConstants.SLICE1_MAIN); + AnalysisOptions options = CallGraphTestUtil.makeAnalysisOptions(scope, entrypoints); + + CallGraphBuilder builder = Util.makeZeroOneCFABuilder(options, new AnalysisCache(), cha, scope); + CallGraph cg = builder.makeCallGraph(options, null); + + CGNode main = findMainMethod(cg); + + Statement s = findCallTo(main, "println"); + System.err.println("Statement: " + s); + // compute a data slice + Collection computeBackwardSlice = Slicer.computeBackwardSlice(s, cg, builder.getPointerAnalysis(), + DataDependenceOptions.FULL, ControlDependenceOptions.NONE); + Collection slice = computeBackwardSlice; + dumpSlice(slice); + + int i = 0; + for (Statement st : slice) { + if (st.getNode().getMethod().getDeclaringClass().getClassLoader().getReference().equals(ClassLoaderReference.Application)) { + i++; + } + } + Assert.assertEquals(16, i); + } + + @Test + public void testSlice2() throws ClassHierarchyException, IllegalArgumentException, CancelException, IOException { + AnalysisScope scope = findOrCreateAnalysisScope(); + IClassHierarchy cha = findOrCreateCHA(scope); + Iterable entrypoints = com.ibm.wala.ipa.callgraph.impl.Util.makeMainEntrypoints(scope, cha, + TestConstants.SLICE2_MAIN); + AnalysisOptions options = CallGraphTestUtil.makeAnalysisOptions(scope, entrypoints); + + CallGraphBuilder builder = Util.makeZeroOneCFABuilder(options, new AnalysisCache(), cha, scope); + CallGraph cg = builder.makeCallGraph(options, null); + + CGNode main = findMethod(cg, "baz"); + + Statement s = findCallTo(main, "println"); + System.err.println("Statement: " + s); + // compute a data slice + Collection computeBackwardSlice = Slicer.computeBackwardSlice(s, cg, builder.getPointerAnalysis(), + DataDependenceOptions.FULL, ControlDependenceOptions.NONE); + Collection slice = computeBackwardSlice; + dumpSlice(slice); + + Assert.assertEquals(9, countNormals(slice)); + } + + @Test + public void testSlice3() throws ClassHierarchyException, IllegalArgumentException, CancelException, IOException { + AnalysisScope scope = findOrCreateAnalysisScope(); + IClassHierarchy cha = findOrCreateCHA(scope); + Iterable entrypoints = com.ibm.wala.ipa.callgraph.impl.Util.makeMainEntrypoints(scope, cha, + TestConstants.SLICE3_MAIN); + AnalysisOptions options = CallGraphTestUtil.makeAnalysisOptions(scope, entrypoints); + + CallGraphBuilder builder = Util.makeZeroOneCFABuilder(options, new AnalysisCache(), cha, scope); + CallGraph cg = builder.makeCallGraph(options, null); + + CGNode main = findMethod(cg, "main"); + + Statement s = findCallTo(main, "doNothing"); + System.err.println("Statement: " + s); + // compute a data slice + Collection slice = Slicer.computeBackwardSlice(s, cg, builder.getPointerAnalysis(), DataDependenceOptions.FULL, + ControlDependenceOptions.NONE); + dumpSlice(slice); + Assert.assertEquals(1, countAllocations(slice)); + } + + @Test + public void testSlice4() throws ClassHierarchyException, IllegalArgumentException, CancelException, IOException { + AnalysisScope scope = findOrCreateAnalysisScope(); + + IClassHierarchy cha = findOrCreateCHA(scope); + Iterable entrypoints = com.ibm.wala.ipa.callgraph.impl.Util.makeMainEntrypoints(scope, cha, + TestConstants.SLICE4_MAIN); + AnalysisOptions options = CallGraphTestUtil.makeAnalysisOptions(scope, entrypoints); + + CallGraphBuilder builder = Util.makeZeroOneCFABuilder(options, new AnalysisCache(), cha, scope); + CallGraph cg = builder.makeCallGraph(options, null); + + CGNode main = findMainMethod(cg); + Statement s = findCallTo(main, "foo"); + s = PDFSlice.getReturnStatementForCall(s); + System.err.println("Statement: " + s); + // compute a data slice + Collection slice = Slicer.computeForwardSlice(s, cg, builder.getPointerAnalysis(), DataDependenceOptions.FULL, + ControlDependenceOptions.NONE); + dumpSlice(slice); + Assert.assertEquals(4, slice.size()); + } + + @Test + public void testSlice5() throws ClassHierarchyException, IllegalArgumentException, CancelException, IOException { + AnalysisScope scope = findOrCreateAnalysisScope(); + + IClassHierarchy cha = findOrCreateCHA(scope); + Iterable entrypoints = com.ibm.wala.ipa.callgraph.impl.Util.makeMainEntrypoints(scope, cha, + TestConstants.SLICE5_MAIN); + AnalysisOptions options = CallGraphTestUtil.makeAnalysisOptions(scope, entrypoints); + + CallGraphBuilder builder = Util.makeZeroOneCFABuilder(options, new AnalysisCache(), cha, scope); + CallGraph cg = builder.makeCallGraph(options, null); + + CGNode n = findMethod(cg, "baz"); + Statement s = findCallTo(n, "foo"); + s = PDFSlice.getReturnStatementForCall(s); + System.err.println("Statement: " + s); + // compute a data slice + Collection slice = Slicer.computeForwardSlice(s, cg, builder.getPointerAnalysis(), DataDependenceOptions.FULL, + ControlDependenceOptions.NONE); + dumpSlice(slice); + Assert.assertEquals(7, slice.size()); + } + + /** + * test unreproduced bug reported on mailing list by Sameer Madan, 7/3/2007 + * + * @throws CancelException + * @throws IllegalArgumentException + * @throws IOException + */ + @Test + public void testSlice7() throws ClassHierarchyException, IllegalArgumentException, CancelException, IOException { + AnalysisScope scope = findOrCreateAnalysisScope(); + + IClassHierarchy cha = findOrCreateCHA(scope); + Iterable entrypoints = com.ibm.wala.ipa.callgraph.impl.Util.makeMainEntrypoints(scope, cha, + TestConstants.SLICE7_MAIN); + AnalysisOptions options = CallGraphTestUtil.makeAnalysisOptions(scope, entrypoints); + + CallGraphBuilder builder = Util.makeZeroOneContainerCFABuilder(options, new AnalysisCache(), cha, scope); + CallGraph cg = builder.makeCallGraph(options, null); + + CGNode main = findMainMethod(cg); + Statement s = findFirstAllocation(main); + System.err.println("Statement: " + s); + // compute a data slice + Collection slice = Slicer.computeForwardSlice(s, cg, builder.getPointerAnalysis(), DataDependenceOptions.FULL, + ControlDependenceOptions.NONE); + dumpSlice(slice); + } + + /** + * test bug reported on mailing list by Ravi Chandhran, 4/16/2010 + * + * @throws CancelException + * @throws IllegalArgumentException + * @throws IOException + */ + @Test + public void testSlice8() throws ClassHierarchyException, IllegalArgumentException, CancelException, IOException { + AnalysisScope scope = findOrCreateAnalysisScope(); + + IClassHierarchy cha = findOrCreateCHA(scope); + Iterable entrypoints = com.ibm.wala.ipa.callgraph.impl.Util.makeMainEntrypoints(scope, cha, + TestConstants.SLICE8_MAIN); + AnalysisOptions options = CallGraphTestUtil.makeAnalysisOptions(scope, entrypoints); + + CallGraphBuilder builder = Util.makeVanillaZeroOneContainerCFABuilder(options, new AnalysisCache(), cha, scope); + CallGraph cg = builder.makeCallGraph(options, null); + + CGNode process = findMethod(cg, Descriptor.findOrCreateUTF8("()V"), Atom.findOrCreateUnicodeAtom("process")); + Statement s = findCallToDoNothing(process); + System.err.println("Statement: " + s); + // compute a backward slice, with data dependence and no exceptional control dependence + Collection slice = Slicer.computeBackwardSlice(s, cg, builder.getPointerAnalysis(), DataDependenceOptions.FULL, + ControlDependenceOptions.NO_EXCEPTIONAL_EDGES); + dumpSlice(slice); + Assert.assertEquals(4, countInvokes(slice)); + // should only get 4 statements total when ignoring control dependences completely + slice = Slicer.computeBackwardSlice(s, cg, builder.getPointerAnalysis(), DataDependenceOptions.FULL, + ControlDependenceOptions.NONE); + Assert.assertEquals(4, slice.size()); + } + + @Test + public void testTestCD1() throws ClassHierarchyException, IllegalArgumentException, CancelException, IOException { + AnalysisScope scope = findOrCreateAnalysisScope(); + + IClassHierarchy cha = findOrCreateCHA(scope); + Iterable entrypoints = com.ibm.wala.ipa.callgraph.impl.Util.makeMainEntrypoints(scope, cha, + TestConstants.SLICE_TESTCD1); + AnalysisOptions options = CallGraphTestUtil.makeAnalysisOptions(scope, entrypoints); + + CallGraphBuilder builder = Util.makeZeroOneCFABuilder(options, new AnalysisCache(), cha, scope); + CallGraph cg = builder.makeCallGraph(options, null); + + CGNode main = findMainMethod(cg); + + Statement s = findCallToDoNothing(main); + System.err.println("Statement: " + s); + // compute a data slice + Collection slice = Slicer.computeBackwardSlice(s, cg, builder.getPointerAnalysis(), DataDependenceOptions.NONE, + ControlDependenceOptions.FULL); + dumpSlice(slice); + Assert.assertEquals(2, countConditionals(slice)); + } + + @Test + public void testTestCD2() throws ClassHierarchyException, IllegalArgumentException, CancelException, IOException { + AnalysisScope scope = findOrCreateAnalysisScope(); + + IClassHierarchy cha = findOrCreateCHA(scope); + Iterable entrypoints = com.ibm.wala.ipa.callgraph.impl.Util.makeMainEntrypoints(scope, cha, + TestConstants.SLICE_TESTCD2); + AnalysisOptions options = CallGraphTestUtil.makeAnalysisOptions(scope, entrypoints); + + CallGraphBuilder builder = Util.makeZeroOneCFABuilder(options, new AnalysisCache(), cha, scope); + CallGraph cg = builder.makeCallGraph(options, null); + + CGNode main = findMainMethod(cg); + + Statement s = findCallToDoNothing(main); + System.err.println("Statement: " + s); + // compute a data slice + Collection slice = Slicer.computeBackwardSlice(s, cg, builder.getPointerAnalysis(), DataDependenceOptions.NONE, + ControlDependenceOptions.FULL); + dumpSlice(slice); + Assert.assertEquals(1, countConditionals(slice)); + } + + @Test + public void testTestCD3() throws ClassHierarchyException, IllegalArgumentException, CancelException, IOException { + AnalysisScope scope = findOrCreateAnalysisScope(); + + IClassHierarchy cha = findOrCreateCHA(scope); + Iterable entrypoints = com.ibm.wala.ipa.callgraph.impl.Util.makeMainEntrypoints(scope, cha, + TestConstants.SLICE_TESTCD3); + AnalysisOptions options = CallGraphTestUtil.makeAnalysisOptions(scope, entrypoints); + + CallGraphBuilder builder = Util.makeZeroOneCFABuilder(options, new AnalysisCache(), cha, scope); + CallGraph cg = builder.makeCallGraph(options, null); + + CGNode main = findMainMethod(cg); + + Statement s = findCallToDoNothing(main); + System.err.println("Statement: " + s); + // compute a data slice + Collection slice = Slicer.computeBackwardSlice(s, cg, builder.getPointerAnalysis(), DataDependenceOptions.NONE, + ControlDependenceOptions.FULL); + dumpSlice(slice); + Assert.assertEquals(0, countConditionals(slice)); + } + + @Test + public void testTestCD4() throws ClassHierarchyException, IllegalArgumentException, CancelException, IOException { + AnalysisScope scope = findOrCreateAnalysisScope(); + + IClassHierarchy cha = findOrCreateCHA(scope); + Iterable entrypoints = com.ibm.wala.ipa.callgraph.impl.Util.makeMainEntrypoints(scope, cha, + TestConstants.SLICE_TESTCD4); + AnalysisOptions options = CallGraphTestUtil.makeAnalysisOptions(scope, entrypoints); + + CallGraphBuilder builder = Util.makeZeroOneCFABuilder(options, new AnalysisCache(), cha, scope); + CallGraph cg = builder.makeCallGraph(options, null); + + CGNode main = findMainMethod(cg); + + Statement s = findCallToDoNothing(main); + System.err.println("Statement: " + s); + + // compute a no-data slice + Collection slice = Slicer.computeBackwardSlice(s, cg, builder.getPointerAnalysis(), DataDependenceOptions.NONE, + ControlDependenceOptions.FULL); + dumpSlice(slice); + Assert.assertEquals(0, countConditionals(slice)); + + // compute a full slice + slice = Slicer.computeBackwardSlice(s, cg, builder.getPointerAnalysis(), DataDependenceOptions.FULL, + ControlDependenceOptions.FULL); + dumpSlice(slice); + Assert.assertEquals(1, countConditionals(slice)); + } + + @Test + public void testTestCD5() throws ClassHierarchyException, IllegalArgumentException, CancelException, IOException { + AnalysisScope scope = findOrCreateAnalysisScope(); + + IClassHierarchy cha = findOrCreateCHA(scope); + Iterable entrypoints = com.ibm.wala.ipa.callgraph.impl.Util.makeMainEntrypoints(scope, cha, + TestConstants.SLICE_TESTCD5); + AnalysisOptions options = CallGraphTestUtil.makeAnalysisOptions(scope, entrypoints); + + CallGraphBuilder builder = Util.makeZeroOneCFABuilder(options, new AnalysisCache(), cha, scope); + CallGraph cg = builder.makeCallGraph(options, null); + + CGNode main = findMainMethod(cg); + + Statement s = new MethodEntryStatement(main); + System.err.println("Statement: " + s); + + // compute a no-data slice + Collection slice = Slicer.computeForwardSlice(s, cg, builder.getPointerAnalysis(), DataDependenceOptions.NONE, + ControlDependenceOptions.NO_EXCEPTIONAL_EDGES); + dumpSlice(slice); + Assert.assertTrue(slice.size() > 1); + } + + @Test + public void testTestCD6() throws ClassHierarchyException, IllegalArgumentException, CancelException, IOException { + AnalysisScope scope = findOrCreateAnalysisScope(); + + IClassHierarchy cha = findOrCreateCHA(scope); + Iterable entrypoints = com.ibm.wala.ipa.callgraph.impl.Util.makeMainEntrypoints(scope, cha, + TestConstants.SLICE_TESTCD6); + AnalysisOptions options = CallGraphTestUtil.makeAnalysisOptions(scope, entrypoints); + + CallGraphBuilder builder = Util.makeZeroOneCFABuilder(options, new AnalysisCache(), cha, scope); + CallGraph cg = builder.makeCallGraph(options, null); + + CGNode main = findMainMethod(cg); + + Statement s = new MethodEntryStatement(main); + System.err.println("Statement: " + s); + + // compute a no-data slice + Collection slice = Slicer.computeForwardSlice(s, cg, builder.getPointerAnalysis(), DataDependenceOptions.NONE, + ControlDependenceOptions.NO_EXCEPTIONAL_EDGES); + dumpSlice(slice); + Assert.assertEquals(2, countInvokes(slice)); + } + + @Test + public void testTestId() throws ClassHierarchyException, IllegalArgumentException, CancelException, IOException { + AnalysisScope scope = findOrCreateAnalysisScope(); + + IClassHierarchy cha = findOrCreateCHA(scope); + Iterable entrypoints = com.ibm.wala.ipa.callgraph.impl.Util.makeMainEntrypoints(scope, cha, + TestConstants.SLICE_TESTID); + AnalysisOptions options = CallGraphTestUtil.makeAnalysisOptions(scope, entrypoints); + + CallGraphBuilder builder = Util.makeZeroOneCFABuilder(options, new AnalysisCache(), cha, scope); + CallGraph cg = builder.makeCallGraph(options, null); + + CGNode main = findMainMethod(cg); + + Statement s = findCallToDoNothing(main); + System.err.println("Statement: " + s); + // compute a data slice + Collection slice = Slicer.computeBackwardSlice(s, cg, builder.getPointerAnalysis(), DataDependenceOptions.FULL, + ControlDependenceOptions.NONE); + dumpSlice(slice); + Assert.assertEquals(1, countAllocations(slice)); + } + + @Test + public void testTestArrays() throws ClassHierarchyException, IllegalArgumentException, CancelException, IOException { + AnalysisScope scope = findOrCreateAnalysisScope(); + + IClassHierarchy cha = findOrCreateCHA(scope); + Iterable entrypoints = com.ibm.wala.ipa.callgraph.impl.Util.makeMainEntrypoints(scope, cha, + TestConstants.SLICE_TESTARRAYS); + AnalysisOptions options = CallGraphTestUtil.makeAnalysisOptions(scope, entrypoints); + + CallGraphBuilder builder = Util.makeZeroOneCFABuilder(options, new AnalysisCache(), cha, scope); + CallGraph cg = builder.makeCallGraph(options, null); + + CGNode main = findMainMethod(cg); + + Statement s = findCallToDoNothing(main); + System.err.println("Statement: " + s); + // compute a data slice + Collection slice = Slicer.computeBackwardSlice(s, cg, builder.getPointerAnalysis(), DataDependenceOptions.FULL, + ControlDependenceOptions.NONE); + dumpSlice(slice); + Assert.assertEquals(2, countAllocations(slice)); + Assert.assertEquals(1, countAloads(slice)); + } + + @Test + public void testTestFields() throws ClassHierarchyException, IllegalArgumentException, CancelException, IOException { + AnalysisScope scope = findOrCreateAnalysisScope(); + + IClassHierarchy cha = findOrCreateCHA(scope); + Iterable entrypoints = com.ibm.wala.ipa.callgraph.impl.Util.makeMainEntrypoints(scope, cha, + TestConstants.SLICE_TESTFIELDS); + AnalysisOptions options = CallGraphTestUtil.makeAnalysisOptions(scope, entrypoints); + + CallGraphBuilder builder = Util.makeZeroOneCFABuilder(options, new AnalysisCache(), cha, scope); + CallGraph cg = builder.makeCallGraph(options, null); + + CGNode main = findMainMethod(cg); + + Statement s = findCallToDoNothing(main); + System.err.println("Statement: " + s); + // compute a data slice + Collection slice = Slicer.computeBackwardSlice(s, cg, builder.getPointerAnalysis(), DataDependenceOptions.FULL, + ControlDependenceOptions.NONE); + dumpSlice(slice); + Assert.assertEquals(2, countAllocations(slice)); + Assert.assertEquals(1, countPutfields(slice)); + } + + @Test + public void testThin1() throws ClassHierarchyException, IllegalArgumentException, CancelException, IOException { + AnalysisScope scope = findOrCreateAnalysisScope(); + + IClassHierarchy cha = findOrCreateCHA(scope); + Iterable entrypoints = com.ibm.wala.ipa.callgraph.impl.Util.makeMainEntrypoints(scope, cha, + TestConstants.SLICE_TESTTHIN1); + AnalysisOptions options = CallGraphTestUtil.makeAnalysisOptions(scope, entrypoints); + + CallGraphBuilder builder = Util.makeZeroOneCFABuilder(options, new AnalysisCache(), cha, scope); + CallGraph cg = builder.makeCallGraph(options, null); + + CGNode main = findMainMethod(cg); + + Statement s = findCallToDoNothing(main); + System.err.println("Statement: " + s); + + // compute normal data slice + // compute a data slice + Collection slice = Slicer.computeBackwardSlice(s, cg, builder.getPointerAnalysis(), DataDependenceOptions.FULL, + ControlDependenceOptions.NONE); + dumpSlice(slice); + Assert.assertEquals(3, countAllocations(slice)); + Assert.assertEquals(2, countPutfields(slice)); + + // compute thin slice .. ignore base pointers + Collection computeBackwardSlice = Slicer.computeBackwardSlice(s, cg, builder.getPointerAnalysis(), + DataDependenceOptions.NO_BASE_PTRS, ControlDependenceOptions.NONE); + slice = computeBackwardSlice; + dumpSlice(slice); + Assert.assertEquals(2, countAllocations(slice)); + Assert.assertEquals(1, countPutfields(slice)); + } + + @Test + public void testTestGlobal() throws ClassHierarchyException, IllegalArgumentException, CancelException, IOException { + AnalysisScope scope = findOrCreateAnalysisScope(); + + IClassHierarchy cha = findOrCreateCHA(scope); + Iterable entrypoints = com.ibm.wala.ipa.callgraph.impl.Util.makeMainEntrypoints(scope, cha, + TestConstants.SLICE_TESTGLOBAL); + AnalysisOptions options = CallGraphTestUtil.makeAnalysisOptions(scope, entrypoints); + + CallGraphBuilder builder = Util.makeZeroOneCFABuilder(options, new AnalysisCache(), cha, scope); + CallGraph cg = builder.makeCallGraph(options, null); + + CGNode main = findMainMethod(cg); + + Statement s = findCallToDoNothing(main); + System.err.println("Statement: " + s); + // compute a data slice + Collection slice = Slicer.computeBackwardSlice(s, cg, builder.getPointerAnalysis(), DataDependenceOptions.FULL, + ControlDependenceOptions.NONE); + dumpSlice(slice); + Assert.assertEquals(1, countAllocations(slice)); + Assert.assertEquals(2, countPutstatics(slice)); + Assert.assertEquals(2, countGetstatics(slice)); + } + + @Test + public void testTestMultiTarget() throws ClassHierarchyException, IllegalArgumentException, CancelException, IOException { + AnalysisScope scope = findOrCreateAnalysisScope(); + + IClassHierarchy cha = findOrCreateCHA(scope); + Iterable entrypoints = com.ibm.wala.ipa.callgraph.impl.Util.makeMainEntrypoints(scope, cha, + TestConstants.SLICE_TESTMULTITARGET); + AnalysisOptions options = CallGraphTestUtil.makeAnalysisOptions(scope, entrypoints); + + CallGraphBuilder builder = Util.makeZeroOneCFABuilder(options, new AnalysisCache(), cha, scope); + CallGraph cg = builder.makeCallGraph(options, null); + + CGNode main = findMainMethod(cg); + + Statement s = findCallToDoNothing(main); + System.err.println("Statement: " + s); + // compute a data slice + Collection slice = Slicer.computeBackwardSlice(s, cg, builder.getPointerAnalysis(), DataDependenceOptions.FULL, + ControlDependenceOptions.NONE); + dumpSlice(slice); + Assert.assertEquals(2, countAllocations(slice)); + } + + @Test + public void testTestRecursion() throws ClassHierarchyException, IllegalArgumentException, CancelException, IOException { + AnalysisScope scope = findOrCreateAnalysisScope(); + + IClassHierarchy cha = findOrCreateCHA(scope); + Iterable entrypoints = com.ibm.wala.ipa.callgraph.impl.Util.makeMainEntrypoints(scope, cha, + TestConstants.SLICE_TESTRECURSION); + AnalysisOptions options = CallGraphTestUtil.makeAnalysisOptions(scope, entrypoints); + + CallGraphBuilder builder = Util.makeZeroOneCFABuilder(options, new AnalysisCache(), cha, scope); + CallGraph cg = builder.makeCallGraph(options, null); + + CGNode main = findMainMethod(cg); + + Statement s = findCallToDoNothing(main); + System.err.println("Statement: " + s); + + // compute a data slice + Collection slice = Slicer.computeBackwardSlice(s, cg, builder.getPointerAnalysis(), DataDependenceOptions.FULL, + ControlDependenceOptions.NONE); + dumpSlice(slice); + Assert.assertEquals(3, countAllocations(slice)); + Assert.assertEquals(2, countPutfields(slice)); + } + + @Test + public void testPrimGetterSetter() throws ClassHierarchyException, IllegalArgumentException, CancelException, IOException { + AnalysisScope scope = findOrCreateAnalysisScope(); + + IClassHierarchy cha = findOrCreateCHA(scope); + Iterable entrypoints = com.ibm.wala.ipa.callgraph.impl.Util.makeMainEntrypoints(scope, cha, + TestConstants.SLICE_TEST_PRIM_GETTER_SETTER); + AnalysisOptions options = CallGraphTestUtil.makeAnalysisOptions(scope, entrypoints); + + CallGraphBuilder builder = Util.makeZeroOneCFABuilder(options, new AnalysisCache(), cha, scope); + CallGraph cg = builder.makeCallGraph(options, null); + + CGNode test = findMethod(cg, "test"); + + PartialCallGraph pcg = PartialCallGraph.make(cg, Collections.singleton(test)); + + Statement s = findCallToDoNothing(test); + System.err.println("Statement: " + s); + + // compute full slice + Collection slice = Slicer.computeBackwardSlice(s, pcg, builder.getPointerAnalysis(), DataDependenceOptions.FULL, + ControlDependenceOptions.FULL); + dumpSlice(slice); + Assert.assertEquals(0, countAllocations(slice)); + Assert.assertEquals(1, countPutfields(slice)); + } + + @Test + public void testTestThrowCatch() throws ClassHierarchyException, IllegalArgumentException, CancelException, IOException { + AnalysisScope scope = findOrCreateAnalysisScope(); + + IClassHierarchy cha = findOrCreateCHA(scope); + Iterable entrypoints = com.ibm.wala.ipa.callgraph.impl.Util.makeMainEntrypoints(scope, cha, + TestConstants.SLICE_TESTTHROWCATCH); + AnalysisOptions options = CallGraphTestUtil.makeAnalysisOptions(scope, entrypoints); + + CallGraphBuilder builder = Util.makeZeroOneCFABuilder(options, new AnalysisCache(), cha, scope); + CallGraph cg = builder.makeCallGraph(options, null); + + CGNode main = findMainMethod(cg); + + Statement s = findCallToDoNothing(main); + System.err.println("Statement: " + s); + // compute a data slice + Collection slice = Slicer.computeBackwardSlice(s, cg, builder.getPointerAnalysis(), DataDependenceOptions.FULL, + ControlDependenceOptions.NONE); + dumpSlice(slice); + Assert.assertEquals(1, countAllocations(slice)); + Assert.assertEquals(1, countThrows(slice)); + Assert.assertEquals(1, countGetfields(slice)); + } + + @Test + public void testTestMessageFormat() throws ClassHierarchyException, IllegalArgumentException, CancelException, IOException { + AnalysisScope scope = findOrCreateAnalysisScope(); + + IClassHierarchy cha = findOrCreateCHA(scope); + Iterable entrypoints = com.ibm.wala.ipa.callgraph.impl.Util.makeMainEntrypoints(scope, cha, + TestConstants.SLICE_TESTMESSAGEFORMAT); + AnalysisOptions options = CallGraphTestUtil.makeAnalysisOptions(scope, entrypoints); + + CallGraphBuilder builder = Util.makeZeroCFABuilder(options, new AnalysisCache(), cha, scope); + CallGraph cg = builder.makeCallGraph(options, null); + + CGNode main = findMainMethod(cg); + Statement seed = new NormalStatement(main, 2); + + System.err.println("Statement: " + seed); + // compute a backwards thin slice + ThinSlicer ts = new ThinSlicer(cg, builder.getPointerAnalysis()); + Collection slice = ts.computeBackwardThinSlice(seed); + dumpSlice(slice); + + } + + /** + * test for bug reported on mailing list by Joshua Garcia, 5/16/2010 + */ + @Test + public void testTestInetAddr() throws ClassHierarchyException, IllegalArgumentException, CancelException, IOException, UnsoundGraphException { + AnalysisScope scope = findOrCreateAnalysisScope(); + + IClassHierarchy cha = findOrCreateCHA(scope); + Iterable entrypoints = com.ibm.wala.ipa.callgraph.impl.Util.makeMainEntrypoints(scope, cha, + TestConstants.SLICE_TESTINETADDR); + AnalysisOptions options = CallGraphTestUtil.makeAnalysisOptions(scope, entrypoints); + + CallGraphBuilder builder = Util.makeZeroOneCFABuilder(options, new AnalysisCache(), cha, scope); + CallGraph cg = builder.makeCallGraph(options, null); + SDG sdg = new SDG(cg, builder.getPointerAnalysis(), DataDependenceOptions.NO_BASE_NO_HEAP, ControlDependenceOptions.FULL); + GraphIntegrity.check(sdg); + } + + public static int countAllocations(Collection slice) { + int count = 0; + for (Statement s : slice) { + if (s.getKind().equals(Statement.Kind.NORMAL)) { + NormalStatement ns = (NormalStatement) s; + if (ns.getInstruction() instanceof SSANewInstruction) { + count++; + } + } + } + return count; + } + + public static int countThrows(Collection slice) { + int count = 0; + for (Statement s : slice) { + if (s.getKind().equals(Statement.Kind.NORMAL)) { + NormalStatement ns = (NormalStatement) s; + if (ns.getInstruction() instanceof SSAAbstractThrowInstruction) { + count++; + } + } + } + return count; + } + + public static int countAloads(Collection slice) { + int count = 0; + for (Statement s : slice) { + if (s.getKind().equals(Statement.Kind.NORMAL)) { + NormalStatement ns = (NormalStatement) s; + if (ns.getInstruction() instanceof SSAArrayLoadInstruction) { + count++; + } + } + } + return count; + } + + public static int countNormals(Collection slice) { + int count = 0; + for (Statement s : slice) { + if (s.getKind().equals(Statement.Kind.NORMAL)) { + count++; + } + } + return count; + } + + public static int countConditionals(Collection slice) { + int count = 0; + for (Statement s : slice) { + if (s.getKind().equals(Statement.Kind.NORMAL)) { + NormalStatement ns = (NormalStatement) s; + if (ns.getInstruction() instanceof SSAConditionalBranchInstruction) { + count++; + } + } + } + return count; + } + + public static int countInvokes(Collection slice) { + int count = 0; + for (Statement s : slice) { + if (s.getKind().equals(Statement.Kind.NORMAL)) { + NormalStatement ns = (NormalStatement) s; + if (ns.getInstruction() instanceof SSAAbstractInvokeInstruction) { + count++; + } + } + } + return count; + } + + public static int countPutfields(Collection slice) { + int count = 0; + for (Statement s : slice) { + if (s.getKind().equals(Statement.Kind.NORMAL)) { + NormalStatement ns = (NormalStatement) s; + if (ns.getInstruction() instanceof SSAPutInstruction) { + SSAPutInstruction p = (SSAPutInstruction) ns.getInstruction(); + if (!p.isStatic()) { + count++; + } + } + } + } + return count; + } + + public static int countGetfields(Collection slice) { + int count = 0; + for (Statement s : slice) { + if (s.getKind().equals(Statement.Kind.NORMAL)) { + NormalStatement ns = (NormalStatement) s; + if (ns.getInstruction() instanceof SSAGetInstruction) { + SSAGetInstruction p = (SSAGetInstruction) ns.getInstruction(); + if (!p.isStatic()) { + count++; + } + } + } + } + return count; + } + + public static int countPutstatics(Collection slice) { + int count = 0; + for (Statement s : slice) { + if (s.getKind().equals(Statement.Kind.NORMAL)) { + NormalStatement ns = (NormalStatement) s; + if (ns.getInstruction() instanceof SSAPutInstruction) { + SSAPutInstruction p = (SSAPutInstruction) ns.getInstruction(); + if (p.isStatic()) { + count++; + } + } + } + } + return count; + } + + public static int countGetstatics(Collection slice) { + int count = 0; + for (Statement s : slice) { + if (s.getKind().equals(Statement.Kind.NORMAL)) { + NormalStatement ns = (NormalStatement) s; + if (ns.getInstruction() instanceof SSAGetInstruction) { + SSAGetInstruction p = (SSAGetInstruction) ns.getInstruction(); + if (p.isStatic()) { + count++; + } + } + } + } + return count; + } + + public static void dumpSlice(Collection slice) { + dumpSlice(slice, new PrintWriter(System.err)); + } + + public static void dumpSlice(Collection slice, PrintWriter w) { + w.println("SLICE:\n"); + int i = 1; + for (Statement s : slice) { + String line = (i++) + " " + s; + w.println(line); + w.flush(); + } + } + + public static void dumpSliceToFile(Collection slice, String fileName) throws FileNotFoundException { + File f = new File(fileName); + FileOutputStream fo = new FileOutputStream(f); + PrintWriter w = new PrintWriter(fo); + dumpSlice(slice, w); + } + + public static CGNode findMainMethod(CallGraph cg) { + Descriptor d = Descriptor.findOrCreateUTF8("([Ljava/lang/String;)V"); + Atom name = Atom.findOrCreateUnicodeAtom("main"); + return findMethod(cg, d, name); + } + + /** + * @param cg + * @param d + * @param name + * @return + */ + private static CGNode findMethod(CallGraph cg, Descriptor d, Atom name) { + for (Iterator it = cg.getSuccNodes(cg.getFakeRootNode()); it.hasNext();) { + CGNode n = it.next(); + if (n.getMethod().getName().equals(name) && n.getMethod().getDescriptor().equals(d)) { + return n; + } + } + // if it's not a successor of fake root, just iterate over everything + for (CGNode n : cg) { + if (n.getMethod().getName().equals(name) && n.getMethod().getDescriptor().equals(d)) { + return n; + } + } + Assertions.UNREACHABLE("failed to find method " + name); + return null; + } + + public static CGNode findMethod(CallGraph cg, String name) { + Atom a = Atom.findOrCreateUnicodeAtom(name); + for (Iterator it = cg.iterator(); it.hasNext();) { + CGNode n = it.next(); + if (n.getMethod().getName().equals(a)) { + return n; + } + } + System.err.println("call graph " + cg); + Assertions.UNREACHABLE("failed to find method " + name); + return null; + } + + public static Statement findCallTo(CGNode n, String methodName) { + IR ir = n.getIR(); + for (Iterator it = ir.iterateAllInstructions(); it.hasNext();) { + SSAInstruction s = it.next(); + if (s instanceof SSAInvokeInstruction) { + SSAInvokeInstruction call = (SSAInvokeInstruction) s; + if (call.getCallSite().getDeclaredTarget().getName().toString().equals(methodName)) { + IntSet indices = ir.getCallInstructionIndices(((SSAInvokeInstruction) s).getCallSite()); + Assertions.productionAssertion(indices.size() == 1, "expected 1 but got " + indices.size()); + return new NormalStatement(n, indices.intIterator().next()); + } + } + } + Assertions.UNREACHABLE("failed to find call to " + methodName + " in " + n); + return null; + } + + public static Statement findFirstAllocation(CGNode n) { + IR ir = n.getIR(); + for (int i = 0; i < ir.getInstructions().length; i++) { + SSAInstruction s = ir.getInstructions()[i]; + if (s instanceof SSANewInstruction) { + return new NormalStatement(n, i); + } + } + Assertions.UNREACHABLE("failed to find allocation in " + n); + return null; + } + + private static Statement findCallToDoNothing(CGNode n) { + return findCallTo(n, "doNothing"); + } +} diff --git a/com.ibm.wala.core.tests/src/com/ibm/wala/core/tests/typeInference/TypeInferenceTest.java b/com.ibm.wala.core.tests/src/com/ibm/wala/core/tests/typeInference/TypeInferenceTest.java index 4371badcf..bdc0f530e 100644 --- a/com.ibm.wala.core.tests/src/com/ibm/wala/core/tests/typeInference/TypeInferenceTest.java +++ b/com.ibm.wala.core.tests/src/com/ibm/wala/core/tests/typeInference/TypeInferenceTest.java @@ -1,148 +1,148 @@ -/******************************************************************************* - * 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.core.tests.typeInference; - -import org.junit.AfterClass; -import org.junit.Assert; -import org.junit.BeforeClass; -import org.junit.Test; - -import com.ibm.wala.analysis.typeInference.ConeType; -import com.ibm.wala.analysis.typeInference.TypeAbstraction; -import com.ibm.wala.analysis.typeInference.TypeInference; -import com.ibm.wala.classLoader.ClassLoaderFactory; -import com.ibm.wala.classLoader.ClassLoaderFactoryImpl; -import com.ibm.wala.classLoader.IMethod; -import com.ibm.wala.core.tests.util.TestConstants; -import com.ibm.wala.core.tests.util.WalaTestCase; -import com.ibm.wala.ipa.callgraph.AnalysisCache; -import com.ibm.wala.ipa.callgraph.AnalysisOptions; -import com.ibm.wala.ipa.callgraph.AnalysisScope; -import com.ibm.wala.ipa.callgraph.impl.Everywhere; -import com.ibm.wala.ipa.cha.ClassHierarchy; -import com.ibm.wala.ipa.cha.ClassHierarchyException; -import com.ibm.wala.ssa.IR; -import com.ibm.wala.types.MethodReference; -import com.ibm.wala.util.config.AnalysisScopeReader; -import com.ibm.wala.util.io.FileProvider; -import com.ibm.wala.util.strings.Atom; -import com.ibm.wala.util.strings.ImmutableByteArray; -import com.ibm.wala.util.strings.UTF8Convert; -import com.ibm.wala.util.warnings.Warnings; - -/** - * Test that the SSA-numbering of variables in the IR is deterministic. - * - * Introduced 05-AUG-03; the default implementation of hashCode was being - * invoked. Object.hashCode is a source of random numbers and has no place in a - * deterministic program. - */ -public class TypeInferenceTest extends WalaTestCase { - - private static final ClassLoader MY_CLASSLOADER = TypeInferenceTest.class.getClassLoader(); - - private static AnalysisScope scope; - - private static ClassHierarchy cha; - - private static AnalysisOptions options; - - private static AnalysisCache cache; - - public static void main(String[] args) { - justThisTest(TypeInferenceTest.class); - } - - @BeforeClass - public static void beforeClass() throws Exception { - - scope = AnalysisScopeReader.readJavaScope(TestConstants.WALA_TESTDATA, (new FileProvider()).getFile("J2SEClassHierarchyExclusions.txt"), MY_CLASSLOADER); - - options = new AnalysisOptions(scope, null); - cache = new AnalysisCache(); - ClassLoaderFactory factory = new ClassLoaderFactoryImpl(scope.getExclusions()); - - try { - cha = ClassHierarchy.make(scope, factory); - } catch (ClassHierarchyException e) { - throw new Exception(); - } - } - - @AfterClass - public static void afterClass() throws Exception { - Warnings.clear(); - scope = null; - cha = null; - options = null; - cache = null; - } - - @Test public void test1() { - MethodReference method = scope.findMethod(AnalysisScope.APPLICATION, "LtypeInference/TI", Atom.findOrCreateUnicodeAtom("foo"), - new ImmutableByteArray(UTF8Convert.toUTF8("()V"))); - Assert.assertNotNull("method not found", method); - IMethod imethod = cha.resolveMethod(method); - Assert.assertNotNull("imethod not found", imethod); - IR ir = cache.getIRFactory().makeIR(imethod, Everywhere.EVERYWHERE, options.getSSAOptions()); - System.out.println(ir); - - TypeInference ti = TypeInference.make(ir, false); - for (int i = 1; i <= ir.getSymbolTable().getMaxValueNumber(); i++) { - System.err.println(i + " " + ti.getType(i)); - } - } - - @Test public void test2() { - MethodReference method = scope.findMethod(AnalysisScope.APPLICATION, "LtypeInference/TI", Atom.findOrCreateUnicodeAtom("bar"), - new ImmutableByteArray(UTF8Convert.toUTF8("(I)V"))); - Assert.assertNotNull("method not found", method); - IMethod imethod = cha.resolveMethod(method); - Assert.assertNotNull("imethod not found", imethod); - IR ir = cache.getIRFactory().makeIR(imethod, Everywhere.EVERYWHERE, options.getSSAOptions()); - System.out.println(ir); - - TypeInference ti = TypeInference.make(ir, true); - Assert.assertNotNull("null type abstraction for parameter", ti.getType(2)); - } - - @Test public void test3() { - MethodReference method = scope.findMethod(AnalysisScope.APPLICATION, "LtypeInference/TI", Atom.findOrCreateUnicodeAtom("inferInt"), - new ImmutableByteArray(UTF8Convert.toUTF8("()V"))); - Assert.assertNotNull("method not found", method); - IMethod imethod = cha.resolveMethod(method); - Assert.assertNotNull("imethod not found", imethod); - IR ir = cache.getIRFactory().makeIR(imethod, Everywhere.EVERYWHERE, options.getSSAOptions()); - System.out.println(ir); - - TypeInference ti = TypeInference.make(ir, true); - TypeAbstraction type = ti.getType(7); - Assert.assertNotNull("null type abstraction", type); - Assert.assertTrue("inferred wrong type", type.toString().equals("int")); - } - - @Test public void test4() { - MethodReference method = scope.findMethod(AnalysisScope.APPLICATION, "LtypeInference/TI", Atom.findOrCreateUnicodeAtom("useCast"), - new ImmutableByteArray(UTF8Convert.toUTF8("(Ljava/lang/Object;)V"))); - Assert.assertNotNull("method not found", method); - IMethod imethod = cha.resolveMethod(method); - Assert.assertNotNull("imethod not found", imethod); - IR ir = cache.getIRFactory().makeIR(imethod, Everywhere.EVERYWHERE, options.getSSAOptions()); - System.out.println(ir); - - TypeInference ti = TypeInference.make(ir, false); - TypeAbstraction type = ti.getType(4); - Assert.assertNotNull("null type abstraction", type); - Assert.assertTrue("inferred wrong type " + type, type instanceof ConeType && ((ConeType)type).getTypeReference().getName().toString().equals("Ljava/lang/String")); - } - - -} +/******************************************************************************* + * 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.core.tests.typeInference; + +import org.junit.AfterClass; +import org.junit.Assert; +import org.junit.BeforeClass; +import org.junit.Test; + +import com.ibm.wala.analysis.typeInference.ConeType; +import com.ibm.wala.analysis.typeInference.TypeAbstraction; +import com.ibm.wala.analysis.typeInference.TypeInference; +import com.ibm.wala.classLoader.ClassLoaderFactory; +import com.ibm.wala.classLoader.ClassLoaderFactoryImpl; +import com.ibm.wala.classLoader.IMethod; +import com.ibm.wala.core.tests.util.TestConstants; +import com.ibm.wala.core.tests.util.WalaTestCase; +import com.ibm.wala.ipa.callgraph.AnalysisCache; +import com.ibm.wala.ipa.callgraph.AnalysisOptions; +import com.ibm.wala.ipa.callgraph.AnalysisScope; +import com.ibm.wala.ipa.callgraph.impl.Everywhere; +import com.ibm.wala.ipa.cha.ClassHierarchy; +import com.ibm.wala.ipa.cha.ClassHierarchyException; +import com.ibm.wala.ssa.IR; +import com.ibm.wala.types.MethodReference; +import com.ibm.wala.util.config.AnalysisScopeReader; +import com.ibm.wala.util.io.FileProvider; +import com.ibm.wala.util.strings.Atom; +import com.ibm.wala.util.strings.ImmutableByteArray; +import com.ibm.wala.util.strings.UTF8Convert; +import com.ibm.wala.util.warnings.Warnings; + +/** + * Test that the SSA-numbering of variables in the IR is deterministic. + * + * Introduced 05-AUG-03; the default implementation of hashCode was being + * invoked. Object.hashCode is a source of random numbers and has no place in a + * deterministic program. + */ +public class TypeInferenceTest extends WalaTestCase { + + private static final ClassLoader MY_CLASSLOADER = TypeInferenceTest.class.getClassLoader(); + + private static AnalysisScope scope; + + private static ClassHierarchy cha; + + private static AnalysisOptions options; + + private static AnalysisCache cache; + + public static void main(String[] args) { + justThisTest(TypeInferenceTest.class); + } + + @BeforeClass + public static void beforeClass() throws Exception { + + scope = AnalysisScopeReader.readJavaScope(TestConstants.WALA_TESTDATA, (new FileProvider()).getFile("J2SEClassHierarchyExclusions.txt"), MY_CLASSLOADER); + + options = new AnalysisOptions(scope, null); + cache = new AnalysisCache(); + ClassLoaderFactory factory = new ClassLoaderFactoryImpl(scope.getExclusions()); + + try { + cha = ClassHierarchy.make(scope, factory); + } catch (ClassHierarchyException e) { + throw new Exception(); + } + } + + @AfterClass + public static void afterClass() throws Exception { + Warnings.clear(); + scope = null; + cha = null; + options = null; + cache = null; + } + + @Test public void test1() { + MethodReference method = scope.findMethod(AnalysisScope.APPLICATION, "LtypeInference/TI", Atom.findOrCreateUnicodeAtom("foo"), + new ImmutableByteArray(UTF8Convert.toUTF8("()V"))); + Assert.assertNotNull("method not found", method); + IMethod imethod = cha.resolveMethod(method); + Assert.assertNotNull("imethod not found", imethod); + IR ir = cache.getIRFactory().makeIR(imethod, Everywhere.EVERYWHERE, options.getSSAOptions()); + System.out.println(ir); + + TypeInference ti = TypeInference.make(ir, false); + for (int i = 1; i <= ir.getSymbolTable().getMaxValueNumber(); i++) { + System.err.println(i + " " + ti.getType(i)); + } + } + + @Test public void test2() { + MethodReference method = scope.findMethod(AnalysisScope.APPLICATION, "LtypeInference/TI", Atom.findOrCreateUnicodeAtom("bar"), + new ImmutableByteArray(UTF8Convert.toUTF8("(I)V"))); + Assert.assertNotNull("method not found", method); + IMethod imethod = cha.resolveMethod(method); + Assert.assertNotNull("imethod not found", imethod); + IR ir = cache.getIRFactory().makeIR(imethod, Everywhere.EVERYWHERE, options.getSSAOptions()); + System.out.println(ir); + + TypeInference ti = TypeInference.make(ir, true); + Assert.assertNotNull("null type abstraction for parameter", ti.getType(2)); + } + + @Test public void test3() { + MethodReference method = scope.findMethod(AnalysisScope.APPLICATION, "LtypeInference/TI", Atom.findOrCreateUnicodeAtom("inferInt"), + new ImmutableByteArray(UTF8Convert.toUTF8("()V"))); + Assert.assertNotNull("method not found", method); + IMethod imethod = cha.resolveMethod(method); + Assert.assertNotNull("imethod not found", imethod); + IR ir = cache.getIRFactory().makeIR(imethod, Everywhere.EVERYWHERE, options.getSSAOptions()); + System.out.println(ir); + + TypeInference ti = TypeInference.make(ir, true); + TypeAbstraction type = ti.getType(7); + Assert.assertNotNull("null type abstraction", type); + Assert.assertTrue("inferred wrong type", type.toString().equals("int")); + } + + @Test public void test4() { + MethodReference method = scope.findMethod(AnalysisScope.APPLICATION, "LtypeInference/TI", Atom.findOrCreateUnicodeAtom("useCast"), + new ImmutableByteArray(UTF8Convert.toUTF8("(Ljava/lang/Object;)V"))); + Assert.assertNotNull("method not found", method); + IMethod imethod = cha.resolveMethod(method); + Assert.assertNotNull("imethod not found", imethod); + IR ir = cache.getIRFactory().makeIR(imethod, Everywhere.EVERYWHERE, options.getSSAOptions()); + System.out.println(ir); + + TypeInference ti = TypeInference.make(ir, false); + TypeAbstraction type = ti.getType(4); + Assert.assertNotNull("null type abstraction", type); + Assert.assertTrue("inferred wrong type " + type, type instanceof ConeType && ((ConeType)type).getTypeReference().getName().toString().equals("Ljava/lang/String")); + } + + +} diff --git a/com.ibm.wala.core.tests/src/com/ibm/wala/core/tests/util/TestConstants.java b/com.ibm.wala.core.tests/src/com/ibm/wala/core/tests/util/TestConstants.java index 9b693ab27..c0e32077d 100644 --- a/com.ibm.wala.core.tests/src/com/ibm/wala/core/tests/util/TestConstants.java +++ b/com.ibm.wala.core.tests/src/com/ibm/wala/core/tests/util/TestConstants.java @@ -1,140 +1,140 @@ -/******************************************************************************* - * 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 com.ibm.wala.core.tests.util; - -public interface TestConstants { - - public final static String WALA_TESTDATA = "wala.testdata.txt"; - - public static final String CLASSCONSTANT_MAIN = "LclassConstant/ClassConstant"; - - public static final String PI_TEST_MAIN = "Lpi/PiNodeCallGraphTestCase"; - - public static final String RECURSE_MAIN = "Lrecurse/NList"; - - public final static String HELLO = "hello.txt"; - - public final static String HELLO_MAIN = "Lhello/Hello"; - - public final static String BCEL = "bcel.txt"; - - public final static String BCEL_VERIFIER_MAIN = "Lorg/apache/bcel/verifier/Verifier"; - - public final static String JLEX = "JLex.txt"; - - public final static String JLEX_MAIN = "LJLex/Main"; - - public final static String JAVA_CUP = "java_cup.txt"; - - public final static String JAVA_CUP_MAIN = "Ljava_cup/Main"; - - public final static String MULTI_DIM_MAIN = "LmultiDim/TestMultiDim"; - - public final static String ARRAY_ALIAS_MAIN = "LarrayAlias/TestArrayAlias"; - - public final static String ZERO_LENGTH_ARRAY_MAIN = "LarrayAlias/TestZeroLengthArray"; - - public final static String REFLECT1_MAIN = "Lreflection/Reflect1"; - - public final static String REFLECT2_MAIN = "Lreflection/Reflect2"; - - public final static String REFLECT3_MAIN = "Lreflection/Reflect3"; - - public final static String REFLECT4_MAIN = "Lreflection/Reflect4"; - - public final static String REFLECT5_MAIN = "Lreflection/Reflect5"; - - public final static String REFLECT6_MAIN = "Lreflection/Reflect6"; - - public final static String REFLECT7_MAIN = "Lreflection/Reflect7"; - - public final static String REFLECT8_MAIN = "Lreflection/Reflect8"; - - public final static String REFLECT9_MAIN = "Lreflection/Reflect9"; - - public final static String REFLECT10_MAIN = "Lreflection/Reflect10"; - - public final static String REFLECT11_MAIN = "Lreflection/Reflect11"; - - public final static String REFLECT12_MAIN = "Lreflection/Reflect12"; - - public final static String REFLECT13_MAIN = "Lreflection/Reflect13"; - - public final static String REFLECT14_MAIN = "Lreflection/Reflect14"; - - public final static String REFLECT15_MAIN = "Lreflection/Reflect15"; - - public final static String REFLECT16_MAIN = "Lreflection/Reflect16"; - - public final static String REFLECT17_MAIN = "Lreflection/Reflect17"; - - public final static String REFLECT18_MAIN = "Lreflection/Reflect18"; - - public final static String REFLECT19_MAIN = "Lreflection/Reflect19"; - - public final static String REFLECT20_MAIN = "Lreflection/Reflect20"; - - public final static String REFLECT21_MAIN = "Lreflection/Reflect21"; - - public final static String REFLECT22_MAIN = "Lreflection/Reflect22"; - - public final static String REFLECT23_MAIN = "Lreflection/Reflect23"; - - public final static String SLICE1_MAIN = "Lslice/Slice1"; - - public final static String SLICE2_MAIN = "Lslice/Slice2"; - - public final static String SLICE3_MAIN = "Lslice/Slice3"; - - public final static String SLICE4_MAIN = "Lslice/Slice4"; - - public final static String SLICE5_MAIN = "Lslice/Slice5"; - - public final static String SLICE7_MAIN = "Lslice/Slice7"; - - public final static String SLICE8_MAIN = "Lslice/Slice8"; - - - public final static String SLICE_TESTCD1 = "Lslice/TestCD1"; - - public final static String SLICE_TESTCD2 = "Lslice/TestCD2"; - - public final static String SLICE_TESTCD3 = "Lslice/TestCD3"; - - public final static String SLICE_TESTCD4 = "Lslice/TestCD4"; - - public final static String SLICE_TESTCD5 = "Lslice/TestCD5"; - - public final static String SLICE_TESTCD6 = "Lslice/TestCD6"; - - public final static String SLICE_TESTID = "Lslice/TestId"; - - public final static String SLICE_TESTARRAYS = "Lslice/TestArrays"; - - public final static String SLICE_TESTFIELDS = "Lslice/TestFields"; - - public final static String SLICE_TESTGLOBAL = "Lslice/TestGlobal"; - - public final static String SLICE_TESTMULTITARGET = "Lslice/TestMultiTarget"; - - public final static String SLICE_TESTRECURSION = "Lslice/TestRecursion"; - - public final static String SLICE_TEST_PRIM_GETTER_SETTER = "Lslice/TestPrimGetterSetter"; - - public final static String SLICE_TESTTHIN1 = "Lslice/TestThin1"; - - public final static String SLICE_TESTTHROWCATCH = "Lslice/TestThrowCatch"; - - public final static String SLICE_TESTMESSAGEFORMAT = "Lslice/TestMessageFormat"; - - public final static String SLICE_TESTINETADDR = "Lslice/TestInetAddr"; - -} +/******************************************************************************* + * 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 com.ibm.wala.core.tests.util; + +public interface TestConstants { + + public final static String WALA_TESTDATA = "wala.testdata.txt"; + + public static final String CLASSCONSTANT_MAIN = "LclassConstant/ClassConstant"; + + public static final String PI_TEST_MAIN = "Lpi/PiNodeCallGraphTestCase"; + + public static final String RECURSE_MAIN = "Lrecurse/NList"; + + public final static String HELLO = "hello.txt"; + + public final static String HELLO_MAIN = "Lhello/Hello"; + + public final static String BCEL = "bcel.txt"; + + public final static String BCEL_VERIFIER_MAIN = "Lorg/apache/bcel/verifier/Verifier"; + + public final static String JLEX = "JLex.txt"; + + public final static String JLEX_MAIN = "LJLex/Main"; + + public final static String JAVA_CUP = "java_cup.txt"; + + public final static String JAVA_CUP_MAIN = "Ljava_cup/Main"; + + public final static String MULTI_DIM_MAIN = "LmultiDim/TestMultiDim"; + + public final static String ARRAY_ALIAS_MAIN = "LarrayAlias/TestArrayAlias"; + + public final static String ZERO_LENGTH_ARRAY_MAIN = "LarrayAlias/TestZeroLengthArray"; + + public final static String REFLECT1_MAIN = "Lreflection/Reflect1"; + + public final static String REFLECT2_MAIN = "Lreflection/Reflect2"; + + public final static String REFLECT3_MAIN = "Lreflection/Reflect3"; + + public final static String REFLECT4_MAIN = "Lreflection/Reflect4"; + + public final static String REFLECT5_MAIN = "Lreflection/Reflect5"; + + public final static String REFLECT6_MAIN = "Lreflection/Reflect6"; + + public final static String REFLECT7_MAIN = "Lreflection/Reflect7"; + + public final static String REFLECT8_MAIN = "Lreflection/Reflect8"; + + public final static String REFLECT9_MAIN = "Lreflection/Reflect9"; + + public final static String REFLECT10_MAIN = "Lreflection/Reflect10"; + + public final static String REFLECT11_MAIN = "Lreflection/Reflect11"; + + public final static String REFLECT12_MAIN = "Lreflection/Reflect12"; + + public final static String REFLECT13_MAIN = "Lreflection/Reflect13"; + + public final static String REFLECT14_MAIN = "Lreflection/Reflect14"; + + public final static String REFLECT15_MAIN = "Lreflection/Reflect15"; + + public final static String REFLECT16_MAIN = "Lreflection/Reflect16"; + + public final static String REFLECT17_MAIN = "Lreflection/Reflect17"; + + public final static String REFLECT18_MAIN = "Lreflection/Reflect18"; + + public final static String REFLECT19_MAIN = "Lreflection/Reflect19"; + + public final static String REFLECT20_MAIN = "Lreflection/Reflect20"; + + public final static String REFLECT21_MAIN = "Lreflection/Reflect21"; + + public final static String REFLECT22_MAIN = "Lreflection/Reflect22"; + + public final static String REFLECT23_MAIN = "Lreflection/Reflect23"; + + public final static String SLICE1_MAIN = "Lslice/Slice1"; + + public final static String SLICE2_MAIN = "Lslice/Slice2"; + + public final static String SLICE3_MAIN = "Lslice/Slice3"; + + public final static String SLICE4_MAIN = "Lslice/Slice4"; + + public final static String SLICE5_MAIN = "Lslice/Slice5"; + + public final static String SLICE7_MAIN = "Lslice/Slice7"; + + public final static String SLICE8_MAIN = "Lslice/Slice8"; + + + public final static String SLICE_TESTCD1 = "Lslice/TestCD1"; + + public final static String SLICE_TESTCD2 = "Lslice/TestCD2"; + + public final static String SLICE_TESTCD3 = "Lslice/TestCD3"; + + public final static String SLICE_TESTCD4 = "Lslice/TestCD4"; + + public final static String SLICE_TESTCD5 = "Lslice/TestCD5"; + + public final static String SLICE_TESTCD6 = "Lslice/TestCD6"; + + public final static String SLICE_TESTID = "Lslice/TestId"; + + public final static String SLICE_TESTARRAYS = "Lslice/TestArrays"; + + public final static String SLICE_TESTFIELDS = "Lslice/TestFields"; + + public final static String SLICE_TESTGLOBAL = "Lslice/TestGlobal"; + + public final static String SLICE_TESTMULTITARGET = "Lslice/TestMultiTarget"; + + public final static String SLICE_TESTRECURSION = "Lslice/TestRecursion"; + + public final static String SLICE_TEST_PRIM_GETTER_SETTER = "Lslice/TestPrimGetterSetter"; + + public final static String SLICE_TESTTHIN1 = "Lslice/TestThin1"; + + public final static String SLICE_TESTTHROWCATCH = "Lslice/TestThrowCatch"; + + public final static String SLICE_TESTMESSAGEFORMAT = "Lslice/TestMessageFormat"; + + public final static String SLICE_TESTINETADDR = "Lslice/TestInetAddr"; + +} diff --git a/com.ibm.wala.core.tests/src/com/ibm/wala/core/tests/util/WalaTestCase.java b/com.ibm.wala.core.tests/src/com/ibm/wala/core/tests/util/WalaTestCase.java index 4f57ff02e..3120a3e4b 100644 --- a/com.ibm.wala.core.tests/src/com/ibm/wala/core/tests/util/WalaTestCase.java +++ b/com.ibm.wala.core.tests/src/com/ibm/wala/core/tests/util/WalaTestCase.java @@ -1,75 +1,75 @@ -/******************************************************************************* - * 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.core.tests.util; - -import org.junit.After; -import org.junit.Assert; -import org.junit.Before; -import org.junit.runner.JUnitCore; - -import com.ibm.wala.util.heapTrace.HeapTracer; -import com.ibm.wala.util.warnings.Warnings; - -/** - * Simple extension to JUnit test case. - */ -public abstract class WalaTestCase { - - final private static boolean ANALYZE_LEAKS = false; - - public static boolean useShortProfile() { - String profile = System.getProperty("com.ibm.wala.junit.profile", "long"); - if (profile.equals("short")) { - return true; - } else { - return false; - } - } - - /* - * @see junit.framework.TestCase#setUp() - */ - @Before - public void setUp() throws Exception { - } - - /* - * @see junit.framework.TestCase#tearDown() - */ - @After - public void tearDown() throws Exception { - Warnings.clear(); - if (ANALYZE_LEAKS) { - HeapTracer.analyzeLeaks(); - } - } - - /** - * Utility function: each DetoxTestCase subclass can have a main() method that calls this, to create a test suite consisting of - * just this test. Useful when investigating a single failing test. - */ - protected static void justThisTest(Class testClass) { - JUnitCore.runClasses(testClass); - } - - protected static void assertBound(String tag, double quantity, double bound) { - String msg = tag + ", quantity: " + quantity + ", bound:" + bound; - System.err.println(msg); - Assert.assertTrue(msg, quantity <= bound); - } - - protected static void assertBound(String tag, int quantity, int bound) { - String msg = tag + ", quantity: " + quantity + ", bound:" + bound; - System.err.println(msg); - Assert.assertTrue(msg, quantity <= bound); - } - -} +/******************************************************************************* + * 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.core.tests.util; + +import org.junit.After; +import org.junit.Assert; +import org.junit.Before; +import org.junit.runner.JUnitCore; + +import com.ibm.wala.util.heapTrace.HeapTracer; +import com.ibm.wala.util.warnings.Warnings; + +/** + * Simple extension to JUnit test case. + */ +public abstract class WalaTestCase { + + final private static boolean ANALYZE_LEAKS = false; + + public static boolean useShortProfile() { + String profile = System.getProperty("com.ibm.wala.junit.profile", "long"); + if (profile.equals("short")) { + return true; + } else { + return false; + } + } + + /* + * @see junit.framework.TestCase#setUp() + */ + @Before + public void setUp() throws Exception { + } + + /* + * @see junit.framework.TestCase#tearDown() + */ + @After + public void tearDown() throws Exception { + Warnings.clear(); + if (ANALYZE_LEAKS) { + HeapTracer.analyzeLeaks(); + } + } + + /** + * Utility function: each DetoxTestCase subclass can have a main() method that calls this, to create a test suite consisting of + * just this test. Useful when investigating a single failing test. + */ + protected static void justThisTest(Class testClass) { + JUnitCore.runClasses(testClass); + } + + protected static void assertBound(String tag, double quantity, double bound) { + String msg = tag + ", quantity: " + quantity + ", bound:" + bound; + System.err.println(msg); + Assert.assertTrue(msg, quantity <= bound); + } + + protected static void assertBound(String tag, int quantity, int bound) { + String msg = tag + ", quantity: " + quantity + ", bound:" + bound; + System.err.println(msg); + Assert.assertTrue(msg, quantity <= bound); + } + +} diff --git a/com.ibm.wala.core.tests/src/com/ibm/wala/demandpa/driver/CompareToZeroOneCFADriver.java b/com.ibm.wala.core.tests/src/com/ibm/wala/demandpa/driver/CompareToZeroOneCFADriver.java index e44993ae9..efc6a0113 100644 --- a/com.ibm.wala.core.tests/src/com/ibm/wala/demandpa/driver/CompareToZeroOneCFADriver.java +++ b/com.ibm.wala.core.tests/src/com/ibm/wala/demandpa/driver/CompareToZeroOneCFADriver.java @@ -1,227 +1,227 @@ -/** - * Refinement Analysis Tools is Copyright (c) 2007 The Regents of the - * University of California (Regents). Provided that this notice and - * the following two paragraphs are included in any distribution of - * Refinement Analysis Tools or its derivative work, Regents agrees - * not to assert any of Regents' copyright rights in Refinement - * Analysis Tools against recipient for recipient's reproduction, - * preparation of derivative works, public display, public - * performance, distribution or sublicensing of Refinement Analysis - * Tools and derivative works, in source code and object code form. - * This agreement not to assert does not confer, by implication, - * estoppel, or otherwise any license or rights in any intellectual - * property of Regents, including, but not limited to, any patents - * of Regents or Regents' employees. - * - * IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, - * INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, - * INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE - * AND ITS DOCUMENTATION, EVEN IF REGENTS HAS BEEN ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE AND FURTHER DISCLAIMS ANY STATUTORY - * WARRANTY OF NON-INFRINGEMENT. THE SOFTWARE AND ACCOMPANYING - * DOCUMENTATION, IF ANY, PROVIDED HEREUNDER IS PROVIDED "AS - * IS". REGENTS HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, - * UPDATES, ENHANCEMENTS, OR MODIFICATIONS. - */ -package com.ibm.wala.demandpa.driver; - -import java.io.File; -import java.io.IOException; -import java.util.Collection; -import java.util.Iterator; - -import com.ibm.wala.analysis.reflection.InstanceKeyWithNode; -import com.ibm.wala.analysis.typeInference.TypeAbstraction; -import com.ibm.wala.analysis.typeInference.TypeInference; -import com.ibm.wala.core.tests.callGraph.CallGraphTestUtil; -import com.ibm.wala.core.tests.demandpa.TestInfo; -import com.ibm.wala.demandpa.alg.DemandRefinementPointsTo; -import com.ibm.wala.demandpa.alg.IDemandPointerAnalysis; -import com.ibm.wala.demandpa.alg.statemachine.DummyStateMachine; -import com.ibm.wala.demandpa.flowgraph.IFlowLabel; -import com.ibm.wala.demandpa.util.CallGraphMapUtil; -import com.ibm.wala.demandpa.util.MemoryAccessMap; -import com.ibm.wala.demandpa.util.SimpleMemoryAccessMap; -import com.ibm.wala.ipa.callgraph.AnalysisCache; -import com.ibm.wala.ipa.callgraph.AnalysisOptions; -import com.ibm.wala.ipa.callgraph.AnalysisScope; -import com.ibm.wala.ipa.callgraph.CGNode; -import com.ibm.wala.ipa.callgraph.CallGraph; -import com.ibm.wala.ipa.callgraph.CallGraphBuilder; -import com.ibm.wala.ipa.callgraph.Entrypoint; -import com.ibm.wala.ipa.callgraph.impl.Util; -import com.ibm.wala.ipa.callgraph.propagation.HeapModel; -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.SSAPropagationCallGraphBuilder; -import com.ibm.wala.ipa.cha.ClassHierarchy; -import com.ibm.wala.ipa.cha.ClassHierarchyException; -import com.ibm.wala.ssa.IR; -import com.ibm.wala.types.MethodReference; -import com.ibm.wala.util.CancelException; -import com.ibm.wala.util.config.AnalysisScopeReader; -import com.ibm.wala.util.debug.Assertions; -import com.ibm.wala.util.intset.OrdinalSet; - -/** - * Driver that tests analysis results against ZeroOneCFA analysis. - * - * @author Manu Sridharan - * - */ -public class CompareToZeroOneCFADriver { - - /** - * @param args - */ - public static void main(String[] args) { - // for (String testCase : TestInfo.ALL_TEST_CASES) { - // runUnitTestCase(testCase); - // } - // runUnitTestCase(TestInfo.TEST_PRIMITIVES); - // runApplication("/home/manu/research/DOMO/tests/JLex.jar"); - } - - @SuppressWarnings("unused") - private static void runUnitTestCase(String mainClass) throws IllegalArgumentException, CancelException, IOException { - System.err.println("=======---------------============="); - System.err.println(("ANALYZING " + mainClass + "\n\n")); - // describe the "scope", what is the program we're analyzing - AnalysisScope scope = CallGraphTestUtil.makeJ2SEAnalysisScope(TestInfo.SCOPE_FILE, CallGraphTestUtil.REGRESSION_EXCLUSIONS); - Object warnings = new Object(); - - // build a type hierarchy - ClassHierarchy cha = null; - try { - cha = ClassHierarchy.make(scope); - } catch (ClassHierarchyException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - - // set up call graph construction options; mainly what should be considered - // entrypoints? - Iterable entrypoints = com.ibm.wala.ipa.callgraph.impl.Util.makeMainEntrypoints(scope, cha, mainClass); - AnalysisOptions options = CallGraphTestUtil.makeAnalysisOptions(scope, entrypoints); - - // run existing pointer analysis - doTests(scope, cha, options); - System.err.println("ALL FINE"); - } - - @SuppressWarnings("unused") - private static void runApplication(String appJar) throws IllegalArgumentException, CancelException, IOException { - System.err.println("=======---------------============="); - System.err.println(("ANALYZING " + appJar + "\n\n")); - - AnalysisScope scope = AnalysisScopeReader.makeJavaBinaryAnalysisScope(appJar, new File(CallGraphTestUtil.REGRESSION_EXCLUSIONS)); - - // TODO: return the warning set (need a CAPA type) - // invoke DOMO to build a DOMO class hierarchy object - Object warnings = new Object(); - ClassHierarchy cha = null; - try { - cha = ClassHierarchy.make(scope); - } catch (ClassHierarchyException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - - Iterable entrypoints = com.ibm.wala.ipa.callgraph.impl.Util.makeMainEntrypoints(scope, cha); - AnalysisOptions options = new AnalysisOptions(scope, entrypoints); - doTests(scope, cha, options); - System.err.println("ALL FINE"); - } - - private static void doTests(AnalysisScope scope, final ClassHierarchy cha, AnalysisOptions options) throws IllegalArgumentException, CancelException { - final SSAPropagationCallGraphBuilder builder = Util.makeVanillaZeroOneCFABuilder(options, new AnalysisCache(), cha, scope); - final CallGraph oldCG = builder.makeCallGraph(options,null); - final PointerAnalysis pa = builder.getPointerAnalysis(); - - // now, run our analysis - // build an RTA call graph - CallGraphBuilder rtaBuilder = Util.makeRTABuilder(options, new AnalysisCache(), cha, scope); - final CallGraph cg = rtaBuilder.makeCallGraph(options, null); - // System.err.println(cg.toString()); - - MemoryAccessMap fam = new SimpleMemoryAccessMap(cg, rtaBuilder.getPointerAnalysis().getHeapModel(), false); - - final IDemandPointerAnalysis dmp = makeDemandPointerAnalysis(options, cha, scope, cg, fam); - - final class Helper { - void checkPointersInMethod(CGNode node) { - // TODO remove this hack - if (node.getMethod().getReference().toString().indexOf("clone()Ljava/lang/Object;") != -1) { - System.err.println(("SKIPPING " + node)); - return; - } - CGNode oldNode = CallGraphMapUtil.mapCGNode(node, cg, oldCG); - if (oldNode == null) { - return; - } - System.err.println(("METHOD " + node)); - IR ir = node.getIR(); - TypeInference ti = TypeInference.make(ir, false); - for (int i = 1; i <= ir.getSymbolTable().getMaxValueNumber(); i++) { - TypeAbstraction t = ti.getType(i); - if (t != null) { - final HeapModel heapModel = dmp.getHeapModel(); - LocalPointerKey pk = (LocalPointerKey) heapModel.getPointerKeyForLocal(node, i); - LocalPointerKey oldPk = (LocalPointerKey) CallGraphMapUtil.mapPointerKey(pk, cg, oldCG, heapModel); - Collection p2set = dmp.getPointsTo(pk); - OrdinalSet otherP2Set = pa.getPointsToSet(oldPk); - System.err.println(("OLD POINTS-TO " + otherP2Set)); - for (InstanceKey key : otherP2Set) { - if (knownBug(key)) { - continue; - } - InstanceKey newKey = CallGraphMapUtil.mapInstKey(key, oldCG, cg, heapModel); - if (!p2set.contains(newKey)) { - System.err.println("BADNESS"); - System.err.println(("pointer key " + pk)); - System.err.println(("missing " + newKey)); - Assertions.UNREACHABLE(); - } - } - } - } - } - - } - Helper h = new Helper(); - for (Iterator nodeIter = cg.iterator(); nodeIter.hasNext();) { - CGNode node = nodeIter.next(); - h.checkPointersInMethod(node); - } - } - - private static boolean knownBug(InstanceKey key) { - // if (key instanceof MultiNewArrayAllocationSiteKey) { - // return true; - // } - if (key instanceof InstanceKeyWithNode) { - CGNode node = ((InstanceKeyWithNode) key).getNode(); - MethodReference methodRef = node.getMethod().getReference(); - if (methodRef.toString().equals("< Primordial, Ljava/lang/Object, clone()Ljava/lang/Object; >")) { - return true; - } - } - return false; - } - - private static IDemandPointerAnalysis makeDemandPointerAnalysis(AnalysisOptions options, ClassHierarchy cha, AnalysisScope scope, - CallGraph cg, MemoryAccessMap fam) { - SSAPropagationCallGraphBuilder builder = Util.makeVanillaZeroOneCFABuilder(options, new AnalysisCache(), cha, scope); - // return new TestNewGraphPointsTo(cg, builder, fam, cha, warnings); - DemandRefinementPointsTo fullDemandPointsTo = DemandRefinementPointsTo.makeWithDefaultFlowGraph(cg, builder, fam, cha, options, new DummyStateMachine.Factory()); - // fullDemandPointsTo.setOnTheFly(true); - // fullDemandPointsTo.setRefineFields(true); - return fullDemandPointsTo; - } - -} +/** + * Refinement Analysis Tools is Copyright (c) 2007 The Regents of the + * University of California (Regents). Provided that this notice and + * the following two paragraphs are included in any distribution of + * Refinement Analysis Tools or its derivative work, Regents agrees + * not to assert any of Regents' copyright rights in Refinement + * Analysis Tools against recipient for recipient's reproduction, + * preparation of derivative works, public display, public + * performance, distribution or sublicensing of Refinement Analysis + * Tools and derivative works, in source code and object code form. + * This agreement not to assert does not confer, by implication, + * estoppel, or otherwise any license or rights in any intellectual + * property of Regents, including, but not limited to, any patents + * of Regents or Regents' employees. + * + * IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, + * INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, + * INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE + * AND ITS DOCUMENTATION, EVEN IF REGENTS HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE AND FURTHER DISCLAIMS ANY STATUTORY + * WARRANTY OF NON-INFRINGEMENT. THE SOFTWARE AND ACCOMPANYING + * DOCUMENTATION, IF ANY, PROVIDED HEREUNDER IS PROVIDED "AS + * IS". REGENTS HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, + * UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + */ +package com.ibm.wala.demandpa.driver; + +import java.io.File; +import java.io.IOException; +import java.util.Collection; +import java.util.Iterator; + +import com.ibm.wala.analysis.reflection.InstanceKeyWithNode; +import com.ibm.wala.analysis.typeInference.TypeAbstraction; +import com.ibm.wala.analysis.typeInference.TypeInference; +import com.ibm.wala.core.tests.callGraph.CallGraphTestUtil; +import com.ibm.wala.core.tests.demandpa.TestInfo; +import com.ibm.wala.demandpa.alg.DemandRefinementPointsTo; +import com.ibm.wala.demandpa.alg.IDemandPointerAnalysis; +import com.ibm.wala.demandpa.alg.statemachine.DummyStateMachine; +import com.ibm.wala.demandpa.flowgraph.IFlowLabel; +import com.ibm.wala.demandpa.util.CallGraphMapUtil; +import com.ibm.wala.demandpa.util.MemoryAccessMap; +import com.ibm.wala.demandpa.util.SimpleMemoryAccessMap; +import com.ibm.wala.ipa.callgraph.AnalysisCache; +import com.ibm.wala.ipa.callgraph.AnalysisOptions; +import com.ibm.wala.ipa.callgraph.AnalysisScope; +import com.ibm.wala.ipa.callgraph.CGNode; +import com.ibm.wala.ipa.callgraph.CallGraph; +import com.ibm.wala.ipa.callgraph.CallGraphBuilder; +import com.ibm.wala.ipa.callgraph.Entrypoint; +import com.ibm.wala.ipa.callgraph.impl.Util; +import com.ibm.wala.ipa.callgraph.propagation.HeapModel; +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.SSAPropagationCallGraphBuilder; +import com.ibm.wala.ipa.cha.ClassHierarchy; +import com.ibm.wala.ipa.cha.ClassHierarchyException; +import com.ibm.wala.ssa.IR; +import com.ibm.wala.types.MethodReference; +import com.ibm.wala.util.CancelException; +import com.ibm.wala.util.config.AnalysisScopeReader; +import com.ibm.wala.util.debug.Assertions; +import com.ibm.wala.util.intset.OrdinalSet; + +/** + * Driver that tests analysis results against ZeroOneCFA analysis. + * + * @author Manu Sridharan + * + */ +public class CompareToZeroOneCFADriver { + + /** + * @param args + */ + public static void main(String[] args) { + // for (String testCase : TestInfo.ALL_TEST_CASES) { + // runUnitTestCase(testCase); + // } + // runUnitTestCase(TestInfo.TEST_PRIMITIVES); + // runApplication("/home/manu/research/DOMO/tests/JLex.jar"); + } + + @SuppressWarnings("unused") + private static void runUnitTestCase(String mainClass) throws IllegalArgumentException, CancelException, IOException { + System.err.println("=======---------------============="); + System.err.println(("ANALYZING " + mainClass + "\n\n")); + // describe the "scope", what is the program we're analyzing + AnalysisScope scope = CallGraphTestUtil.makeJ2SEAnalysisScope(TestInfo.SCOPE_FILE, CallGraphTestUtil.REGRESSION_EXCLUSIONS); + Object warnings = new Object(); + + // build a type hierarchy + ClassHierarchy cha = null; + try { + cha = ClassHierarchy.make(scope); + } catch (ClassHierarchyException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + + // set up call graph construction options; mainly what should be considered + // entrypoints? + Iterable entrypoints = com.ibm.wala.ipa.callgraph.impl.Util.makeMainEntrypoints(scope, cha, mainClass); + AnalysisOptions options = CallGraphTestUtil.makeAnalysisOptions(scope, entrypoints); + + // run existing pointer analysis + doTests(scope, cha, options); + System.err.println("ALL FINE"); + } + + @SuppressWarnings("unused") + private static void runApplication(String appJar) throws IllegalArgumentException, CancelException, IOException { + System.err.println("=======---------------============="); + System.err.println(("ANALYZING " + appJar + "\n\n")); + + AnalysisScope scope = AnalysisScopeReader.makeJavaBinaryAnalysisScope(appJar, new File(CallGraphTestUtil.REGRESSION_EXCLUSIONS)); + + // TODO: return the warning set (need a CAPA type) + // invoke DOMO to build a DOMO class hierarchy object + Object warnings = new Object(); + ClassHierarchy cha = null; + try { + cha = ClassHierarchy.make(scope); + } catch (ClassHierarchyException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + + Iterable entrypoints = com.ibm.wala.ipa.callgraph.impl.Util.makeMainEntrypoints(scope, cha); + AnalysisOptions options = new AnalysisOptions(scope, entrypoints); + doTests(scope, cha, options); + System.err.println("ALL FINE"); + } + + private static void doTests(AnalysisScope scope, final ClassHierarchy cha, AnalysisOptions options) throws IllegalArgumentException, CancelException { + final SSAPropagationCallGraphBuilder builder = Util.makeVanillaZeroOneCFABuilder(options, new AnalysisCache(), cha, scope); + final CallGraph oldCG = builder.makeCallGraph(options,null); + final PointerAnalysis pa = builder.getPointerAnalysis(); + + // now, run our analysis + // build an RTA call graph + CallGraphBuilder rtaBuilder = Util.makeRTABuilder(options, new AnalysisCache(), cha, scope); + final CallGraph cg = rtaBuilder.makeCallGraph(options, null); + // System.err.println(cg.toString()); + + MemoryAccessMap fam = new SimpleMemoryAccessMap(cg, rtaBuilder.getPointerAnalysis().getHeapModel(), false); + + final IDemandPointerAnalysis dmp = makeDemandPointerAnalysis(options, cha, scope, cg, fam); + + final class Helper { + void checkPointersInMethod(CGNode node) { + // TODO remove this hack + if (node.getMethod().getReference().toString().indexOf("clone()Ljava/lang/Object;") != -1) { + System.err.println(("SKIPPING " + node)); + return; + } + CGNode oldNode = CallGraphMapUtil.mapCGNode(node, cg, oldCG); + if (oldNode == null) { + return; + } + System.err.println(("METHOD " + node)); + IR ir = node.getIR(); + TypeInference ti = TypeInference.make(ir, false); + for (int i = 1; i <= ir.getSymbolTable().getMaxValueNumber(); i++) { + TypeAbstraction t = ti.getType(i); + if (t != null) { + final HeapModel heapModel = dmp.getHeapModel(); + LocalPointerKey pk = (LocalPointerKey) heapModel.getPointerKeyForLocal(node, i); + LocalPointerKey oldPk = (LocalPointerKey) CallGraphMapUtil.mapPointerKey(pk, cg, oldCG, heapModel); + Collection p2set = dmp.getPointsTo(pk); + OrdinalSet otherP2Set = pa.getPointsToSet(oldPk); + System.err.println(("OLD POINTS-TO " + otherP2Set)); + for (InstanceKey key : otherP2Set) { + if (knownBug(key)) { + continue; + } + InstanceKey newKey = CallGraphMapUtil.mapInstKey(key, oldCG, cg, heapModel); + if (!p2set.contains(newKey)) { + System.err.println("BADNESS"); + System.err.println(("pointer key " + pk)); + System.err.println(("missing " + newKey)); + Assertions.UNREACHABLE(); + } + } + } + } + } + + } + Helper h = new Helper(); + for (Iterator nodeIter = cg.iterator(); nodeIter.hasNext();) { + CGNode node = nodeIter.next(); + h.checkPointersInMethod(node); + } + } + + private static boolean knownBug(InstanceKey key) { + // if (key instanceof MultiNewArrayAllocationSiteKey) { + // return true; + // } + if (key instanceof InstanceKeyWithNode) { + CGNode node = ((InstanceKeyWithNode) key).getNode(); + MethodReference methodRef = node.getMethod().getReference(); + if (methodRef.toString().equals("< Primordial, Ljava/lang/Object, clone()Ljava/lang/Object; >")) { + return true; + } + } + return false; + } + + private static IDemandPointerAnalysis makeDemandPointerAnalysis(AnalysisOptions options, ClassHierarchy cha, AnalysisScope scope, + CallGraph cg, MemoryAccessMap fam) { + SSAPropagationCallGraphBuilder builder = Util.makeVanillaZeroOneCFABuilder(options, new AnalysisCache(), cha, scope); + // return new TestNewGraphPointsTo(cg, builder, fam, cha, warnings); + DemandRefinementPointsTo fullDemandPointsTo = DemandRefinementPointsTo.makeWithDefaultFlowGraph(cg, builder, fam, cha, options, new DummyStateMachine.Factory()); + // fullDemandPointsTo.setOnTheFly(true); + // fullDemandPointsTo.setRefineFields(true); + return fullDemandPointsTo; + } + +} diff --git a/com.ibm.wala.core.tests/src/com/ibm/wala/demandpa/driver/TestAgainstSimpleDriver.java b/com.ibm.wala.core.tests/src/com/ibm/wala/demandpa/driver/TestAgainstSimpleDriver.java index 7b366844b..dfc887096 100644 --- a/com.ibm.wala.core.tests/src/com/ibm/wala/demandpa/driver/TestAgainstSimpleDriver.java +++ b/com.ibm.wala.core.tests/src/com/ibm/wala/demandpa/driver/TestAgainstSimpleDriver.java @@ -1,165 +1,165 @@ -/** - * Refinement Analysis Tools is Copyright (c) 2007 The Regents of the - * University of California (Regents). Provided that this notice and - * the following two paragraphs are included in any distribution of - * Refinement Analysis Tools or its derivative work, Regents agrees - * not to assert any of Regents' copyright rights in Refinement - * Analysis Tools against recipient for recipient's reproduction, - * preparation of derivative works, public display, public - * performance, distribution or sublicensing of Refinement Analysis - * Tools and derivative works, in source code and object code form. - * This agreement not to assert does not confer, by implication, - * estoppel, or otherwise any license or rights in any intellectual - * property of Regents, including, but not limited to, any patents - * of Regents or Regents' employees. - * - * IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, - * INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, - * INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE - * AND ITS DOCUMENTATION, EVEN IF REGENTS HAS BEEN ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE AND FURTHER DISCLAIMS ANY STATUTORY - * WARRANTY OF NON-INFRINGEMENT. THE SOFTWARE AND ACCOMPANYING - * DOCUMENTATION, IF ANY, PROVIDED HEREUNDER IS PROVIDED "AS - * IS". REGENTS HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, - * UPDATES, ENHANCEMENTS, OR MODIFICATIONS. - */ -package com.ibm.wala.demandpa.driver; - -import java.io.IOException; -import java.util.Collection; -import java.util.Iterator; - -import com.ibm.wala.analysis.typeInference.TypeAbstraction; -import com.ibm.wala.analysis.typeInference.TypeInference; -import com.ibm.wala.core.tests.callGraph.CallGraphTestUtil; -import com.ibm.wala.core.tests.demandpa.TestInfo; -import com.ibm.wala.demandpa.alg.DemandRefinementPointsTo; -import com.ibm.wala.demandpa.alg.IDemandPointerAnalysis; -import com.ibm.wala.demandpa.alg.SimpleDemandPointsTo; -import com.ibm.wala.demandpa.alg.refinepolicy.AlwaysRefineCGPolicy; -import com.ibm.wala.demandpa.alg.refinepolicy.AlwaysRefineFieldsPolicy; -import com.ibm.wala.demandpa.alg.refinepolicy.SinglePassRefinementPolicy; -import com.ibm.wala.demandpa.alg.statemachine.DummyStateMachine; -import com.ibm.wala.demandpa.flowgraph.IFlowLabel; -import com.ibm.wala.demandpa.util.MemoryAccessMap; -import com.ibm.wala.demandpa.util.SimpleMemoryAccessMap; -import com.ibm.wala.ipa.callgraph.AnalysisCache; -import com.ibm.wala.ipa.callgraph.AnalysisOptions; -import com.ibm.wala.ipa.callgraph.AnalysisScope; -import com.ibm.wala.ipa.callgraph.CGNode; -import com.ibm.wala.ipa.callgraph.CallGraph; -import com.ibm.wala.ipa.callgraph.CallGraphBuilder; -import com.ibm.wala.ipa.callgraph.Entrypoint; -import com.ibm.wala.ipa.callgraph.impl.Util; -import com.ibm.wala.ipa.callgraph.propagation.InstanceKey; -import com.ibm.wala.ipa.callgraph.propagation.LocalPointerKey; -import com.ibm.wala.ipa.callgraph.propagation.PointerKey; -import com.ibm.wala.ipa.callgraph.propagation.SSAPropagationCallGraphBuilder; -import com.ibm.wala.ipa.cha.ClassHierarchy; -import com.ibm.wala.ipa.cha.ClassHierarchyException; -import com.ibm.wala.ssa.IR; -import com.ibm.wala.util.CancelException; - -/** - * Driver that tests a pointer analysis results against the results of - * {@link SimpleDemandPointsTo}. - * - * @author Manu Sridharan - * - */ -public class TestAgainstSimpleDriver { - - private static final boolean VERBOSE = false; - - public static void main(String[] args) throws IllegalArgumentException, CancelException, IOException { - - // for (String String : ALL_TEST_CASES) { - // runAnalysisForString(String.mainClass, String.scopeFileName); - // } - runAnalysisForTestCase(TestInfo.TEST_ARRAY_SET_ITER); - System.err.println("computed all points-to sets successfully"); - } - - private static void runAnalysisForTestCase(String mainClass) throws IllegalArgumentException, CancelException, IOException { - System.err.println("=======---------------============="); - System.err.println(("ANALYZING " + mainClass + "\n\n")); - // describe the "scope", what is the program we're analyzing - AnalysisScope scope = CallGraphTestUtil.makeJ2SEAnalysisScope(TestInfo.SCOPE_FILE, CallGraphTestUtil.REGRESSION_EXCLUSIONS); - - // build a type hierarchy - ClassHierarchy cha = null; - try { - cha = ClassHierarchy.make(scope); - } catch (ClassHierarchyException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - - // set up call graph construction options; mainly what should be considered - // entrypoints? - Iterable entrypoints = com.ibm.wala.ipa.callgraph.impl.Util.makeMainEntrypoints(scope, cha, mainClass); - AnalysisOptions options = CallGraphTestUtil.makeAnalysisOptions(scope, entrypoints); - - // build an RTA call graph - CallGraphBuilder rtaBuilder = Util.makeRTABuilder(options, new AnalysisCache(), cha, scope); - final CallGraph cg = rtaBuilder.makeCallGraph(options, null); - // System.err.println(cg.toString()); - - MemoryAccessMap fam = new SimpleMemoryAccessMap(cg, rtaBuilder.getPointerAnalysis().getHeapModel(), false); - // System.err.println(fam.toString()); - - IDemandPointerAnalysis dmp = makeDemandPointerAnalysis(options, cha, scope, cg, fam); - - IDemandPointerAnalysis simpleDmp = new SimpleDemandPointsTo(cg, dmp.getHeapModel(), fam, cha, options); - CGNode main = cg.getEntrypointNodes().iterator().next(); - - IR ir = main.getIR(); - TypeInference ti = TypeInference.make(ir, false); - for (int i = 1; i <= ir.getSymbolTable().getMaxValueNumber(); i++) { - TypeAbstraction t = ti.getType(i); - if (t != null) { - LocalPointerKey v = (LocalPointerKey) dmp.getHeapModel().getPointerKeyForLocal(main, i); - Collection p = dmp.getPointsTo(v); - Collection oldP = simpleDmp.getPointsTo(v); - if (!sameContents(p, oldP)) { - System.err.println(("different result for " + v)); - System.err.println(("old " + oldP + "\n\nnew " + p)); - } - printResult(v, p); - } - } - } - - private static boolean sameContents(Collection c1, Collection c2) { - return c1.containsAll(c2) && c2.containsAll(c1); - } - - private static void printResult(PointerKey pk, Collection result) { - if (VERBOSE) { - System.err.println("points-to for " + pk); - if (result.isEmpty()) { - System.err.println(" EMPTY!"); - } - for (Iterator it = result.iterator(); it.hasNext();) { - System.err.println(" " + it.next()); - } - } - } - - private static IDemandPointerAnalysis makeDemandPointerAnalysis(AnalysisOptions options, ClassHierarchy cha, AnalysisScope scope, - CallGraph cg, MemoryAccessMap fam) { - SSAPropagationCallGraphBuilder builder = Util.makeVanillaZeroOneCFABuilder(options, new AnalysisCache(), cha, scope); - // return new TestNewGraphPointsTo(cg, builder, fam, cha, warnings); - DemandRefinementPointsTo fullDemandPointsTo = DemandRefinementPointsTo.makeWithDefaultFlowGraph(cg, builder, fam, cha, options, new DummyStateMachine.Factory()); - // fullDemandPointsTo.setCGRefinePolicy(new AlwaysRefineCGPolicy()); - // fullDemandPointsTo.setFieldRefinePolicy(new AlwaysRefineFieldsPolicy()); - fullDemandPointsTo.setRefinementPolicyFactory(new SinglePassRefinementPolicy.Factory(new AlwaysRefineFieldsPolicy(), - new AlwaysRefineCGPolicy())); - return fullDemandPointsTo; - } - +/** + * Refinement Analysis Tools is Copyright (c) 2007 The Regents of the + * University of California (Regents). Provided that this notice and + * the following two paragraphs are included in any distribution of + * Refinement Analysis Tools or its derivative work, Regents agrees + * not to assert any of Regents' copyright rights in Refinement + * Analysis Tools against recipient for recipient's reproduction, + * preparation of derivative works, public display, public + * performance, distribution or sublicensing of Refinement Analysis + * Tools and derivative works, in source code and object code form. + * This agreement not to assert does not confer, by implication, + * estoppel, or otherwise any license or rights in any intellectual + * property of Regents, including, but not limited to, any patents + * of Regents or Regents' employees. + * + * IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, + * INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, + * INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE + * AND ITS DOCUMENTATION, EVEN IF REGENTS HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE AND FURTHER DISCLAIMS ANY STATUTORY + * WARRANTY OF NON-INFRINGEMENT. THE SOFTWARE AND ACCOMPANYING + * DOCUMENTATION, IF ANY, PROVIDED HEREUNDER IS PROVIDED "AS + * IS". REGENTS HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, + * UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + */ +package com.ibm.wala.demandpa.driver; + +import java.io.IOException; +import java.util.Collection; +import java.util.Iterator; + +import com.ibm.wala.analysis.typeInference.TypeAbstraction; +import com.ibm.wala.analysis.typeInference.TypeInference; +import com.ibm.wala.core.tests.callGraph.CallGraphTestUtil; +import com.ibm.wala.core.tests.demandpa.TestInfo; +import com.ibm.wala.demandpa.alg.DemandRefinementPointsTo; +import com.ibm.wala.demandpa.alg.IDemandPointerAnalysis; +import com.ibm.wala.demandpa.alg.SimpleDemandPointsTo; +import com.ibm.wala.demandpa.alg.refinepolicy.AlwaysRefineCGPolicy; +import com.ibm.wala.demandpa.alg.refinepolicy.AlwaysRefineFieldsPolicy; +import com.ibm.wala.demandpa.alg.refinepolicy.SinglePassRefinementPolicy; +import com.ibm.wala.demandpa.alg.statemachine.DummyStateMachine; +import com.ibm.wala.demandpa.flowgraph.IFlowLabel; +import com.ibm.wala.demandpa.util.MemoryAccessMap; +import com.ibm.wala.demandpa.util.SimpleMemoryAccessMap; +import com.ibm.wala.ipa.callgraph.AnalysisCache; +import com.ibm.wala.ipa.callgraph.AnalysisOptions; +import com.ibm.wala.ipa.callgraph.AnalysisScope; +import com.ibm.wala.ipa.callgraph.CGNode; +import com.ibm.wala.ipa.callgraph.CallGraph; +import com.ibm.wala.ipa.callgraph.CallGraphBuilder; +import com.ibm.wala.ipa.callgraph.Entrypoint; +import com.ibm.wala.ipa.callgraph.impl.Util; +import com.ibm.wala.ipa.callgraph.propagation.InstanceKey; +import com.ibm.wala.ipa.callgraph.propagation.LocalPointerKey; +import com.ibm.wala.ipa.callgraph.propagation.PointerKey; +import com.ibm.wala.ipa.callgraph.propagation.SSAPropagationCallGraphBuilder; +import com.ibm.wala.ipa.cha.ClassHierarchy; +import com.ibm.wala.ipa.cha.ClassHierarchyException; +import com.ibm.wala.ssa.IR; +import com.ibm.wala.util.CancelException; + +/** + * Driver that tests a pointer analysis results against the results of + * {@link SimpleDemandPointsTo}. + * + * @author Manu Sridharan + * + */ +public class TestAgainstSimpleDriver { + + private static final boolean VERBOSE = false; + + public static void main(String[] args) throws IllegalArgumentException, CancelException, IOException { + + // for (String String : ALL_TEST_CASES) { + // runAnalysisForString(String.mainClass, String.scopeFileName); + // } + runAnalysisForTestCase(TestInfo.TEST_ARRAY_SET_ITER); + System.err.println("computed all points-to sets successfully"); + } + + private static void runAnalysisForTestCase(String mainClass) throws IllegalArgumentException, CancelException, IOException { + System.err.println("=======---------------============="); + System.err.println(("ANALYZING " + mainClass + "\n\n")); + // describe the "scope", what is the program we're analyzing + AnalysisScope scope = CallGraphTestUtil.makeJ2SEAnalysisScope(TestInfo.SCOPE_FILE, CallGraphTestUtil.REGRESSION_EXCLUSIONS); + + // build a type hierarchy + ClassHierarchy cha = null; + try { + cha = ClassHierarchy.make(scope); + } catch (ClassHierarchyException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + + // set up call graph construction options; mainly what should be considered + // entrypoints? + Iterable entrypoints = com.ibm.wala.ipa.callgraph.impl.Util.makeMainEntrypoints(scope, cha, mainClass); + AnalysisOptions options = CallGraphTestUtil.makeAnalysisOptions(scope, entrypoints); + + // build an RTA call graph + CallGraphBuilder rtaBuilder = Util.makeRTABuilder(options, new AnalysisCache(), cha, scope); + final CallGraph cg = rtaBuilder.makeCallGraph(options, null); + // System.err.println(cg.toString()); + + MemoryAccessMap fam = new SimpleMemoryAccessMap(cg, rtaBuilder.getPointerAnalysis().getHeapModel(), false); + // System.err.println(fam.toString()); + + IDemandPointerAnalysis dmp = makeDemandPointerAnalysis(options, cha, scope, cg, fam); + + IDemandPointerAnalysis simpleDmp = new SimpleDemandPointsTo(cg, dmp.getHeapModel(), fam, cha, options); + CGNode main = cg.getEntrypointNodes().iterator().next(); + + IR ir = main.getIR(); + TypeInference ti = TypeInference.make(ir, false); + for (int i = 1; i <= ir.getSymbolTable().getMaxValueNumber(); i++) { + TypeAbstraction t = ti.getType(i); + if (t != null) { + LocalPointerKey v = (LocalPointerKey) dmp.getHeapModel().getPointerKeyForLocal(main, i); + Collection p = dmp.getPointsTo(v); + Collection oldP = simpleDmp.getPointsTo(v); + if (!sameContents(p, oldP)) { + System.err.println(("different result for " + v)); + System.err.println(("old " + oldP + "\n\nnew " + p)); + } + printResult(v, p); + } + } + } + + private static boolean sameContents(Collection c1, Collection c2) { + return c1.containsAll(c2) && c2.containsAll(c1); + } + + private static void printResult(PointerKey pk, Collection result) { + if (VERBOSE) { + System.err.println("points-to for " + pk); + if (result.isEmpty()) { + System.err.println(" EMPTY!"); + } + for (Iterator it = result.iterator(); it.hasNext();) { + System.err.println(" " + it.next()); + } + } + } + + private static IDemandPointerAnalysis makeDemandPointerAnalysis(AnalysisOptions options, ClassHierarchy cha, AnalysisScope scope, + CallGraph cg, MemoryAccessMap fam) { + SSAPropagationCallGraphBuilder builder = Util.makeVanillaZeroOneCFABuilder(options, new AnalysisCache(), cha, scope); + // return new TestNewGraphPointsTo(cg, builder, fam, cha, warnings); + DemandRefinementPointsTo fullDemandPointsTo = DemandRefinementPointsTo.makeWithDefaultFlowGraph(cg, builder, fam, cha, options, new DummyStateMachine.Factory()); + // fullDemandPointsTo.setCGRefinePolicy(new AlwaysRefineCGPolicy()); + // fullDemandPointsTo.setFieldRefinePolicy(new AlwaysRefineFieldsPolicy()); + fullDemandPointsTo.setRefinementPolicyFactory(new SinglePassRefinementPolicy.Factory(new AlwaysRefineFieldsPolicy(), + new AlwaysRefineCGPolicy())); + return fullDemandPointsTo; + } + } \ No newline at end of file diff --git a/com.ibm.wala.core.tests/src/com/ibm/wala/demandpa/driver/WalaUtil.java b/com.ibm.wala.core.tests/src/com/ibm/wala/demandpa/driver/WalaUtil.java index 199f437d1..1792304d6 100644 --- a/com.ibm.wala.core.tests/src/com/ibm/wala/demandpa/driver/WalaUtil.java +++ b/com.ibm.wala.core.tests/src/com/ibm/wala/demandpa/driver/WalaUtil.java @@ -1,91 +1,91 @@ -/******************************************************************************* - * 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. - * - * This file is a derivative of code released by the University of - * California under the terms listed below. - * - * Refinement Analysis Tools is Copyright (c) 2007 The Regents of the - * University of California (Regents). Provided that this notice and - * the following two paragraphs are included in any distribution of - * Refinement Analysis Tools or its derivative work, Regents agrees - * not to assert any of Regents' copyright rights in Refinement - * Analysis Tools against recipient for recipient's reproduction, - * preparation of derivative works, public display, public - * performance, distribution or sublicensing of Refinement Analysis - * Tools and derivative works, in source code and object code form. - * This agreement not to assert does not confer, by implication, - * estoppel, or otherwise any license or rights in any intellectual - * property of Regents, including, but not limited to, any patents - * of Regents or Regents' employees. - * - * IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, - * INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, - * INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE - * AND ITS DOCUMENTATION, EVEN IF REGENTS HAS BEEN ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE AND FURTHER DISCLAIMS ANY STATUTORY - * WARRANTY OF NON-INFRINGEMENT. THE SOFTWARE AND ACCOMPANYING - * DOCUMENTATION, IF ANY, PROVIDED HEREUNDER IS PROVIDED "AS - * IS". REGENTS HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, - * UPDATES, ENHANCEMENTS, OR MODIFICATIONS. - */ -package com.ibm.wala.demandpa.driver; - -import java.io.BufferedWriter; -import java.io.File; -import java.io.FileWriter; -import java.io.IOException; -import java.io.PrintWriter; -import java.util.Iterator; -import java.util.Properties; - -import com.ibm.wala.ipa.callgraph.CGNode; -import com.ibm.wala.ipa.callgraph.CallGraph; -import com.ibm.wala.properties.WalaProperties; -import com.ibm.wala.ssa.IR; - -/** - * Various utility methods for working with WALA. - * @author Manu Sridharan - * - */ -public class WalaUtil { - - - public static void dumpAllIR(CallGraph cg, String benchName, Properties p) throws IllegalArgumentException, IllegalArgumentException { - if (cg == null) { - throw new IllegalArgumentException("cg == null"); - } - if (p == null) { - throw new IllegalArgumentException("p == null"); - } - System.err.print("dumping ir..."); - String irFile = p.getProperty(WalaProperties.OUTPUT_DIR) + File.separatorChar + benchName + "-ir.txt"; - try { - PrintWriter writer = new PrintWriter(new BufferedWriter(new FileWriter(irFile))); - for (Iterator iter = cg.iterator(); iter.hasNext();) { - CGNode node = iter.next(); - IR ir = node.getIR(); - if (ir == null) - continue; - writer.println(node); - writer.println("+++++++++++++++++++++++++++++++++"); - writer.println(ir); - writer.println(""); - } - writer.close(); - } catch (IOException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - - System.err.println("done"); - } - -} +/******************************************************************************* + * 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. + * + * This file is a derivative of code released by the University of + * California under the terms listed below. + * + * Refinement Analysis Tools is Copyright (c) 2007 The Regents of the + * University of California (Regents). Provided that this notice and + * the following two paragraphs are included in any distribution of + * Refinement Analysis Tools or its derivative work, Regents agrees + * not to assert any of Regents' copyright rights in Refinement + * Analysis Tools against recipient for recipient's reproduction, + * preparation of derivative works, public display, public + * performance, distribution or sublicensing of Refinement Analysis + * Tools and derivative works, in source code and object code form. + * This agreement not to assert does not confer, by implication, + * estoppel, or otherwise any license or rights in any intellectual + * property of Regents, including, but not limited to, any patents + * of Regents or Regents' employees. + * + * IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, + * INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, + * INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE + * AND ITS DOCUMENTATION, EVEN IF REGENTS HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE AND FURTHER DISCLAIMS ANY STATUTORY + * WARRANTY OF NON-INFRINGEMENT. THE SOFTWARE AND ACCOMPANYING + * DOCUMENTATION, IF ANY, PROVIDED HEREUNDER IS PROVIDED "AS + * IS". REGENTS HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, + * UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + */ +package com.ibm.wala.demandpa.driver; + +import java.io.BufferedWriter; +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; +import java.io.PrintWriter; +import java.util.Iterator; +import java.util.Properties; + +import com.ibm.wala.ipa.callgraph.CGNode; +import com.ibm.wala.ipa.callgraph.CallGraph; +import com.ibm.wala.properties.WalaProperties; +import com.ibm.wala.ssa.IR; + +/** + * Various utility methods for working with WALA. + * @author Manu Sridharan + * + */ +public class WalaUtil { + + + public static void dumpAllIR(CallGraph cg, String benchName, Properties p) throws IllegalArgumentException, IllegalArgumentException { + if (cg == null) { + throw new IllegalArgumentException("cg == null"); + } + if (p == null) { + throw new IllegalArgumentException("p == null"); + } + System.err.print("dumping ir..."); + String irFile = p.getProperty(WalaProperties.OUTPUT_DIR) + File.separatorChar + benchName + "-ir.txt"; + try { + PrintWriter writer = new PrintWriter(new BufferedWriter(new FileWriter(irFile))); + for (Iterator iter = cg.iterator(); iter.hasNext();) { + CGNode node = iter.next(); + IR ir = node.getIR(); + if (ir == null) + continue; + writer.println(node); + writer.println("+++++++++++++++++++++++++++++++++"); + writer.println(ir); + writer.println(""); + } + writer.close(); + } catch (IOException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + + System.err.println("done"); + } + +} diff --git a/com.ibm.wala.core.tests/src/com/ibm/wala/examples/analysis/CountParameters.java b/com.ibm.wala.core.tests/src/com/ibm/wala/examples/analysis/CountParameters.java index 4de1e1220..8353dc652 100644 --- a/com.ibm.wala.core.tests/src/com/ibm/wala/examples/analysis/CountParameters.java +++ b/com.ibm.wala.core.tests/src/com/ibm/wala/examples/analysis/CountParameters.java @@ -1,64 +1,64 @@ -/******************************************************************************* - * 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.examples.analysis; - -import java.io.IOException; - -import com.ibm.wala.classLoader.IClass; -import com.ibm.wala.classLoader.IMethod; -import com.ibm.wala.ipa.callgraph.AnalysisScope; -import com.ibm.wala.ipa.cha.ClassHierarchy; -import com.ibm.wala.ipa.cha.ClassHierarchyException; -import com.ibm.wala.ipa.cha.IClassHierarchy; -import com.ibm.wala.util.config.AnalysisScopeReader; - -/** - * This is a simple example WALA application. - * - * This counts the number of parameters to each method in the primordial loader (the J2SE standard libraries), and - * prints the result. - * - * @author sfink - */ -public class CountParameters { - - private final static ClassLoader MY_CLASSLOADER = CountParameters.class.getClassLoader(); - - /** - * Use the 'CountParameters' launcher to run this program with the appropriate classpath - */ - public static void main(String[] args) throws IOException, ClassHierarchyException { - // build an analysis scope representing the standard libraries, excluding no classes - AnalysisScope scope = AnalysisScopeReader.readJavaScope("primordial.txt", null, MY_CLASSLOADER); - - // build a class hierarchy - System.err.print("Build class hierarchy..."); - IClassHierarchy cha = ClassHierarchy.make(scope); - System.err.println("Done"); - - int nClasses = 0; - int nMethods = 0; - int nParameters = 0; - - for (IClass c : cha) { - nClasses++; - for (IMethod m : c.getDeclaredMethods()) { - nMethods++; - nParameters += m.getNumberOfParameters(); - } - } - - System.out.println(nClasses + " classes"); - System.out.println(nMethods + " methods"); - System.out.println((float)nParameters/(float)nMethods + " parameters per method"); - - } +/******************************************************************************* + * 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.examples.analysis; + +import java.io.IOException; + +import com.ibm.wala.classLoader.IClass; +import com.ibm.wala.classLoader.IMethod; +import com.ibm.wala.ipa.callgraph.AnalysisScope; +import com.ibm.wala.ipa.cha.ClassHierarchy; +import com.ibm.wala.ipa.cha.ClassHierarchyException; +import com.ibm.wala.ipa.cha.IClassHierarchy; +import com.ibm.wala.util.config.AnalysisScopeReader; + +/** + * This is a simple example WALA application. + * + * This counts the number of parameters to each method in the primordial loader (the J2SE standard libraries), and + * prints the result. + * + * @author sfink + */ +public class CountParameters { + + private final static ClassLoader MY_CLASSLOADER = CountParameters.class.getClassLoader(); + + /** + * Use the 'CountParameters' launcher to run this program with the appropriate classpath + */ + public static void main(String[] args) throws IOException, ClassHierarchyException { + // build an analysis scope representing the standard libraries, excluding no classes + AnalysisScope scope = AnalysisScopeReader.readJavaScope("primordial.txt", null, MY_CLASSLOADER); + + // build a class hierarchy + System.err.print("Build class hierarchy..."); + IClassHierarchy cha = ClassHierarchy.make(scope); + System.err.println("Done"); + + int nClasses = 0; + int nMethods = 0; + int nParameters = 0; + + for (IClass c : cha) { + nClasses++; + for (IMethod m : c.getDeclaredMethods()) { + nMethods++; + nParameters += m.getNumberOfParameters(); + } + } + + System.out.println(nClasses + " classes"); + System.out.println(nMethods + " methods"); + System.out.println((float)nParameters/(float)nMethods + " parameters per method"); + + } } \ No newline at end of file diff --git a/com.ibm.wala.core.tests/src/com/ibm/wala/examples/analysis/GetLoadedFields.java b/com.ibm.wala.core.tests/src/com/ibm/wala/examples/analysis/GetLoadedFields.java index e1df6b8ad..d05fc9a16 100644 --- a/com.ibm.wala.core.tests/src/com/ibm/wala/examples/analysis/GetLoadedFields.java +++ b/com.ibm.wala.core.tests/src/com/ibm/wala/examples/analysis/GetLoadedFields.java @@ -1,69 +1,69 @@ -/******************************************************************************* - * Copyright (c) 2002 - 2006 IBM Corporation. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * IBM Corporation - initial API and implementation - *******************************************************************************/ -package com.ibm.wala.examples.analysis; - -import java.io.IOException; -import java.util.Collection; -import java.util.Map; - -import com.ibm.wala.classLoader.CodeScanner; -import com.ibm.wala.classLoader.IClass; -import com.ibm.wala.classLoader.IMethod; -import com.ibm.wala.ipa.callgraph.AnalysisScope; -import com.ibm.wala.ipa.cha.ClassHierarchy; -import com.ibm.wala.ipa.cha.ClassHierarchyException; -import com.ibm.wala.ipa.cha.IClassHierarchy; -import com.ibm.wala.shrikeCT.InvalidClassFileException; -import com.ibm.wala.types.FieldReference; -import com.ibm.wala.util.collections.HashMapFactory; -import com.ibm.wala.util.config.AnalysisScopeReader; - -/** - * This is a simple example WALA application. - * - * For each method in the standard libraries, it maps the IMethod to the set of fields the method reads. - * - * @author sfink - */ -public class GetLoadedFields { - - private final static ClassLoader MY_CLASSLOADER = GetLoadedFields.class.getClassLoader(); - - /** - * Use the 'GetLoadedFields' launcher to run this program with the appropriate classpath - * @throws InvalidClassFileException - */ - public static void main(String[] args) throws IOException, ClassHierarchyException, InvalidClassFileException { - // build an analysis scope representing the standard libraries, excluding no classes - AnalysisScope scope = AnalysisScopeReader.readJavaScope("primordial.txt", null, MY_CLASSLOADER); - - // build a class hierarchy - System.err.print("Build class hierarchy..."); - IClassHierarchy cha = ClassHierarchy.make(scope); - System.err.println("Done"); - - int nMethods = 0; - int nFields = 0; - - Map> method2Field = HashMapFactory.make(); - for (IClass c : cha) { - for (IMethod m : c.getDeclaredMethods()) { - nMethods++; - Collection fields = CodeScanner.getFieldsRead(m); - nFields += fields.size(); - method2Field.put(m, fields); - } - } - - System.out.println(nMethods + " methods"); - System.out.println((float)nFields/(float)nMethods + " fields read per method"); - } +/******************************************************************************* + * 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.examples.analysis; + +import java.io.IOException; +import java.util.Collection; +import java.util.Map; + +import com.ibm.wala.classLoader.CodeScanner; +import com.ibm.wala.classLoader.IClass; +import com.ibm.wala.classLoader.IMethod; +import com.ibm.wala.ipa.callgraph.AnalysisScope; +import com.ibm.wala.ipa.cha.ClassHierarchy; +import com.ibm.wala.ipa.cha.ClassHierarchyException; +import com.ibm.wala.ipa.cha.IClassHierarchy; +import com.ibm.wala.shrikeCT.InvalidClassFileException; +import com.ibm.wala.types.FieldReference; +import com.ibm.wala.util.collections.HashMapFactory; +import com.ibm.wala.util.config.AnalysisScopeReader; + +/** + * This is a simple example WALA application. + * + * For each method in the standard libraries, it maps the IMethod to the set of fields the method reads. + * + * @author sfink + */ +public class GetLoadedFields { + + private final static ClassLoader MY_CLASSLOADER = GetLoadedFields.class.getClassLoader(); + + /** + * Use the 'GetLoadedFields' launcher to run this program with the appropriate classpath + * @throws InvalidClassFileException + */ + public static void main(String[] args) throws IOException, ClassHierarchyException, InvalidClassFileException { + // build an analysis scope representing the standard libraries, excluding no classes + AnalysisScope scope = AnalysisScopeReader.readJavaScope("primordial.txt", null, MY_CLASSLOADER); + + // build a class hierarchy + System.err.print("Build class hierarchy..."); + IClassHierarchy cha = ClassHierarchy.make(scope); + System.err.println("Done"); + + int nMethods = 0; + int nFields = 0; + + Map> method2Field = HashMapFactory.make(); + for (IClass c : cha) { + for (IMethod m : c.getDeclaredMethods()) { + nMethods++; + Collection fields = CodeScanner.getFieldsRead(m); + nFields += fields.size(); + method2Field.put(m, fields); + } + } + + System.out.println(nMethods + " methods"); + System.out.println((float)nFields/(float)nMethods + " fields read per method"); + } } \ No newline at end of file diff --git a/com.ibm.wala.core.tests/src/com/ibm/wala/examples/analysis/SimpleThreadEscapeAnalysis.java b/com.ibm.wala.core.tests/src/com/ibm/wala/examples/analysis/SimpleThreadEscapeAnalysis.java index 61b66d65a..d72f4b077 100644 --- a/com.ibm.wala.core.tests/src/com/ibm/wala/examples/analysis/SimpleThreadEscapeAnalysis.java +++ b/com.ibm.wala.core.tests/src/com/ibm/wala/examples/analysis/SimpleThreadEscapeAnalysis.java @@ -1,350 +1,350 @@ -/******************************************************************************* - * 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 com.ibm.wala.examples.analysis; - -import java.io.File; -import java.io.IOException; -import java.util.Collection; -import java.util.Iterator; -import java.util.Properties; -import java.util.Set; -import java.util.jar.JarFile; - -import com.ibm.wala.classLoader.ArrayClass; -import com.ibm.wala.classLoader.IClass; -import com.ibm.wala.classLoader.IField; -import com.ibm.wala.classLoader.IMethod; -import com.ibm.wala.classLoader.JarFileModule; -import com.ibm.wala.client.AbstractAnalysisEngine; -import com.ibm.wala.ipa.callgraph.AnalysisCache; -import com.ibm.wala.ipa.callgraph.AnalysisOptions; -import com.ibm.wala.ipa.callgraph.CGNode; -import com.ibm.wala.ipa.callgraph.CallGraph; -import com.ibm.wala.ipa.callgraph.CallGraphBuilder; -import com.ibm.wala.ipa.callgraph.Entrypoint; -import com.ibm.wala.ipa.callgraph.impl.Util; -import com.ibm.wala.ipa.callgraph.propagation.HeapModel; -import com.ibm.wala.ipa.callgraph.propagation.InstanceKey; -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.ipa.cha.IClassHierarchy; -import com.ibm.wala.properties.WalaProperties; -import com.ibm.wala.types.TypeReference; -import com.ibm.wala.util.CancelException; -import com.ibm.wala.util.WalaException; -import com.ibm.wala.util.collections.HashSetFactory; -import com.ibm.wala.util.intset.OrdinalSet; - -/** - *

- * A simple thread-level escape analysis: this code computes the set of classes of which some instance may be accessed - * by some thread other than the one that created it. - *

- * - *

- * The algorithm is not very bright; it is based on the observation that there are only three ways for an object to pass - * from one thread to another. - *

    - *
  • The object is stored into a static variable. - *
  • The object is stored into an instance field of a Thread - *
  • The object is reachable from a field of another escaping object. - *
- *

- * - *

- * This observation is implemented in the obvious way: - *

    - *
  1. All static fields are collected - *
  2. All Thread constructor parameters are collected - *
  3. The points-to sets of these values represent the base set of escapees. - *
  4. All object reachable from fields of these objects are added - *
  5. This process continues until a fixpoint is reached - *
  6. The abstract objects in the points-to sets are converted to types - *
  7. This set of types is returned - *
- *

- * - * @author Julian Dolby - */ -public class SimpleThreadEscapeAnalysis extends AbstractAnalysisEngine { - - private final Set applicationJarFiles; - - private final String applicationMainClass; - - /** - * The two input parameters define the program to analyze: the jars of .class files and the main class to start from. - */ - public SimpleThreadEscapeAnalysis(Set applicationJarFiles, String applicationMainClass) { - this.applicationJarFiles = applicationJarFiles; - this.applicationMainClass = applicationMainClass; - } - - @Override - protected CallGraphBuilder getCallGraphBuilder(IClassHierarchy cha, AnalysisOptions options, AnalysisCache cache) { - return Util.makeZeroCFABuilder(options, cache, cha, scope); - } - - /** - * Given a root path, add it to the set if it is a jar, or traverse it recursively if it is a directory. - */ - private void collectJars(File f, Set result) throws IOException { - if (f.isDirectory()) { - File[] files = f.listFiles(); - for (int i = 0; i < files.length; i++) { - collectJars(files[i], result); - } - } else if (f.getAbsolutePath().endsWith(".jar")) { - result.add(new JarFile(f)); - } - } - - /** - * Collect the set of JarFiles that constitute the system libraries of the running JRE. - */ - private JarFile[] getSystemJars() throws IOException { - String javaHomePath = "garbage"; - Set jarFiles = HashSetFactory.make(); - - // first, see if wala.properties has been set up - try { - Properties p = WalaProperties.loadProperties(); - javaHomePath = p.getProperty(WalaProperties.J2SE_DIR); - } catch (WalaException e) { - // no luck. - } - - // if not, try assuming the running JRE looks normal - File x = new File(javaHomePath); - if (!(x.exists() && x.isDirectory())) { - javaHomePath = System.getProperty("java.home"); - - if (!javaHomePath.endsWith(File.separator)) { - javaHomePath = javaHomePath + File.separator; - } - - javaHomePath = javaHomePath + "lib"; - } - - // find jars from chosen JRE lib path - collectJars(new File(javaHomePath), jarFiles); - - return jarFiles.toArray(new JarFile[jarFiles.size()]); - } - - /** - * Take the given set of JarFiles that constitute the program, and return a set of Module files as expected by the - * WALA machinery. - */ - private Set getModuleFiles() { - Set result = HashSetFactory.make(); - for (Iterator jars = applicationJarFiles.iterator(); jars.hasNext();) { - result.add(new JarFileModule(jars.next())); - } - - return result; - } - - /** - * The heart of the analysis. - * @throws CancelException - * @throws IllegalArgumentException - */ - public Set gatherThreadEscapingClasses() throws IOException, ClassHierarchyException, IllegalArgumentException, - CancelException { - - // - // set the application to analyze - // - setModuleFiles(getModuleFiles()); - - // - // set the system jar files to use. - // change this if you want to use a specific jre version - // - setJ2SELibraries(getSystemJars()); - - // - // the application and libraries are set, now build the scope... - // - buildAnalysisScope(); - - // - // ...and the class hierarchy - // - IClassHierarchy cha = buildClassHierarchy(); - assert cha != null : "failed to create class hierarchy"; - setClassHierarchy(cha); - - // - // entrypoints are where analysis starts - // - Iterable roots = Util.makeMainEntrypoints(getScope(), cha, applicationMainClass); - - // - // analysis options controls aspects of call graph construction - // - AnalysisOptions options = getDefaultOptions(roots); - - // - // build the call graph - // - buildCallGraph(cha, options, true, null); - - // - // extract data for analysis - // - CallGraph cg = getCallGraph(); - PointerAnalysis pa = getPointerAnalysis(); - - // - // collect all places where objects can escape their creating thread: - // 1) all static fields - // 2) arguments to Thread constructors - // - Set escapeAnalysisRoots = HashSetFactory.make(); - HeapModel heapModel = pa.getHeapModel(); - - // 1) static fields - for (IClass cls : cha) { - Collection staticFields = cls.getDeclaredStaticFields(); - for (Iterator sfs = staticFields.iterator(); sfs.hasNext();) { - IField sf = (IField) sfs.next(); - if (sf.getFieldTypeReference().isReferenceType()) { - escapeAnalysisRoots.add(heapModel.getPointerKeyForStaticField(sf)); - } - } - } - - // 2) instance fields of Threads - // (we hack this by getting the 'this' parameter of all ctor calls; - // this works because the next phase will add all objects transitively - // reachable from fields of types in these pointer keys, and all - // Thread objects must be constructed somewhere) - Collection threads = cha.computeSubClasses(TypeReference.JavaLangThread); - for (Iterator clss = threads.iterator(); clss.hasNext();) { - IClass cls = (IClass) clss.next(); - for (Iterator ms = cls.getDeclaredMethods().iterator(); ms.hasNext();) { - IMethod m = (IMethod) ms.next(); - if (m.isInit()) { - Set nodes = cg.getNodes(m.getReference()); - for (Iterator ns = nodes.iterator(); ns.hasNext();) { - CGNode n = (CGNode) ns.next(); - escapeAnalysisRoots.add(heapModel.getPointerKeyForLocal(n, 1)); - } - } - } - } - - // - // compute escaping types: all types flowing to escaping roots and - // all types transitively reachable through their fields. - // - Set escapingInstanceKeys = HashSetFactory.make(); - - // - // pass 1: get abstract objects (instance keys) for escaping locations - // - for (Iterator rts = escapeAnalysisRoots.iterator(); rts.hasNext();) { - PointerKey root = rts.next(); - OrdinalSet objects = pa.getPointsToSet(root); - for (Iterator objs = objects.iterator(); objs.hasNext();) { - InstanceKey obj = (InstanceKey) objs.next(); - escapingInstanceKeys.add(obj); - } - } - - // - // passes 2+: get fields of escaping keys, and add pointed-to keys - // - Set newKeys = HashSetFactory.make(); - do { - newKeys.clear(); - for (Iterator keys = escapingInstanceKeys.iterator(); keys.hasNext();) { - InstanceKey key = keys.next(); - IClass type = key.getConcreteType(); - if (type.isReferenceType()) { - if (type.isArrayClass()) { - if (((ArrayClass) type).getElementClass() != null) { - PointerKey fk = heapModel.getPointerKeyForArrayContents(key); - OrdinalSet fobjects = pa.getPointsToSet(fk); - for (Iterator fobjs = fobjects.iterator(); fobjs.hasNext();) { - InstanceKey fobj = (InstanceKey) fobjs.next(); - if (!escapingInstanceKeys.contains(fobj)) { - newKeys.add(fobj); - } - } - } - } else { - Collection fields = type.getAllInstanceFields(); - for (Iterator fs = fields.iterator(); fs.hasNext();) { - IField f = (IField) fs.next(); - if (f.getFieldTypeReference().isReferenceType()) { - PointerKey fk = heapModel.getPointerKeyForInstanceField(key, f); - OrdinalSet fobjects = pa.getPointsToSet(fk); - for (Iterator fobjs = fobjects.iterator(); fobjs.hasNext();) { - InstanceKey fobj = (InstanceKey) fobjs.next(); - if (!escapingInstanceKeys.contains(fobj)) { - newKeys.add(fobj); - } - } - } - } - } - } - } - escapingInstanceKeys.addAll(newKeys); - } while (!newKeys.isEmpty()); - - // - // get set of types from set of instance keys - // - Set escapingTypes = HashSetFactory.make(); - for (Iterator keys = escapingInstanceKeys.iterator(); keys.hasNext();) { - InstanceKey key = keys.next(); - escapingTypes.add(key.getConcreteType()); - } - - return escapingTypes; - } - - /** - * This main program shows one example use of thread escape analysis: producing a set of fields to be monitored for a - * dynamic race detector. The idea is that any field might have a race with two exceptions: final fields do not have - * races since there are no writes to them, and volatile fields have atomic read and write semantics provided by the - * VM. Hence, this piece of code produces a list of all other fields. - * @throws CancelException - * @throws IllegalArgumentException - */ - public static void main(String[] args) throws IOException, ClassHierarchyException, IllegalArgumentException, CancelException { - String mainClassName = args[0]; - - Set jars = HashSetFactory.make(); - for (int i = 1; i < args.length; i++) { - jars.add(new JarFile(args[i])); - } - - Set escapingTypes = (new SimpleThreadEscapeAnalysis(jars, mainClassName)).gatherThreadEscapingClasses(); - - for (Iterator types = escapingTypes.iterator(); types.hasNext();) { - IClass cls = types.next(); - if (!cls.isArrayClass()) { - for (Iterator fs = cls.getAllFields().iterator(); fs.hasNext();) { - IField f = (IField) fs.next(); - if (!f.isVolatile() && !f.isFinal()) { - System.err.println(f.getReference()); - } - } - } - } - } -} +/******************************************************************************* + * 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 com.ibm.wala.examples.analysis; + +import java.io.File; +import java.io.IOException; +import java.util.Collection; +import java.util.Iterator; +import java.util.Properties; +import java.util.Set; +import java.util.jar.JarFile; + +import com.ibm.wala.classLoader.ArrayClass; +import com.ibm.wala.classLoader.IClass; +import com.ibm.wala.classLoader.IField; +import com.ibm.wala.classLoader.IMethod; +import com.ibm.wala.classLoader.JarFileModule; +import com.ibm.wala.client.AbstractAnalysisEngine; +import com.ibm.wala.ipa.callgraph.AnalysisCache; +import com.ibm.wala.ipa.callgraph.AnalysisOptions; +import com.ibm.wala.ipa.callgraph.CGNode; +import com.ibm.wala.ipa.callgraph.CallGraph; +import com.ibm.wala.ipa.callgraph.CallGraphBuilder; +import com.ibm.wala.ipa.callgraph.Entrypoint; +import com.ibm.wala.ipa.callgraph.impl.Util; +import com.ibm.wala.ipa.callgraph.propagation.HeapModel; +import com.ibm.wala.ipa.callgraph.propagation.InstanceKey; +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.ipa.cha.IClassHierarchy; +import com.ibm.wala.properties.WalaProperties; +import com.ibm.wala.types.TypeReference; +import com.ibm.wala.util.CancelException; +import com.ibm.wala.util.WalaException; +import com.ibm.wala.util.collections.HashSetFactory; +import com.ibm.wala.util.intset.OrdinalSet; + +/** + *

+ * A simple thread-level escape analysis: this code computes the set of classes of which some instance may be accessed + * by some thread other than the one that created it. + *

+ * + *

+ * The algorithm is not very bright; it is based on the observation that there are only three ways for an object to pass + * from one thread to another. + *

    + *
  • The object is stored into a static variable. + *
  • The object is stored into an instance field of a Thread + *
  • The object is reachable from a field of another escaping object. + *
+ *

+ * + *

+ * This observation is implemented in the obvious way: + *

    + *
  1. All static fields are collected + *
  2. All Thread constructor parameters are collected + *
  3. The points-to sets of these values represent the base set of escapees. + *
  4. All object reachable from fields of these objects are added + *
  5. This process continues until a fixpoint is reached + *
  6. The abstract objects in the points-to sets are converted to types + *
  7. This set of types is returned + *
+ *

+ * + * @author Julian Dolby + */ +public class SimpleThreadEscapeAnalysis extends AbstractAnalysisEngine { + + private final Set applicationJarFiles; + + private final String applicationMainClass; + + /** + * The two input parameters define the program to analyze: the jars of .class files and the main class to start from. + */ + public SimpleThreadEscapeAnalysis(Set applicationJarFiles, String applicationMainClass) { + this.applicationJarFiles = applicationJarFiles; + this.applicationMainClass = applicationMainClass; + } + + @Override + protected CallGraphBuilder getCallGraphBuilder(IClassHierarchy cha, AnalysisOptions options, AnalysisCache cache) { + return Util.makeZeroCFABuilder(options, cache, cha, scope); + } + + /** + * Given a root path, add it to the set if it is a jar, or traverse it recursively if it is a directory. + */ + private void collectJars(File f, Set result) throws IOException { + if (f.isDirectory()) { + File[] files = f.listFiles(); + for (int i = 0; i < files.length; i++) { + collectJars(files[i], result); + } + } else if (f.getAbsolutePath().endsWith(".jar")) { + result.add(new JarFile(f)); + } + } + + /** + * Collect the set of JarFiles that constitute the system libraries of the running JRE. + */ + private JarFile[] getSystemJars() throws IOException { + String javaHomePath = "garbage"; + Set jarFiles = HashSetFactory.make(); + + // first, see if wala.properties has been set up + try { + Properties p = WalaProperties.loadProperties(); + javaHomePath = p.getProperty(WalaProperties.J2SE_DIR); + } catch (WalaException e) { + // no luck. + } + + // if not, try assuming the running JRE looks normal + File x = new File(javaHomePath); + if (!(x.exists() && x.isDirectory())) { + javaHomePath = System.getProperty("java.home"); + + if (!javaHomePath.endsWith(File.separator)) { + javaHomePath = javaHomePath + File.separator; + } + + javaHomePath = javaHomePath + "lib"; + } + + // find jars from chosen JRE lib path + collectJars(new File(javaHomePath), jarFiles); + + return jarFiles.toArray(new JarFile[jarFiles.size()]); + } + + /** + * Take the given set of JarFiles that constitute the program, and return a set of Module files as expected by the + * WALA machinery. + */ + private Set getModuleFiles() { + Set result = HashSetFactory.make(); + for (Iterator jars = applicationJarFiles.iterator(); jars.hasNext();) { + result.add(new JarFileModule(jars.next())); + } + + return result; + } + + /** + * The heart of the analysis. + * @throws CancelException + * @throws IllegalArgumentException + */ + public Set gatherThreadEscapingClasses() throws IOException, ClassHierarchyException, IllegalArgumentException, + CancelException { + + // + // set the application to analyze + // + setModuleFiles(getModuleFiles()); + + // + // set the system jar files to use. + // change this if you want to use a specific jre version + // + setJ2SELibraries(getSystemJars()); + + // + // the application and libraries are set, now build the scope... + // + buildAnalysisScope(); + + // + // ...and the class hierarchy + // + IClassHierarchy cha = buildClassHierarchy(); + assert cha != null : "failed to create class hierarchy"; + setClassHierarchy(cha); + + // + // entrypoints are where analysis starts + // + Iterable roots = Util.makeMainEntrypoints(getScope(), cha, applicationMainClass); + + // + // analysis options controls aspects of call graph construction + // + AnalysisOptions options = getDefaultOptions(roots); + + // + // build the call graph + // + buildCallGraph(cha, options, true, null); + + // + // extract data for analysis + // + CallGraph cg = getCallGraph(); + PointerAnalysis pa = getPointerAnalysis(); + + // + // collect all places where objects can escape their creating thread: + // 1) all static fields + // 2) arguments to Thread constructors + // + Set escapeAnalysisRoots = HashSetFactory.make(); + HeapModel heapModel = pa.getHeapModel(); + + // 1) static fields + for (IClass cls : cha) { + Collection staticFields = cls.getDeclaredStaticFields(); + for (Iterator sfs = staticFields.iterator(); sfs.hasNext();) { + IField sf = (IField) sfs.next(); + if (sf.getFieldTypeReference().isReferenceType()) { + escapeAnalysisRoots.add(heapModel.getPointerKeyForStaticField(sf)); + } + } + } + + // 2) instance fields of Threads + // (we hack this by getting the 'this' parameter of all ctor calls; + // this works because the next phase will add all objects transitively + // reachable from fields of types in these pointer keys, and all + // Thread objects must be constructed somewhere) + Collection threads = cha.computeSubClasses(TypeReference.JavaLangThread); + for (Iterator clss = threads.iterator(); clss.hasNext();) { + IClass cls = (IClass) clss.next(); + for (Iterator ms = cls.getDeclaredMethods().iterator(); ms.hasNext();) { + IMethod m = (IMethod) ms.next(); + if (m.isInit()) { + Set nodes = cg.getNodes(m.getReference()); + for (Iterator ns = nodes.iterator(); ns.hasNext();) { + CGNode n = (CGNode) ns.next(); + escapeAnalysisRoots.add(heapModel.getPointerKeyForLocal(n, 1)); + } + } + } + } + + // + // compute escaping types: all types flowing to escaping roots and + // all types transitively reachable through their fields. + // + Set escapingInstanceKeys = HashSetFactory.make(); + + // + // pass 1: get abstract objects (instance keys) for escaping locations + // + for (Iterator rts = escapeAnalysisRoots.iterator(); rts.hasNext();) { + PointerKey root = rts.next(); + OrdinalSet objects = pa.getPointsToSet(root); + for (Iterator objs = objects.iterator(); objs.hasNext();) { + InstanceKey obj = (InstanceKey) objs.next(); + escapingInstanceKeys.add(obj); + } + } + + // + // passes 2+: get fields of escaping keys, and add pointed-to keys + // + Set newKeys = HashSetFactory.make(); + do { + newKeys.clear(); + for (Iterator keys = escapingInstanceKeys.iterator(); keys.hasNext();) { + InstanceKey key = keys.next(); + IClass type = key.getConcreteType(); + if (type.isReferenceType()) { + if (type.isArrayClass()) { + if (((ArrayClass) type).getElementClass() != null) { + PointerKey fk = heapModel.getPointerKeyForArrayContents(key); + OrdinalSet fobjects = pa.getPointsToSet(fk); + for (Iterator fobjs = fobjects.iterator(); fobjs.hasNext();) { + InstanceKey fobj = (InstanceKey) fobjs.next(); + if (!escapingInstanceKeys.contains(fobj)) { + newKeys.add(fobj); + } + } + } + } else { + Collection fields = type.getAllInstanceFields(); + for (Iterator fs = fields.iterator(); fs.hasNext();) { + IField f = (IField) fs.next(); + if (f.getFieldTypeReference().isReferenceType()) { + PointerKey fk = heapModel.getPointerKeyForInstanceField(key, f); + OrdinalSet fobjects = pa.getPointsToSet(fk); + for (Iterator fobjs = fobjects.iterator(); fobjs.hasNext();) { + InstanceKey fobj = (InstanceKey) fobjs.next(); + if (!escapingInstanceKeys.contains(fobj)) { + newKeys.add(fobj); + } + } + } + } + } + } + } + escapingInstanceKeys.addAll(newKeys); + } while (!newKeys.isEmpty()); + + // + // get set of types from set of instance keys + // + Set escapingTypes = HashSetFactory.make(); + for (Iterator keys = escapingInstanceKeys.iterator(); keys.hasNext();) { + InstanceKey key = keys.next(); + escapingTypes.add(key.getConcreteType()); + } + + return escapingTypes; + } + + /** + * This main program shows one example use of thread escape analysis: producing a set of fields to be monitored for a + * dynamic race detector. The idea is that any field might have a race with two exceptions: final fields do not have + * races since there are no writes to them, and volatile fields have atomic read and write semantics provided by the + * VM. Hence, this piece of code produces a list of all other fields. + * @throws CancelException + * @throws IllegalArgumentException + */ + public static void main(String[] args) throws IOException, ClassHierarchyException, IllegalArgumentException, CancelException { + String mainClassName = args[0]; + + Set jars = HashSetFactory.make(); + for (int i = 1; i < args.length; i++) { + jars.add(new JarFile(args[i])); + } + + Set escapingTypes = (new SimpleThreadEscapeAnalysis(jars, mainClassName)).gatherThreadEscapingClasses(); + + for (Iterator types = escapingTypes.iterator(); types.hasNext();) { + IClass cls = types.next(); + if (!cls.isArrayClass()) { + for (Iterator fs = cls.getAllFields().iterator(); fs.hasNext();) { + IField f = (IField) fs.next(); + if (!f.isVolatile() && !f.isFinal()) { + System.err.println(f.getReference()); + } + } + } + } + } +} diff --git a/com.ibm.wala.core.tests/src/com/ibm/wala/examples/drivers/JavaViewerDriver.java b/com.ibm.wala.core.tests/src/com/ibm/wala/examples/drivers/JavaViewerDriver.java index a9ccf9f74..a2ebc9101 100644 --- a/com.ibm.wala.core.tests/src/com/ibm/wala/examples/drivers/JavaViewerDriver.java +++ b/com.ibm.wala.core.tests/src/com/ibm/wala/examples/drivers/JavaViewerDriver.java @@ -1,62 +1,62 @@ -package com.ibm.wala.examples.drivers; - -import java.io.File; -import java.io.IOException; -import java.util.Properties; - -import com.ibm.wala.core.tests.callGraph.CallGraphTestUtil; -import com.ibm.wala.ipa.callgraph.AnalysisCache; -import com.ibm.wala.ipa.callgraph.AnalysisOptions; -import com.ibm.wala.ipa.callgraph.AnalysisScope; -import com.ibm.wala.ipa.callgraph.CallGraph; -import com.ibm.wala.ipa.callgraph.CallGraphBuilderCancelException; -import com.ibm.wala.ipa.callgraph.Entrypoint; -import com.ibm.wala.ipa.callgraph.impl.Util; -import com.ibm.wala.ipa.callgraph.propagation.PointerAnalysis; -import com.ibm.wala.ipa.cha.ClassHierarchy; -import com.ibm.wala.ipa.cha.ClassHierarchyException; -import com.ibm.wala.util.config.AnalysisScopeReader; -import com.ibm.wala.util.io.CommandLine; -import com.ibm.wala.util.io.FileProvider; -import com.ibm.wala.viz.viewer.WalaViewer; - -/** - * Allows viewing the ClassHeirarcy, CallGraph and Pointer Analysis built from a given classpath. - * @author yinnonh - * - */ -public class JavaViewerDriver { - public static void main(String[] args) throws ClassHierarchyException, IOException, CallGraphBuilderCancelException { - Properties p = CommandLine.parse(args); - validateCommandLine(p); - run(p.getProperty("appClassPath"), p.getProperty("exclusionFile", CallGraphTestUtil.REGRESSION_EXCLUSIONS)); - } - - public static void validateCommandLine(Properties p) { - if (p.get("appClassPath") == null) { - throw new UnsupportedOperationException("expected command-line to include -appClassPath"); - } - } - - private static void run(String classPath, String exclusionFilePath) throws IOException, ClassHierarchyException, CallGraphBuilderCancelException{ - - File exclusionFile = (new FileProvider()).getFile(exclusionFilePath); - AnalysisScope scope = AnalysisScopeReader.makeJavaBinaryAnalysisScope(classPath, exclusionFile != null ? exclusionFile - : new File(CallGraphTestUtil.REGRESSION_EXCLUSIONS)); - - ClassHierarchy cha = ClassHierarchy.make(scope); - - Iterable entrypoints = com.ibm.wala.ipa.callgraph.impl.Util.makeMainEntrypoints(scope, cha); - AnalysisOptions options = new AnalysisOptions(scope, entrypoints); - - // // - // build the call graph - // // - com.ibm.wala.ipa.callgraph.CallGraphBuilder builder = Util.makeZeroCFABuilder(options, new AnalysisCache(), cha, scope); - CallGraph cg = builder.makeCallGraph(options, null); - - PointerAnalysis pa = builder.getPointerAnalysis(); - new WalaViewer(cg, pa); - - } -} +package com.ibm.wala.examples.drivers; + +import java.io.File; +import java.io.IOException; +import java.util.Properties; + +import com.ibm.wala.core.tests.callGraph.CallGraphTestUtil; +import com.ibm.wala.ipa.callgraph.AnalysisCache; +import com.ibm.wala.ipa.callgraph.AnalysisOptions; +import com.ibm.wala.ipa.callgraph.AnalysisScope; +import com.ibm.wala.ipa.callgraph.CallGraph; +import com.ibm.wala.ipa.callgraph.CallGraphBuilderCancelException; +import com.ibm.wala.ipa.callgraph.Entrypoint; +import com.ibm.wala.ipa.callgraph.impl.Util; +import com.ibm.wala.ipa.callgraph.propagation.PointerAnalysis; +import com.ibm.wala.ipa.cha.ClassHierarchy; +import com.ibm.wala.ipa.cha.ClassHierarchyException; +import com.ibm.wala.util.config.AnalysisScopeReader; +import com.ibm.wala.util.io.CommandLine; +import com.ibm.wala.util.io.FileProvider; +import com.ibm.wala.viz.viewer.WalaViewer; + +/** + * Allows viewing the ClassHeirarcy, CallGraph and Pointer Analysis built from a given classpath. + * @author yinnonh + * + */ +public class JavaViewerDriver { + public static void main(String[] args) throws ClassHierarchyException, IOException, CallGraphBuilderCancelException { + Properties p = CommandLine.parse(args); + validateCommandLine(p); + run(p.getProperty("appClassPath"), p.getProperty("exclusionFile", CallGraphTestUtil.REGRESSION_EXCLUSIONS)); + } + + public static void validateCommandLine(Properties p) { + if (p.get("appClassPath") == null) { + throw new UnsupportedOperationException("expected command-line to include -appClassPath"); + } + } + + private static void run(String classPath, String exclusionFilePath) throws IOException, ClassHierarchyException, CallGraphBuilderCancelException{ + + File exclusionFile = (new FileProvider()).getFile(exclusionFilePath); + AnalysisScope scope = AnalysisScopeReader.makeJavaBinaryAnalysisScope(classPath, exclusionFile != null ? exclusionFile + : new File(CallGraphTestUtil.REGRESSION_EXCLUSIONS)); + + ClassHierarchy cha = ClassHierarchy.make(scope); + + Iterable entrypoints = com.ibm.wala.ipa.callgraph.impl.Util.makeMainEntrypoints(scope, cha); + AnalysisOptions options = new AnalysisOptions(scope, entrypoints); + + // // + // build the call graph + // // + com.ibm.wala.ipa.callgraph.CallGraphBuilder builder = Util.makeZeroCFABuilder(options, new AnalysisCache(), cha, scope); + CallGraph cg = builder.makeCallGraph(options, null); + + PointerAnalysis pa = builder.getPointerAnalysis(); + new WalaViewer(cg, pa); + + } +} diff --git a/com.ibm.wala.core.tests/src/com/ibm/wala/examples/drivers/PDFCallGraph.java b/com.ibm.wala.core.tests/src/com/ibm/wala/examples/drivers/PDFCallGraph.java index 49a282361..8c7ea772a 100644 --- a/com.ibm.wala.core.tests/src/com/ibm/wala/examples/drivers/PDFCallGraph.java +++ b/com.ibm.wala.core.tests/src/com/ibm/wala/examples/drivers/PDFCallGraph.java @@ -1,211 +1,211 @@ -/******************************************************************************* - * 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.examples.drivers; - -import java.io.File; -import java.io.IOException; -import java.util.Collection; -import java.util.Iterator; -import java.util.Properties; - -import com.ibm.wala.core.tests.callGraph.CallGraphTestUtil; -import com.ibm.wala.examples.properties.WalaExamplesProperties; -import com.ibm.wala.ipa.callgraph.AnalysisCache; -import com.ibm.wala.ipa.callgraph.AnalysisOptions; -import com.ibm.wala.ipa.callgraph.AnalysisScope; -import com.ibm.wala.ipa.callgraph.CGNode; -import com.ibm.wala.ipa.callgraph.CallGraph; -import com.ibm.wala.ipa.callgraph.CallGraphStats; -import com.ibm.wala.ipa.callgraph.Entrypoint; -import com.ibm.wala.ipa.callgraph.impl.Util; -import com.ibm.wala.ipa.callgraph.propagation.LocalPointerKey; -import com.ibm.wala.ipa.cha.ClassHierarchy; -import com.ibm.wala.properties.WalaProperties; -import com.ibm.wala.types.ClassLoaderReference; -import com.ibm.wala.util.CancelException; -import com.ibm.wala.util.WalaException; -import com.ibm.wala.util.collections.Filter; -import com.ibm.wala.util.collections.HashSetFactory; -import com.ibm.wala.util.config.AnalysisScopeReader; -import com.ibm.wala.util.debug.Assertions; -import com.ibm.wala.util.graph.Graph; -import com.ibm.wala.util.io.CommandLine; -import com.ibm.wala.util.io.FileProvider; -import com.ibm.wala.util.io.FileUtil; -import com.ibm.wala.viz.DotUtil; -import com.ibm.wala.viz.PDFViewUtil; - -/** - * This simple example WALA application builds a call graph and fires off ghostview to visualize a DOT representation. - */ -public class PDFCallGraph { - public static boolean isDirectory(String appJar) { - return (new File(appJar).isDirectory()); - } - - public static String findJarFiles(String[] directories) throws WalaException { - Collection result = HashSetFactory.make(); - for (int i = 0; i < directories.length; i++) { - for (Iterator it = FileUtil.listFiles(directories[i], ".*\\.jar", true).iterator(); it.hasNext();) { - File f = (File) it.next(); - result.add(f.getAbsolutePath()); - } - } - return composeString(result); - } - - private static String composeString(Collection s) { - StringBuffer result = new StringBuffer(); - Iterator it = s.iterator(); - for (int i = 0; i < s.size() - 1; i++) { - result.append(it.next()); - result.append(File.pathSeparator); - } - if (it.hasNext()) { - result.append(it.next()); - } - return result.toString(); - } - - private final static String PDF_FILE = "cg.pdf"; - - /** - * Usage: args = "-appJar [jar file name] {-exclusionFile [exclusionFileName]}" The "jar file name" should be something like - * "c:/temp/testdata/java_cup.jar" - * - * @throws CancelException - * @throws IllegalArgumentException - */ - public static void main(String[] args) throws WalaException, IllegalArgumentException, CancelException { - run(args); - } - - /** - * Usage: args = "-appJar [jar file name] {-exclusionFile [exclusionFileName]}" The "jar file name" should be something like - * "c:/temp/testdata/java_cup.jar" - * - * @throws CancelException - * @throws IllegalArgumentException - */ - public static Process run(String[] args) throws WalaException, IllegalArgumentException, CancelException { - Properties p = CommandLine.parse(args); - validateCommandLine(p); - return run(p.getProperty("appJar"), p.getProperty("exclusionFile", CallGraphTestUtil.REGRESSION_EXCLUSIONS)); - } - - /** - * @param appJar something like "c:/temp/testdata/java_cup.jar" - * @throws CancelException - * @throws IllegalArgumentException - */ - public static Process run(String appJar, String exclusionFile) throws IllegalArgumentException, CancelException { - try { - Graph g = buildPrunedCallGraph(appJar, (new FileProvider()).getFile(exclusionFile)); - - Properties p = null; - try { - p = WalaExamplesProperties.loadProperties(); - p.putAll(WalaProperties.loadProperties()); - } catch (WalaException e) { - e.printStackTrace(); - Assertions.UNREACHABLE(); - } - String pdfFile = p.getProperty(WalaProperties.OUTPUT_DIR) + File.separatorChar + PDF_FILE; - - String dotExe = p.getProperty(WalaExamplesProperties.DOT_EXE); - DotUtil.dotify(g, null, PDFTypeHierarchy.DOT_FILE, pdfFile, dotExe); - - String gvExe = p.getProperty(WalaExamplesProperties.PDFVIEW_EXE); - return PDFViewUtil.launchPDFView(pdfFile, gvExe); - - } catch (WalaException e) { - e.printStackTrace(); - return null; - } catch (IOException e) { - e.printStackTrace(); - return null; - } - } - - /** - * @param appJar something like "c:/temp/testdata/java_cup.jar" - * @return a call graph - * @throws CancelException - * @throws IllegalArgumentException - * @throws IOException - */ - public static Graph buildPrunedCallGraph(String appJar, File exclusionFile) throws WalaException, - IllegalArgumentException, CancelException, IOException { - AnalysisScope scope = AnalysisScopeReader.makeJavaBinaryAnalysisScope(appJar, exclusionFile != null ? exclusionFile : new File( - CallGraphTestUtil.REGRESSION_EXCLUSIONS)); - - ClassHierarchy cha = ClassHierarchy.make(scope); - - Iterable entrypoints = com.ibm.wala.ipa.callgraph.impl.Util.makeMainEntrypoints(scope, cha); - AnalysisOptions options = new AnalysisOptions(scope, entrypoints); - - // // - // build the call graph - // // - com.ibm.wala.ipa.callgraph.CallGraphBuilder builder = Util.makeZeroCFABuilder(options, new AnalysisCache(), cha, scope); - CallGraph cg = builder.makeCallGraph(options, null); - - System.err.println(CallGraphStats.getStats(cg)); - - Graph g = pruneForAppLoader(cg); - - return g; - } - - public static Graph pruneForAppLoader(CallGraph g) throws WalaException { - return PDFTypeHierarchy.pruneGraph(g, new ApplicationLoaderFilter()); - } - - /** - * Validate that the command-line arguments obey the expected usage. - * - * Usage: - *
    - *
  • args[0] : "-appJar" - *
  • args[1] : something like "c:/temp/testdata/java_cup.jar" - *
  • {@link CGNode} - *
  • {@link LocalPointerKey} - *
- */ - private static class ApplicationLoaderFilter implements Filter { - - public boolean accepts(CGNode o) { - if (o instanceof CGNode) { - CGNode n = (CGNode) o; - return n.getMethod().getDeclaringClass().getClassLoader().getReference().equals(ClassLoaderReference.Application); - } else if (o instanceof LocalPointerKey) { - LocalPointerKey l = (LocalPointerKey) o; - return accepts(l.getNode()); - } else { - return false; - } - } - } -} +/******************************************************************************* + * 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.examples.drivers; + +import java.io.File; +import java.io.IOException; +import java.util.Collection; +import java.util.Iterator; +import java.util.Properties; + +import com.ibm.wala.core.tests.callGraph.CallGraphTestUtil; +import com.ibm.wala.examples.properties.WalaExamplesProperties; +import com.ibm.wala.ipa.callgraph.AnalysisCache; +import com.ibm.wala.ipa.callgraph.AnalysisOptions; +import com.ibm.wala.ipa.callgraph.AnalysisScope; +import com.ibm.wala.ipa.callgraph.CGNode; +import com.ibm.wala.ipa.callgraph.CallGraph; +import com.ibm.wala.ipa.callgraph.CallGraphStats; +import com.ibm.wala.ipa.callgraph.Entrypoint; +import com.ibm.wala.ipa.callgraph.impl.Util; +import com.ibm.wala.ipa.callgraph.propagation.LocalPointerKey; +import com.ibm.wala.ipa.cha.ClassHierarchy; +import com.ibm.wala.properties.WalaProperties; +import com.ibm.wala.types.ClassLoaderReference; +import com.ibm.wala.util.CancelException; +import com.ibm.wala.util.WalaException; +import com.ibm.wala.util.collections.Filter; +import com.ibm.wala.util.collections.HashSetFactory; +import com.ibm.wala.util.config.AnalysisScopeReader; +import com.ibm.wala.util.debug.Assertions; +import com.ibm.wala.util.graph.Graph; +import com.ibm.wala.util.io.CommandLine; +import com.ibm.wala.util.io.FileProvider; +import com.ibm.wala.util.io.FileUtil; +import com.ibm.wala.viz.DotUtil; +import com.ibm.wala.viz.PDFViewUtil; + +/** + * This simple example WALA application builds a call graph and fires off ghostview to visualize a DOT representation. + */ +public class PDFCallGraph { + public static boolean isDirectory(String appJar) { + return (new File(appJar).isDirectory()); + } + + public static String findJarFiles(String[] directories) throws WalaException { + Collection result = HashSetFactory.make(); + for (int i = 0; i < directories.length; i++) { + for (Iterator it = FileUtil.listFiles(directories[i], ".*\\.jar", true).iterator(); it.hasNext();) { + File f = (File) it.next(); + result.add(f.getAbsolutePath()); + } + } + return composeString(result); + } + + private static String composeString(Collection s) { + StringBuffer result = new StringBuffer(); + Iterator it = s.iterator(); + for (int i = 0; i < s.size() - 1; i++) { + result.append(it.next()); + result.append(File.pathSeparator); + } + if (it.hasNext()) { + result.append(it.next()); + } + return result.toString(); + } + + private final static String PDF_FILE = "cg.pdf"; + + /** + * Usage: args = "-appJar [jar file name] {-exclusionFile [exclusionFileName]}" The "jar file name" should be something like + * "c:/temp/testdata/java_cup.jar" + * + * @throws CancelException + * @throws IllegalArgumentException + */ + public static void main(String[] args) throws WalaException, IllegalArgumentException, CancelException { + run(args); + } + + /** + * Usage: args = "-appJar [jar file name] {-exclusionFile [exclusionFileName]}" The "jar file name" should be something like + * "c:/temp/testdata/java_cup.jar" + * + * @throws CancelException + * @throws IllegalArgumentException + */ + public static Process run(String[] args) throws WalaException, IllegalArgumentException, CancelException { + Properties p = CommandLine.parse(args); + validateCommandLine(p); + return run(p.getProperty("appJar"), p.getProperty("exclusionFile", CallGraphTestUtil.REGRESSION_EXCLUSIONS)); + } + + /** + * @param appJar something like "c:/temp/testdata/java_cup.jar" + * @throws CancelException + * @throws IllegalArgumentException + */ + public static Process run(String appJar, String exclusionFile) throws IllegalArgumentException, CancelException { + try { + Graph g = buildPrunedCallGraph(appJar, (new FileProvider()).getFile(exclusionFile)); + + Properties p = null; + try { + p = WalaExamplesProperties.loadProperties(); + p.putAll(WalaProperties.loadProperties()); + } catch (WalaException e) { + e.printStackTrace(); + Assertions.UNREACHABLE(); + } + String pdfFile = p.getProperty(WalaProperties.OUTPUT_DIR) + File.separatorChar + PDF_FILE; + + String dotExe = p.getProperty(WalaExamplesProperties.DOT_EXE); + DotUtil.dotify(g, null, PDFTypeHierarchy.DOT_FILE, pdfFile, dotExe); + + String gvExe = p.getProperty(WalaExamplesProperties.PDFVIEW_EXE); + return PDFViewUtil.launchPDFView(pdfFile, gvExe); + + } catch (WalaException e) { + e.printStackTrace(); + return null; + } catch (IOException e) { + e.printStackTrace(); + return null; + } + } + + /** + * @param appJar something like "c:/temp/testdata/java_cup.jar" + * @return a call graph + * @throws CancelException + * @throws IllegalArgumentException + * @throws IOException + */ + public static Graph buildPrunedCallGraph(String appJar, File exclusionFile) throws WalaException, + IllegalArgumentException, CancelException, IOException { + AnalysisScope scope = AnalysisScopeReader.makeJavaBinaryAnalysisScope(appJar, exclusionFile != null ? exclusionFile : new File( + CallGraphTestUtil.REGRESSION_EXCLUSIONS)); + + ClassHierarchy cha = ClassHierarchy.make(scope); + + Iterable entrypoints = com.ibm.wala.ipa.callgraph.impl.Util.makeMainEntrypoints(scope, cha); + AnalysisOptions options = new AnalysisOptions(scope, entrypoints); + + // // + // build the call graph + // // + com.ibm.wala.ipa.callgraph.CallGraphBuilder builder = Util.makeZeroCFABuilder(options, new AnalysisCache(), cha, scope); + CallGraph cg = builder.makeCallGraph(options, null); + + System.err.println(CallGraphStats.getStats(cg)); + + Graph g = pruneForAppLoader(cg); + + return g; + } + + public static Graph pruneForAppLoader(CallGraph g) throws WalaException { + return PDFTypeHierarchy.pruneGraph(g, new ApplicationLoaderFilter()); + } + + /** + * Validate that the command-line arguments obey the expected usage. + * + * Usage: + *
    + *
  • args[0] : "-appJar" + *
  • args[1] : something like "c:/temp/testdata/java_cup.jar" + *
  • {@link CGNode} + *
  • {@link LocalPointerKey} + *
+ */ + private static class ApplicationLoaderFilter implements Filter { + + public boolean accepts(CGNode o) { + if (o instanceof CGNode) { + CGNode n = (CGNode) o; + return n.getMethod().getDeclaringClass().getClassLoader().getReference().equals(ClassLoaderReference.Application); + } else if (o instanceof LocalPointerKey) { + LocalPointerKey l = (LocalPointerKey) o; + return accepts(l.getNode()); + } else { + return false; + } + } + } +} diff --git a/com.ibm.wala.core.tests/src/com/ibm/wala/examples/drivers/PDFControlDependenceGraph.java b/com.ibm.wala.core.tests/src/com/ibm/wala/examples/drivers/PDFControlDependenceGraph.java index 445f93aeb..804e424ba 100644 --- a/com.ibm.wala.core.tests/src/com/ibm/wala/examples/drivers/PDFControlDependenceGraph.java +++ b/com.ibm.wala.core.tests/src/com/ibm/wala/examples/drivers/PDFControlDependenceGraph.java @@ -1,163 +1,163 @@ -/******************************************************************************* - * 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.examples.drivers; - -import java.io.File; -import java.io.IOException; -import java.util.Properties; - -import com.ibm.wala.cfg.cdg.ControlDependenceGraph; -import com.ibm.wala.classLoader.IMethod; -import com.ibm.wala.core.tests.callGraph.CallGraphTestUtil; -import com.ibm.wala.examples.properties.WalaExamplesProperties; -import com.ibm.wala.ipa.callgraph.AnalysisCache; -import com.ibm.wala.ipa.callgraph.AnalysisOptions; -import com.ibm.wala.ipa.callgraph.AnalysisScope; -import com.ibm.wala.ipa.callgraph.impl.Everywhere; -import com.ibm.wala.ipa.cha.ClassHierarchy; -import com.ibm.wala.properties.WalaProperties; -import com.ibm.wala.ssa.IR; -import com.ibm.wala.ssa.ISSABasicBlock; -import com.ibm.wala.ssa.SSAInstruction; -import com.ibm.wala.ssa.SSAOptions; -import com.ibm.wala.types.MethodReference; -import com.ibm.wala.util.WalaException; -import com.ibm.wala.util.config.AnalysisScopeReader; -import com.ibm.wala.util.debug.Assertions; -import com.ibm.wala.util.io.FileProvider; -import com.ibm.wala.util.strings.StringStuff; -import com.ibm.wala.viz.DotUtil; -import com.ibm.wala.viz.PDFViewUtil; - -/** - * - * This simple example application builds a WALA CDG and fires off ghostview - * to viz a DOT representation. - * - * @author sfink - */ -public class PDFControlDependenceGraph { - - final public static boolean SANITIZE_CFG = false; - - final public static String PDF_FILE = "cdg.pdf"; - - /** - * Usage: GVControlDependenceGraph -appJar [jar file name] -sig [method signature] The "jar - * file name" should be something like "c:/temp/testdata/java_cup.jar" The - * signature should be something like "java_cup.lexer.advance()V" - * - * @param args - * @throws IOException - */ - public static void main(String[] args) throws IOException { - - run(args); - } - - /** - * @param args - * -appJar [jar file name] -sig [method signature] The "jar file - * name" should be something like "c:/temp/testdata/java_cup.jar" The - * signature should be something like "java_cup.lexer.advance()V" - * @throws IOException - */ - public static Process run(String[] args) throws IOException { - validateCommandLine(args); - return run(args[1], args[3]); - } - - /** - * @param appJar - * should be something like "c:/temp/testdata/java_cup.jar" - * @param methodSig - * should be something like "java_cup.lexer.advance()V" - * @throws IOException - */ - public static Process run(String appJar, String methodSig) throws IOException { - try { - if (PDFCallGraph.isDirectory(appJar)) { - appJar = PDFCallGraph.findJarFiles(new String[] { appJar }); - } - AnalysisScope scope = AnalysisScopeReader.makeJavaBinaryAnalysisScope(appJar, (new FileProvider()).getFile(CallGraphTestUtil.REGRESSION_EXCLUSIONS)); - - ClassHierarchy cha = ClassHierarchy.make(scope); - - MethodReference mr = StringStuff.makeMethodReference(methodSig); - - IMethod m = cha.resolveMethod(mr); - if (m == null) { - System.err.println("could not resolve " + mr); - throw new RuntimeException(); - } - AnalysisOptions options = new AnalysisOptions(); - options.getSSAOptions().setPiNodePolicy(SSAOptions.getAllBuiltInPiNodes()); - AnalysisCache cache = new AnalysisCache(); - IR ir = cache.getSSACache().findOrCreateIR(m, Everywhere.EVERYWHERE, options.getSSAOptions() ); - - if (ir == null) { - Assertions.UNREACHABLE("Null IR for " + m); - } - - System.err.println(ir.toString()); - ControlDependenceGraph cdg = new ControlDependenceGraph(ir.getControlFlowGraph()); - - Properties wp = null; - try { - wp = WalaProperties.loadProperties(); - wp.putAll(WalaExamplesProperties.loadProperties()); - } catch (WalaException e) { - e.printStackTrace(); - Assertions.UNREACHABLE(); - } - String psFile = wp.getProperty(WalaProperties.OUTPUT_DIR) + File.separatorChar + PDFControlDependenceGraph.PDF_FILE; - String dotFile = wp.getProperty(WalaProperties.OUTPUT_DIR) + File.separatorChar - + PDFTypeHierarchy.DOT_FILE; - String dotExe = wp.getProperty(WalaExamplesProperties.DOT_EXE); - String gvExe = wp.getProperty(WalaExamplesProperties.PDFVIEW_EXE); - - DotUtil.dotify(cdg, PDFViewUtil.makeIRDecorator(ir), dotFile, psFile, dotExe); - - return PDFViewUtil.launchPDFView(psFile, gvExe); - - } catch (WalaException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - return null; - } - } - - /** - * Validate that the command-line arguments obey the expected usage. - * - * Usage: - *
    - *
  • args[0] : "-appJar" - *
  • args[1] : something like "c:/temp/testdata/java_cup.jar" - *
  • args[2] : "-sig" - *
  • args[3] : a method signature like "java_cup.lexer.advance()V" cdg = new ControlDependenceGraph(ir.getControlFlowGraph()); + + Properties wp = null; + try { + wp = WalaProperties.loadProperties(); + wp.putAll(WalaExamplesProperties.loadProperties()); + } catch (WalaException e) { + e.printStackTrace(); + Assertions.UNREACHABLE(); + } + String psFile = wp.getProperty(WalaProperties.OUTPUT_DIR) + File.separatorChar + PDFControlDependenceGraph.PDF_FILE; + String dotFile = wp.getProperty(WalaProperties.OUTPUT_DIR) + File.separatorChar + + PDFTypeHierarchy.DOT_FILE; + String dotExe = wp.getProperty(WalaExamplesProperties.DOT_EXE); + String gvExe = wp.getProperty(WalaExamplesProperties.PDFVIEW_EXE); + + DotUtil.dotify(cdg, PDFViewUtil.makeIRDecorator(ir), dotFile, psFile, dotExe); + + return PDFViewUtil.launchPDFView(psFile, gvExe); + + } catch (WalaException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + return null; + } + } + + /** + * Validate that the command-line arguments obey the expected usage. + * + * Usage: + *
      + *
    • args[0] : "-appJar" + *
    • args[1] : something like "c:/temp/testdata/java_cup.jar" + *
    • args[2] : "-sig" + *
    • args[3] : a method signature like "java_cup.lexer.advance()V" entrypoints = com.ibm.wala.ipa.callgraph.impl.Util.makeMainEntrypoints(scope, cha, mainClass); - AnalysisOptions options = CallGraphTestUtil.makeAnalysisOptions(scope, entrypoints); - - CallGraphBuilder builder = Util.makeZeroOneCFABuilder(options, new AnalysisCache(), cha, scope); - CallGraph cg = builder.makeCallGraph(options,null); - SDG sdg = new SDG(cg, builder.getPointerAnalysis(), dOptions, cOptions); - try { - GraphIntegrity.check(sdg); - } catch (UnsoundGraphException e1) { - e1.printStackTrace(); - Assertions.UNREACHABLE(); - } - System.err.println(sdg); - - Properties p = null; - try { - p = WalaExamplesProperties.loadProperties(); - p.putAll(WalaProperties.loadProperties()); - } catch (WalaException e) { - e.printStackTrace(); - Assertions.UNREACHABLE(); - } - String psFile = p.getProperty(WalaProperties.OUTPUT_DIR) + File.separatorChar + PDF_FILE; - - String dotExe = p.getProperty(WalaExamplesProperties.DOT_EXE); - Graph g = pruneSDG(sdg); - DotUtil.dotify(g, makeNodeDecorator(), PDFTypeHierarchy.DOT_FILE, psFile, dotExe); - - String gvExe = p.getProperty(WalaExamplesProperties.PDFVIEW_EXE); - return PDFViewUtil.launchPDFView(psFile, gvExe); - - } catch (WalaException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - return null; - } - } - - private static Graph pruneSDG(final SDG sdg) { - Filter f = new Filter() { - public boolean accepts(Statement o) { - Statement s = (Statement) o; - if (s.getNode().equals(sdg.getCallGraph().getFakeRootNode())) { - return false; - } else if (s instanceof MethodExitStatement || s instanceof MethodEntryStatement) { - return false; - } else { - return true; - } - } - }; - return GraphSlicer.prune(sdg, f); - } - - private static NodeDecorator makeNodeDecorator() { - return new NodeDecorator() { - public String getLabel(Object o) throws WalaException { - Statement s = (Statement) o; - switch (s.getKind()) { - case HEAP_PARAM_CALLEE: - case HEAP_PARAM_CALLER: - case HEAP_RET_CALLEE: - case HEAP_RET_CALLER: - HeapStatement h = (HeapStatement) s; - return s.getKind() + "\\n" + h.getNode() + "\\n" + h.getLocation(); - case EXC_RET_CALLEE: - case EXC_RET_CALLER: - case NORMAL: - case NORMAL_RET_CALLEE: - case NORMAL_RET_CALLER: - case PARAM_CALLEE: - case PARAM_CALLER: - case PHI: - default: - return s.toString(); - } - } - - }; - } - - /** - * Validate that the command-line arguments obey the expected usage. - * - * Usage: - *
        - *
      • args[0] : "-appJar" - *
      • args[1] : something like "c:/temp/testdata/java_cup.jar" - *
      • args[2] : "-mainClass" - *
      • args[3] : something like "Lslice/TestRecursion" - * - * @throws UnsupportedOperationException - * if command-line is malformed. - */ - static void validateCommandLine(Properties p) { - if (p.get("appJar") == null) { - throw new UnsupportedOperationException("expected command-line to include -appJar"); - } - if (p.get("mainClass") == null) { - throw new UnsupportedOperationException("expected command-line to include -appJar"); - } - } +/******************************************************************************* + * 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.examples.drivers; + +import java.io.File; +import java.io.IOException; +import java.util.Properties; + +import com.ibm.wala.core.tests.callGraph.CallGraphTestUtil; +import com.ibm.wala.examples.properties.WalaExamplesProperties; +import com.ibm.wala.ipa.callgraph.AnalysisCache; +import com.ibm.wala.ipa.callgraph.AnalysisOptions; +import com.ibm.wala.ipa.callgraph.AnalysisScope; +import com.ibm.wala.ipa.callgraph.CallGraph; +import com.ibm.wala.ipa.callgraph.CallGraphBuilder; +import com.ibm.wala.ipa.callgraph.Entrypoint; +import com.ibm.wala.ipa.callgraph.impl.Util; +import com.ibm.wala.ipa.cha.ClassHierarchy; +import com.ibm.wala.ipa.slicer.HeapStatement; +import com.ibm.wala.ipa.slicer.MethodEntryStatement; +import com.ibm.wala.ipa.slicer.MethodExitStatement; +import com.ibm.wala.ipa.slicer.SDG; +import com.ibm.wala.ipa.slicer.Slicer.ControlDependenceOptions; +import com.ibm.wala.ipa.slicer.Slicer.DataDependenceOptions; +import com.ibm.wala.ipa.slicer.Statement; +import com.ibm.wala.properties.WalaProperties; +import com.ibm.wala.util.CancelException; +import com.ibm.wala.util.WalaException; +import com.ibm.wala.util.collections.Filter; +import com.ibm.wala.util.config.AnalysisScopeReader; +import com.ibm.wala.util.debug.Assertions; +import com.ibm.wala.util.graph.Graph; +import com.ibm.wala.util.graph.GraphIntegrity; +import com.ibm.wala.util.graph.GraphIntegrity.UnsoundGraphException; +import com.ibm.wala.util.graph.GraphSlicer; +import com.ibm.wala.util.io.CommandLine; +import com.ibm.wala.util.io.FileProvider; +import com.ibm.wala.viz.DotUtil; +import com.ibm.wala.viz.NodeDecorator; +import com.ibm.wala.viz.PDFViewUtil; + +/** + * + * This simple example WALA application builds an SDG and fires off ghostview to + * viz a DOT representation. + * + * @author sfink + */ +public class PDFSDG { + + private final static String PDF_FILE = "sdg.pdf"; + + /** + * Usage: GVSDG -appJar [jar file name] -mainclass [main class] + * + * The "jar file name" should be something like + * "c:/temp/testdata/java_cup.jar" + * + * @param args + * @throws WalaException + * @throws CancelException + * @throws IllegalArgumentException + * @throws IOException + */ + public static void main(String[] args) throws WalaException, IllegalArgumentException, CancelException, IOException { + run(args); + } + + /** + * @throws WalaException + * @throws CancelException + * @throws IllegalArgumentException + * @throws IOException + */ + public static Process run(String[] args) throws WalaException, IllegalArgumentException, CancelException, IOException { + Properties p = CommandLine.parse(args); + validateCommandLine(p); + return run(p.getProperty("appJar"), p.getProperty("mainClass"), getDataDependenceOptions(p), getControlDependenceOptions(p)); + } + + public static DataDependenceOptions getDataDependenceOptions(Properties p) { + String d = p.getProperty("dd", "full"); + for (DataDependenceOptions result : DataDependenceOptions.values()) { + if (d.equals(result.getName())) { + return result; + } + } + Assertions.UNREACHABLE("unknown data datapendence option: " + d); + return null; + } + + public static ControlDependenceOptions getControlDependenceOptions(Properties p) { + String d = p.getProperty("cd", "full"); + for (ControlDependenceOptions result : ControlDependenceOptions.values()) { + if (d.equals(result.getName())) { + return result; + } + } + Assertions.UNREACHABLE("unknown control datapendence option: " + d); + return null; + } + + /** + * @param appJar + * something like "c:/temp/testdata/java_cup.jar" + * @throws CancelException + * @throws IllegalArgumentException + * @throws IOException + */ + public static Process run(String appJar, String mainClass, DataDependenceOptions dOptions, ControlDependenceOptions cOptions) throws IllegalArgumentException, CancelException, IOException { + try { + AnalysisScope scope = AnalysisScopeReader.makeJavaBinaryAnalysisScope(appJar, (new FileProvider()).getFile(CallGraphTestUtil.REGRESSION_EXCLUSIONS)); + + // generate a WALA-consumable wrapper around the incoming scope object + + ClassHierarchy cha = ClassHierarchy.make(scope); + Iterable entrypoints = com.ibm.wala.ipa.callgraph.impl.Util.makeMainEntrypoints(scope, cha, mainClass); + AnalysisOptions options = CallGraphTestUtil.makeAnalysisOptions(scope, entrypoints); + + CallGraphBuilder builder = Util.makeZeroOneCFABuilder(options, new AnalysisCache(), cha, scope); + CallGraph cg = builder.makeCallGraph(options,null); + SDG sdg = new SDG(cg, builder.getPointerAnalysis(), dOptions, cOptions); + try { + GraphIntegrity.check(sdg); + } catch (UnsoundGraphException e1) { + e1.printStackTrace(); + Assertions.UNREACHABLE(); + } + System.err.println(sdg); + + Properties p = null; + try { + p = WalaExamplesProperties.loadProperties(); + p.putAll(WalaProperties.loadProperties()); + } catch (WalaException e) { + e.printStackTrace(); + Assertions.UNREACHABLE(); + } + String psFile = p.getProperty(WalaProperties.OUTPUT_DIR) + File.separatorChar + PDF_FILE; + + String dotExe = p.getProperty(WalaExamplesProperties.DOT_EXE); + Graph g = pruneSDG(sdg); + DotUtil.dotify(g, makeNodeDecorator(), PDFTypeHierarchy.DOT_FILE, psFile, dotExe); + + String gvExe = p.getProperty(WalaExamplesProperties.PDFVIEW_EXE); + return PDFViewUtil.launchPDFView(psFile, gvExe); + + } catch (WalaException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + return null; + } + } + + private static Graph pruneSDG(final SDG sdg) { + Filter f = new Filter() { + public boolean accepts(Statement o) { + Statement s = (Statement) o; + if (s.getNode().equals(sdg.getCallGraph().getFakeRootNode())) { + return false; + } else if (s instanceof MethodExitStatement || s instanceof MethodEntryStatement) { + return false; + } else { + return true; + } + } + }; + return GraphSlicer.prune(sdg, f); + } + + private static NodeDecorator makeNodeDecorator() { + return new NodeDecorator() { + public String getLabel(Object o) throws WalaException { + Statement s = (Statement) o; + switch (s.getKind()) { + case HEAP_PARAM_CALLEE: + case HEAP_PARAM_CALLER: + case HEAP_RET_CALLEE: + case HEAP_RET_CALLER: + HeapStatement h = (HeapStatement) s; + return s.getKind() + "\\n" + h.getNode() + "\\n" + h.getLocation(); + case EXC_RET_CALLEE: + case EXC_RET_CALLER: + case NORMAL: + case NORMAL_RET_CALLEE: + case NORMAL_RET_CALLER: + case PARAM_CALLEE: + case PARAM_CALLER: + case PHI: + default: + return s.toString(); + } + } + + }; + } + + /** + * Validate that the command-line arguments obey the expected usage. + * + * Usage: + *
          + *
        • args[0] : "-appJar" + *
        • args[1] : something like "c:/temp/testdata/java_cup.jar" + *
        • args[2] : "-mainClass" + *
        • args[3] : something like "Lslice/TestRecursion" + * + * @throws UnsupportedOperationException + * if command-line is malformed. + */ + static void validateCommandLine(Properties p) { + if (p.get("appJar") == null) { + throw new UnsupportedOperationException("expected command-line to include -appJar"); + } + if (p.get("mainClass") == null) { + throw new UnsupportedOperationException("expected command-line to include -appJar"); + } + } } \ No newline at end of file diff --git a/com.ibm.wala.core.tests/src/com/ibm/wala/examples/drivers/PDFSlice.java b/com.ibm.wala.core.tests/src/com/ibm/wala/examples/drivers/PDFSlice.java index a08a1b8f8..c73e11cb3 100644 --- a/com.ibm.wala.core.tests/src/com/ibm/wala/examples/drivers/PDFSlice.java +++ b/com.ibm.wala.core.tests/src/com/ibm/wala/examples/drivers/PDFSlice.java @@ -1,323 +1,323 @@ -/******************************************************************************* - * 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.examples.drivers; - -import java.io.File; -import java.io.IOException; -import java.util.Collection; -import java.util.Properties; - -import com.ibm.wala.core.tests.callGraph.CallGraphTestUtil; -import com.ibm.wala.core.tests.slicer.SlicerTest; -import com.ibm.wala.examples.properties.WalaExamplesProperties; -import com.ibm.wala.ipa.callgraph.AnalysisCache; -import com.ibm.wala.ipa.callgraph.AnalysisOptions; -import com.ibm.wala.ipa.callgraph.AnalysisScope; -import com.ibm.wala.ipa.callgraph.CGNode; -import com.ibm.wala.ipa.callgraph.CallGraph; -import com.ibm.wala.ipa.callgraph.CallGraphBuilder; -import com.ibm.wala.ipa.callgraph.Entrypoint; -import com.ibm.wala.ipa.callgraph.impl.Util; -import com.ibm.wala.ipa.cha.ClassHierarchy; -import com.ibm.wala.ipa.slicer.HeapStatement; -import com.ibm.wala.ipa.slicer.NormalReturnCaller; -import com.ibm.wala.ipa.slicer.NormalStatement; -import com.ibm.wala.ipa.slicer.ParamCallee; -import com.ibm.wala.ipa.slicer.ParamCaller; -import com.ibm.wala.ipa.slicer.SDG; -import com.ibm.wala.ipa.slicer.Slicer; -import com.ibm.wala.ipa.slicer.Slicer.ControlDependenceOptions; -import com.ibm.wala.ipa.slicer.Slicer.DataDependenceOptions; -import com.ibm.wala.ipa.slicer.Statement; -import com.ibm.wala.ipa.slicer.Statement.Kind; -import com.ibm.wala.properties.WalaProperties; -import com.ibm.wala.ssa.SSAAbstractInvokeInstruction; -import com.ibm.wala.ssa.SSAInstruction; -import com.ibm.wala.ssa.SSAInvokeInstruction; -import com.ibm.wala.types.TypeReference; -import com.ibm.wala.util.CancelException; -import com.ibm.wala.util.WalaException; -import com.ibm.wala.util.collections.Filter; -import com.ibm.wala.util.config.AnalysisScopeReader; -import com.ibm.wala.util.debug.Assertions; -import com.ibm.wala.util.graph.Graph; -import com.ibm.wala.util.graph.GraphIntegrity; -import com.ibm.wala.util.graph.GraphIntegrity.UnsoundGraphException; -import com.ibm.wala.util.graph.GraphSlicer; -import com.ibm.wala.util.io.CommandLine; -import com.ibm.wala.util.io.FileProvider; -import com.ibm.wala.viz.DotUtil; -import com.ibm.wala.viz.NodeDecorator; -import com.ibm.wala.viz.PDFViewUtil; - -/** - * - * This simple example WALA application computes a slice (see {@link Slicer}) and fires off the PDF viewer to view a dot-ted - * representation of the slice. - * - * This is an example program on how to use the slicer. - * - * See the 'PDFSlice' launcher included in the 'launchers' directory. - * - * @see Slicer - * @author sfink - */ -public class PDFSlice { - - /** - * Name of the postscript file generated by dot - */ - private final static String PDF_FILE = "slice.pdf"; - - /** - * Usage: PDFSlice -appJar [jar file name] -mainClass [main class] -srcCaller [method name] -srcCallee [method name] -dd [data - * dependence options] -cd [control dependence options] -dir [forward|backward] - * - *
            - *
          • "jar file name" should be something like "c:/temp/testdata/java_cup.jar" - *
          • "main class" should beshould be something like "c:/temp/testdata/java_cup.jar" - *
          • "method name" should be the name of a method. This takes a slice from the statement that calls "srcCallee" from "srcCaller" - *
          • "data dependence options" can be one of "-full", "-no_base_ptrs", "-no_base_no_heap", "-no_heap", - * "-no_base_no_heap_no_cast", or "-none". - *
          - * - * @throws CancelException - * @throws IllegalArgumentException - * @throws IOException - * - * @see com.ibm.wala.ipa.slicer.Slicer.DataDependenceOptions
        • "control dependence options" can be "-full" or "-none"
        • the - * -dir argument tells whether to compute a forwards or backwards slice.
        - * - */ - public static void main(String[] args) throws WalaException, IllegalArgumentException, CancelException, IOException { - run(args); - } - - /** - * see {@link #main(String[])} for command-line arguments - * - * @throws CancelException - * @throws IllegalArgumentException - * @throws IOException - */ - public static Process run(String[] args) throws WalaException, IllegalArgumentException, CancelException, IOException { - // parse the command-line into a Properties object - Properties p = CommandLine.parse(args); - // validate that the command-line has the expected format - validateCommandLine(p); - - // run the applications - return run(p.getProperty("appJar"), p.getProperty("mainClass"), p.getProperty("srcCaller"), p.getProperty("srcCallee"), - goBackward(p), PDFSDG.getDataDependenceOptions(p), PDFSDG.getControlDependenceOptions(p)); - } - - /** - * Should the slice be a backwards slice? - */ - private static boolean goBackward(Properties p) { - return !p.getProperty("dir", "backward").equals("forward"); - } - - /** - * Compute a slice from a call statements, dot it, and fire off the PDF viewer to visualize the result - * - * @param appJar should be something like "c:/temp/testdata/java_cup.jar" - * @param mainClass should be something like "c:/temp/testdata/java_cup.jar" - * @param srcCaller name of the method containing the statement of interest - * @param srcCallee name of the method called by the statement of interest - * @param goBackward do a backward slice? - * @param dOptions options controlling data dependence - * @param cOptions options controlling control dependence - * @return a Process running the PDF viewer to visualize the dot'ted representation of the slice - * @throws CancelException - * @throws IllegalArgumentException - */ - public static Process run(String appJar, String mainClass, String srcCaller, String srcCallee, boolean goBackward, - DataDependenceOptions dOptions, ControlDependenceOptions cOptions) throws IllegalArgumentException, CancelException, - IOException { - try { - // create an analysis scope representing the appJar as a J2SE application - AnalysisScope scope = AnalysisScopeReader.makeJavaBinaryAnalysisScope(appJar, (new FileProvider()) - .getFile(CallGraphTestUtil.REGRESSION_EXCLUSIONS)); - - // build a class hierarchy, call graph, and system dependence graph - ClassHierarchy cha = ClassHierarchy.make(scope); - Iterable entrypoints = com.ibm.wala.ipa.callgraph.impl.Util.makeMainEntrypoints(scope, cha, mainClass); - AnalysisOptions options = CallGraphTestUtil.makeAnalysisOptions(scope, entrypoints); - CallGraphBuilder builder = Util.makeVanillaZeroOneCFABuilder(options, new AnalysisCache(), cha, scope); - // CallGraphBuilder builder = Util.makeZeroOneCFABuilder(options, new - // AnalysisCache(), cha, scope); - CallGraph cg = builder.makeCallGraph(options, null); - SDG sdg = new SDG(cg, builder.getPointerAnalysis(), dOptions, cOptions); - - // find the call statement of interest - CGNode callerNode = SlicerTest.findMethod(cg, srcCaller); - Statement s = SlicerTest.findCallTo(callerNode, srcCallee); - System.err.println("Statement: " + s); - - // compute the slice as a collection of statements - Collection slice = null; - if (goBackward) { - slice = Slicer.computeBackwardSlice(s, cg, builder.getPointerAnalysis(), dOptions, cOptions); - } else { - // for forward slices ... we actually slice from the return value of - // calls. - s = getReturnStatementForCall(s); - slice = Slicer.computeForwardSlice(s, cg, builder.getPointerAnalysis(), dOptions, cOptions); - } - SlicerTest.dumpSlice(slice); - - // create a view of the SDG restricted to nodes in the slice - Graph g = pruneSDG(sdg, slice); - - sanityCheck(slice, g); - - // load Properties from standard WALA and the WALA examples project - Properties p = null; - try { - p = WalaExamplesProperties.loadProperties(); - p.putAll(WalaProperties.loadProperties()); - } catch (WalaException e) { - e.printStackTrace(); - Assertions.UNREACHABLE(); - } - // create a dot representation. - String psFile = p.getProperty(WalaProperties.OUTPUT_DIR) + File.separatorChar + PDF_FILE; - String dotExe = p.getProperty(WalaExamplesProperties.DOT_EXE); - DotUtil.dotify(g, makeNodeDecorator(), PDFTypeHierarchy.DOT_FILE, psFile, dotExe); - - // fire off the PDF viewer - String gvExe = p.getProperty(WalaExamplesProperties.PDFVIEW_EXE); - return PDFViewUtil.launchPDFView(psFile, gvExe); - - } catch (WalaException e) { - // something bad happened. - e.printStackTrace(); - return null; - } - } - - /** - * check that g is a well-formed graph, and that it contains exactly the number of nodes in the slice - */ - private static void sanityCheck(Collection slice, Graph g) { - try { - GraphIntegrity.check(g); - } catch (UnsoundGraphException e1) { - e1.printStackTrace(); - Assertions.UNREACHABLE(); - } - Assertions.productionAssertion(g.getNumberOfNodes() == slice.size(), "panic " + g.getNumberOfNodes() + " " + slice.size()); - } - - /** - * If s is a call statement, return the statement representing the normal return from s - */ - public static Statement getReturnStatementForCall(Statement s) { - if (s.getKind() == Kind.NORMAL) { - NormalStatement n = (NormalStatement) s; - SSAInstruction st = n.getInstruction(); - if (st instanceof SSAInvokeInstruction) { - SSAAbstractInvokeInstruction call = (SSAAbstractInvokeInstruction) st; - if (call.getCallSite().getDeclaredTarget().getReturnType().equals(TypeReference.Void)) { - throw new IllegalArgumentException("this driver computes forward slices from the return value of calls.\n" + "" - + "Method " + call.getCallSite().getDeclaredTarget().getSignature() + " returns void."); - } - return new NormalReturnCaller(s.getNode(), n.getInstructionIndex()); - } else { - return s; - } - } else { - return s; - } - } - - /** - * return a view of the sdg restricted to the statements in the slice - */ - public static Graph pruneSDG(SDG sdg, final Collection slice) { - Filter f = new Filter() { - public boolean accepts(Statement o) { - return slice.contains(o); - } - }; - return GraphSlicer.prune(sdg, f); - } - - /** - * @return a NodeDecorator that decorates statements in a slice for a dot-ted representation - */ - public static NodeDecorator makeNodeDecorator() { - return new NodeDecorator() { - public String getLabel(Object o) throws WalaException { - Statement s = (Statement) o; - switch (s.getKind()) { - case HEAP_PARAM_CALLEE: - case HEAP_PARAM_CALLER: - case HEAP_RET_CALLEE: - case HEAP_RET_CALLER: - HeapStatement h = (HeapStatement) s; - return s.getKind() + "\\n" + h.getNode() + "\\n" + h.getLocation(); - case NORMAL: - NormalStatement n = (NormalStatement) s; - return n.getInstruction() + "\\n" + n.getNode().getMethod().getSignature(); - case PARAM_CALLEE: - ParamCallee paramCallee = (ParamCallee) s; - return s.getKind() + " " + paramCallee.getValueNumber() + "\\n" + s.getNode().getMethod().getName(); - case PARAM_CALLER: - ParamCaller paramCaller = (ParamCaller) s; - return s.getKind() + " " + paramCaller.getValueNumber() + "\\n" + s.getNode().getMethod().getName() + "\\n" - + paramCaller.getInstruction().getCallSite().getDeclaredTarget().getName(); - case EXC_RET_CALLEE: - case EXC_RET_CALLER: - case NORMAL_RET_CALLEE: - case NORMAL_RET_CALLER: - case PHI: - default: - return s.toString(); - } - } - - }; - } - - /** - * Validate that the command-line arguments obey the expected usage. - * - * Usage: - *
          - *
        • args[0] : "-appJar" - *
        • args[1] : something like "c:/temp/testdata/java_cup.jar" - *
        • args[2] : "-mainClass" - *
        • args[3] : something like "Lslice/TestRecursion" * - *
        • args[4] : "-srcCallee" - *
        • args[5] : something like "print" * - *
        • args[4] : "-srcCaller" - *
        • args[5] : something like "main" - *
        - * - * @throws UnsupportedOperationException if command-line is malformed. - */ - static void validateCommandLine(Properties p) { - if (p.get("appJar") == null) { - throw new UnsupportedOperationException("expected command-line to include -appJar"); - } - if (p.get("mainClass") == null) { - throw new UnsupportedOperationException("expected command-line to include -mainClass"); - } - if (p.get("srcCallee") == null) { - throw new UnsupportedOperationException("expected command-line to include -srcCallee"); - } - if (p.get("srcCaller") == null) { - throw new UnsupportedOperationException("expected command-line to include -srcCaller"); - } - } +/******************************************************************************* + * 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.examples.drivers; + +import java.io.File; +import java.io.IOException; +import java.util.Collection; +import java.util.Properties; + +import com.ibm.wala.core.tests.callGraph.CallGraphTestUtil; +import com.ibm.wala.core.tests.slicer.SlicerTest; +import com.ibm.wala.examples.properties.WalaExamplesProperties; +import com.ibm.wala.ipa.callgraph.AnalysisCache; +import com.ibm.wala.ipa.callgraph.AnalysisOptions; +import com.ibm.wala.ipa.callgraph.AnalysisScope; +import com.ibm.wala.ipa.callgraph.CGNode; +import com.ibm.wala.ipa.callgraph.CallGraph; +import com.ibm.wala.ipa.callgraph.CallGraphBuilder; +import com.ibm.wala.ipa.callgraph.Entrypoint; +import com.ibm.wala.ipa.callgraph.impl.Util; +import com.ibm.wala.ipa.cha.ClassHierarchy; +import com.ibm.wala.ipa.slicer.HeapStatement; +import com.ibm.wala.ipa.slicer.NormalReturnCaller; +import com.ibm.wala.ipa.slicer.NormalStatement; +import com.ibm.wala.ipa.slicer.ParamCallee; +import com.ibm.wala.ipa.slicer.ParamCaller; +import com.ibm.wala.ipa.slicer.SDG; +import com.ibm.wala.ipa.slicer.Slicer; +import com.ibm.wala.ipa.slicer.Slicer.ControlDependenceOptions; +import com.ibm.wala.ipa.slicer.Slicer.DataDependenceOptions; +import com.ibm.wala.ipa.slicer.Statement; +import com.ibm.wala.ipa.slicer.Statement.Kind; +import com.ibm.wala.properties.WalaProperties; +import com.ibm.wala.ssa.SSAAbstractInvokeInstruction; +import com.ibm.wala.ssa.SSAInstruction; +import com.ibm.wala.ssa.SSAInvokeInstruction; +import com.ibm.wala.types.TypeReference; +import com.ibm.wala.util.CancelException; +import com.ibm.wala.util.WalaException; +import com.ibm.wala.util.collections.Filter; +import com.ibm.wala.util.config.AnalysisScopeReader; +import com.ibm.wala.util.debug.Assertions; +import com.ibm.wala.util.graph.Graph; +import com.ibm.wala.util.graph.GraphIntegrity; +import com.ibm.wala.util.graph.GraphIntegrity.UnsoundGraphException; +import com.ibm.wala.util.graph.GraphSlicer; +import com.ibm.wala.util.io.CommandLine; +import com.ibm.wala.util.io.FileProvider; +import com.ibm.wala.viz.DotUtil; +import com.ibm.wala.viz.NodeDecorator; +import com.ibm.wala.viz.PDFViewUtil; + +/** + * + * This simple example WALA application computes a slice (see {@link Slicer}) and fires off the PDF viewer to view a dot-ted + * representation of the slice. + * + * This is an example program on how to use the slicer. + * + * See the 'PDFSlice' launcher included in the 'launchers' directory. + * + * @see Slicer + * @author sfink + */ +public class PDFSlice { + + /** + * Name of the postscript file generated by dot + */ + private final static String PDF_FILE = "slice.pdf"; + + /** + * Usage: PDFSlice -appJar [jar file name] -mainClass [main class] -srcCaller [method name] -srcCallee [method name] -dd [data + * dependence options] -cd [control dependence options] -dir [forward|backward] + * + *
          + *
        • "jar file name" should be something like "c:/temp/testdata/java_cup.jar" + *
        • "main class" should beshould be something like "c:/temp/testdata/java_cup.jar" + *
        • "method name" should be the name of a method. This takes a slice from the statement that calls "srcCallee" from "srcCaller" + *
        • "data dependence options" can be one of "-full", "-no_base_ptrs", "-no_base_no_heap", "-no_heap", + * "-no_base_no_heap_no_cast", or "-none". + *
        + * + * @throws CancelException + * @throws IllegalArgumentException + * @throws IOException + * + * @see com.ibm.wala.ipa.slicer.Slicer.DataDependenceOptions
      • "control dependence options" can be "-full" or "-none"
      • the + * -dir argument tells whether to compute a forwards or backwards slice.
      + * + */ + public static void main(String[] args) throws WalaException, IllegalArgumentException, CancelException, IOException { + run(args); + } + + /** + * see {@link #main(String[])} for command-line arguments + * + * @throws CancelException + * @throws IllegalArgumentException + * @throws IOException + */ + public static Process run(String[] args) throws WalaException, IllegalArgumentException, CancelException, IOException { + // parse the command-line into a Properties object + Properties p = CommandLine.parse(args); + // validate that the command-line has the expected format + validateCommandLine(p); + + // run the applications + return run(p.getProperty("appJar"), p.getProperty("mainClass"), p.getProperty("srcCaller"), p.getProperty("srcCallee"), + goBackward(p), PDFSDG.getDataDependenceOptions(p), PDFSDG.getControlDependenceOptions(p)); + } + + /** + * Should the slice be a backwards slice? + */ + private static boolean goBackward(Properties p) { + return !p.getProperty("dir", "backward").equals("forward"); + } + + /** + * Compute a slice from a call statements, dot it, and fire off the PDF viewer to visualize the result + * + * @param appJar should be something like "c:/temp/testdata/java_cup.jar" + * @param mainClass should be something like "c:/temp/testdata/java_cup.jar" + * @param srcCaller name of the method containing the statement of interest + * @param srcCallee name of the method called by the statement of interest + * @param goBackward do a backward slice? + * @param dOptions options controlling data dependence + * @param cOptions options controlling control dependence + * @return a Process running the PDF viewer to visualize the dot'ted representation of the slice + * @throws CancelException + * @throws IllegalArgumentException + */ + public static Process run(String appJar, String mainClass, String srcCaller, String srcCallee, boolean goBackward, + DataDependenceOptions dOptions, ControlDependenceOptions cOptions) throws IllegalArgumentException, CancelException, + IOException { + try { + // create an analysis scope representing the appJar as a J2SE application + AnalysisScope scope = AnalysisScopeReader.makeJavaBinaryAnalysisScope(appJar, (new FileProvider()) + .getFile(CallGraphTestUtil.REGRESSION_EXCLUSIONS)); + + // build a class hierarchy, call graph, and system dependence graph + ClassHierarchy cha = ClassHierarchy.make(scope); + Iterable entrypoints = com.ibm.wala.ipa.callgraph.impl.Util.makeMainEntrypoints(scope, cha, mainClass); + AnalysisOptions options = CallGraphTestUtil.makeAnalysisOptions(scope, entrypoints); + CallGraphBuilder builder = Util.makeVanillaZeroOneCFABuilder(options, new AnalysisCache(), cha, scope); + // CallGraphBuilder builder = Util.makeZeroOneCFABuilder(options, new + // AnalysisCache(), cha, scope); + CallGraph cg = builder.makeCallGraph(options, null); + SDG sdg = new SDG(cg, builder.getPointerAnalysis(), dOptions, cOptions); + + // find the call statement of interest + CGNode callerNode = SlicerTest.findMethod(cg, srcCaller); + Statement s = SlicerTest.findCallTo(callerNode, srcCallee); + System.err.println("Statement: " + s); + + // compute the slice as a collection of statements + Collection slice = null; + if (goBackward) { + slice = Slicer.computeBackwardSlice(s, cg, builder.getPointerAnalysis(), dOptions, cOptions); + } else { + // for forward slices ... we actually slice from the return value of + // calls. + s = getReturnStatementForCall(s); + slice = Slicer.computeForwardSlice(s, cg, builder.getPointerAnalysis(), dOptions, cOptions); + } + SlicerTest.dumpSlice(slice); + + // create a view of the SDG restricted to nodes in the slice + Graph g = pruneSDG(sdg, slice); + + sanityCheck(slice, g); + + // load Properties from standard WALA and the WALA examples project + Properties p = null; + try { + p = WalaExamplesProperties.loadProperties(); + p.putAll(WalaProperties.loadProperties()); + } catch (WalaException e) { + e.printStackTrace(); + Assertions.UNREACHABLE(); + } + // create a dot representation. + String psFile = p.getProperty(WalaProperties.OUTPUT_DIR) + File.separatorChar + PDF_FILE; + String dotExe = p.getProperty(WalaExamplesProperties.DOT_EXE); + DotUtil.dotify(g, makeNodeDecorator(), PDFTypeHierarchy.DOT_FILE, psFile, dotExe); + + // fire off the PDF viewer + String gvExe = p.getProperty(WalaExamplesProperties.PDFVIEW_EXE); + return PDFViewUtil.launchPDFView(psFile, gvExe); + + } catch (WalaException e) { + // something bad happened. + e.printStackTrace(); + return null; + } + } + + /** + * check that g is a well-formed graph, and that it contains exactly the number of nodes in the slice + */ + private static void sanityCheck(Collection slice, Graph g) { + try { + GraphIntegrity.check(g); + } catch (UnsoundGraphException e1) { + e1.printStackTrace(); + Assertions.UNREACHABLE(); + } + Assertions.productionAssertion(g.getNumberOfNodes() == slice.size(), "panic " + g.getNumberOfNodes() + " " + slice.size()); + } + + /** + * If s is a call statement, return the statement representing the normal return from s + */ + public static Statement getReturnStatementForCall(Statement s) { + if (s.getKind() == Kind.NORMAL) { + NormalStatement n = (NormalStatement) s; + SSAInstruction st = n.getInstruction(); + if (st instanceof SSAInvokeInstruction) { + SSAAbstractInvokeInstruction call = (SSAAbstractInvokeInstruction) st; + if (call.getCallSite().getDeclaredTarget().getReturnType().equals(TypeReference.Void)) { + throw new IllegalArgumentException("this driver computes forward slices from the return value of calls.\n" + "" + + "Method " + call.getCallSite().getDeclaredTarget().getSignature() + " returns void."); + } + return new NormalReturnCaller(s.getNode(), n.getInstructionIndex()); + } else { + return s; + } + } else { + return s; + } + } + + /** + * return a view of the sdg restricted to the statements in the slice + */ + public static Graph pruneSDG(SDG sdg, final Collection slice) { + Filter f = new Filter() { + public boolean accepts(Statement o) { + return slice.contains(o); + } + }; + return GraphSlicer.prune(sdg, f); + } + + /** + * @return a NodeDecorator that decorates statements in a slice for a dot-ted representation + */ + public static NodeDecorator makeNodeDecorator() { + return new NodeDecorator() { + public String getLabel(Object o) throws WalaException { + Statement s = (Statement) o; + switch (s.getKind()) { + case HEAP_PARAM_CALLEE: + case HEAP_PARAM_CALLER: + case HEAP_RET_CALLEE: + case HEAP_RET_CALLER: + HeapStatement h = (HeapStatement) s; + return s.getKind() + "\\n" + h.getNode() + "\\n" + h.getLocation(); + case NORMAL: + NormalStatement n = (NormalStatement) s; + return n.getInstruction() + "\\n" + n.getNode().getMethod().getSignature(); + case PARAM_CALLEE: + ParamCallee paramCallee = (ParamCallee) s; + return s.getKind() + " " + paramCallee.getValueNumber() + "\\n" + s.getNode().getMethod().getName(); + case PARAM_CALLER: + ParamCaller paramCaller = (ParamCaller) s; + return s.getKind() + " " + paramCaller.getValueNumber() + "\\n" + s.getNode().getMethod().getName() + "\\n" + + paramCaller.getInstruction().getCallSite().getDeclaredTarget().getName(); + case EXC_RET_CALLEE: + case EXC_RET_CALLER: + case NORMAL_RET_CALLEE: + case NORMAL_RET_CALLER: + case PHI: + default: + return s.toString(); + } + } + + }; + } + + /** + * Validate that the command-line arguments obey the expected usage. + * + * Usage: + *
        + *
      • args[0] : "-appJar" + *
      • args[1] : something like "c:/temp/testdata/java_cup.jar" + *
      • args[2] : "-mainClass" + *
      • args[3] : something like "Lslice/TestRecursion" * + *
      • args[4] : "-srcCallee" + *
      • args[5] : something like "print" * + *
      • args[4] : "-srcCaller" + *
      • args[5] : something like "main" + *
      + * + * @throws UnsupportedOperationException if command-line is malformed. + */ + static void validateCommandLine(Properties p) { + if (p.get("appJar") == null) { + throw new UnsupportedOperationException("expected command-line to include -appJar"); + } + if (p.get("mainClass") == null) { + throw new UnsupportedOperationException("expected command-line to include -mainClass"); + } + if (p.get("srcCallee") == null) { + throw new UnsupportedOperationException("expected command-line to include -srcCallee"); + } + if (p.get("srcCaller") == null) { + throw new UnsupportedOperationException("expected command-line to include -srcCaller"); + } + } } \ No newline at end of file diff --git a/com.ibm.wala.core.tests/src/com/ibm/wala/examples/drivers/PDFTypeHierarchy.java b/com.ibm.wala.core.tests/src/com/ibm/wala/examples/drivers/PDFTypeHierarchy.java index eb01049ce..bbcb500ed 100644 --- a/com.ibm.wala.core.tests/src/com/ibm/wala/examples/drivers/PDFTypeHierarchy.java +++ b/com.ibm.wala.core.tests/src/com/ibm/wala/examples/drivers/PDFTypeHierarchy.java @@ -1,149 +1,149 @@ -/******************************************************************************* - * 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.examples.drivers; - -import java.io.File; -import java.io.IOException; -import java.util.Collection; -import java.util.Properties; - -import com.ibm.wala.classLoader.IClass; -import com.ibm.wala.core.tests.callGraph.CallGraphTestUtil; -import com.ibm.wala.examples.properties.WalaExamplesProperties; -import com.ibm.wala.ipa.callgraph.AnalysisScope; -import com.ibm.wala.ipa.cha.ClassHierarchy; -import com.ibm.wala.ipa.cha.IClassHierarchy; -import com.ibm.wala.properties.WalaProperties; -import com.ibm.wala.types.ClassLoaderReference; -import com.ibm.wala.util.WalaException; -import com.ibm.wala.util.collections.CollectionFilter; -import com.ibm.wala.util.collections.Filter; -import com.ibm.wala.util.config.AnalysisScopeReader; -import com.ibm.wala.util.debug.Assertions; -import com.ibm.wala.util.graph.Graph; -import com.ibm.wala.util.graph.GraphSlicer; -import com.ibm.wala.util.graph.impl.SlowSparseNumberedGraph; -import com.ibm.wala.util.io.FileProvider; -import com.ibm.wala.viz.DotUtil; -import com.ibm.wala.viz.PDFViewUtil; - -/** - * - * This simple example WALA application builds a TypeHierarchy and fires off - * ghostview to viz a DOT representation. - * - * @author sfink - */ -public class PDFTypeHierarchy { - // This example takes one command-line argument, so args[1] should be the "-classpath" parameter - final static int CLASSPATH_INDEX = 1; - - public final static String DOT_FILE = "temp.dt"; - - private final static String PDF_FILE = "th.pdf"; - - public static Properties p; - - static { - try { - p = WalaProperties.loadProperties(); - p.putAll(WalaExamplesProperties.loadProperties()); - } catch (WalaException e) { - e.printStackTrace(); - Assertions.UNREACHABLE(); - } - - } - - public static void main(String[] args) throws IOException { - run(args); - } - - public static Process run(String[] args) throws IOException { - try { - validateCommandLine(args); - String classpath = args[CLASSPATH_INDEX]; - AnalysisScope scope = AnalysisScopeReader.makeJavaBinaryAnalysisScope(classpath, (new FileProvider()).getFile(CallGraphTestUtil.REGRESSION_EXCLUSIONS)); - - // invoke WALA to build a class hierarchy - ClassHierarchy cha = ClassHierarchy.make(scope); - - Graph g = typeHierarchy2Graph(cha); - - g = pruneForAppLoader(g); - String dotFile = p.getProperty(WalaProperties.OUTPUT_DIR) + File.separatorChar + DOT_FILE; - String pdfFile = p.getProperty(WalaProperties.OUTPUT_DIR) + File.separatorChar + PDF_FILE; - String dotExe = p.getProperty(WalaExamplesProperties.DOT_EXE); - String gvExe = p.getProperty(WalaExamplesProperties.PDFVIEW_EXE); - DotUtil.dotify(g, null, dotFile, pdfFile, dotExe); - return PDFViewUtil.launchPDFView(pdfFile, gvExe); - - } catch (WalaException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - return null; - } - } - - public static Graph pruneGraph(Graph g, Filter f) throws WalaException { - Collection slice = GraphSlicer.slice(g, f); - return GraphSlicer.prune(g, new CollectionFilter(slice)); - } - - /** - * Restrict g to nodes from the Application loader - */ - public static Graph pruneForAppLoader(Graph g) throws WalaException { - Filter f = new Filter() { - public boolean accepts(IClass c) { - return (c.getClassLoader().getReference().equals(ClassLoaderReference.Application)); - } - }; - return pruneGraph(g, f); - } - - /** - * Validate that the command-line arguments obey the expected usage. - * - * Usage: args[0] : "-classpath" args[1] : String, a ";"-delimited class path - * - * @throws UnsupportedOperationException if command-line is malformed. - */ - public static void validateCommandLine(String[] args) { - if (args.length < 2) { - throw new UnsupportedOperationException("must have at least 2 command-line arguments"); - } - if (!args[0].equals("-classpath")) { - throw new UnsupportedOperationException("invalid command-line, args[0] should be -classpath, but is " + args[0]); - } - } - - /** - * Return a view of an {@link IClassHierarchy} as a {@link Graph}, with edges from classes to immediate subtypes - */ - public static Graph typeHierarchy2Graph(IClassHierarchy cha) throws WalaException { - Graph result = SlowSparseNumberedGraph.make(); - for (IClass c : cha) { - result.addNode(c); - } - for (IClass c : cha) { - for (IClass x : cha.getImmediateSubclasses(c)) { - result.addEdge(c, x); - } - if (c.isInterface()) { - for (IClass x : cha.getImplementors(c.getReference())) { - result.addEdge(c, x); - } - } - } - return result; - } +/******************************************************************************* + * 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.examples.drivers; + +import java.io.File; +import java.io.IOException; +import java.util.Collection; +import java.util.Properties; + +import com.ibm.wala.classLoader.IClass; +import com.ibm.wala.core.tests.callGraph.CallGraphTestUtil; +import com.ibm.wala.examples.properties.WalaExamplesProperties; +import com.ibm.wala.ipa.callgraph.AnalysisScope; +import com.ibm.wala.ipa.cha.ClassHierarchy; +import com.ibm.wala.ipa.cha.IClassHierarchy; +import com.ibm.wala.properties.WalaProperties; +import com.ibm.wala.types.ClassLoaderReference; +import com.ibm.wala.util.WalaException; +import com.ibm.wala.util.collections.CollectionFilter; +import com.ibm.wala.util.collections.Filter; +import com.ibm.wala.util.config.AnalysisScopeReader; +import com.ibm.wala.util.debug.Assertions; +import com.ibm.wala.util.graph.Graph; +import com.ibm.wala.util.graph.GraphSlicer; +import com.ibm.wala.util.graph.impl.SlowSparseNumberedGraph; +import com.ibm.wala.util.io.FileProvider; +import com.ibm.wala.viz.DotUtil; +import com.ibm.wala.viz.PDFViewUtil; + +/** + * + * This simple example WALA application builds a TypeHierarchy and fires off + * ghostview to viz a DOT representation. + * + * @author sfink + */ +public class PDFTypeHierarchy { + // This example takes one command-line argument, so args[1] should be the "-classpath" parameter + final static int CLASSPATH_INDEX = 1; + + public final static String DOT_FILE = "temp.dt"; + + private final static String PDF_FILE = "th.pdf"; + + public static Properties p; + + static { + try { + p = WalaProperties.loadProperties(); + p.putAll(WalaExamplesProperties.loadProperties()); + } catch (WalaException e) { + e.printStackTrace(); + Assertions.UNREACHABLE(); + } + + } + + public static void main(String[] args) throws IOException { + run(args); + } + + public static Process run(String[] args) throws IOException { + try { + validateCommandLine(args); + String classpath = args[CLASSPATH_INDEX]; + AnalysisScope scope = AnalysisScopeReader.makeJavaBinaryAnalysisScope(classpath, (new FileProvider()).getFile(CallGraphTestUtil.REGRESSION_EXCLUSIONS)); + + // invoke WALA to build a class hierarchy + ClassHierarchy cha = ClassHierarchy.make(scope); + + Graph g = typeHierarchy2Graph(cha); + + g = pruneForAppLoader(g); + String dotFile = p.getProperty(WalaProperties.OUTPUT_DIR) + File.separatorChar + DOT_FILE; + String pdfFile = p.getProperty(WalaProperties.OUTPUT_DIR) + File.separatorChar + PDF_FILE; + String dotExe = p.getProperty(WalaExamplesProperties.DOT_EXE); + String gvExe = p.getProperty(WalaExamplesProperties.PDFVIEW_EXE); + DotUtil.dotify(g, null, dotFile, pdfFile, dotExe); + return PDFViewUtil.launchPDFView(pdfFile, gvExe); + + } catch (WalaException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + return null; + } + } + + public static Graph pruneGraph(Graph g, Filter f) throws WalaException { + Collection slice = GraphSlicer.slice(g, f); + return GraphSlicer.prune(g, new CollectionFilter(slice)); + } + + /** + * Restrict g to nodes from the Application loader + */ + public static Graph pruneForAppLoader(Graph g) throws WalaException { + Filter f = new Filter() { + public boolean accepts(IClass c) { + return (c.getClassLoader().getReference().equals(ClassLoaderReference.Application)); + } + }; + return pruneGraph(g, f); + } + + /** + * Validate that the command-line arguments obey the expected usage. + * + * Usage: args[0] : "-classpath" args[1] : String, a ";"-delimited class path + * + * @throws UnsupportedOperationException if command-line is malformed. + */ + public static void validateCommandLine(String[] args) { + if (args.length < 2) { + throw new UnsupportedOperationException("must have at least 2 command-line arguments"); + } + if (!args[0].equals("-classpath")) { + throw new UnsupportedOperationException("invalid command-line, args[0] should be -classpath, but is " + args[0]); + } + } + + /** + * Return a view of an {@link IClassHierarchy} as a {@link Graph}, with edges from classes to immediate subtypes + */ + public static Graph typeHierarchy2Graph(IClassHierarchy cha) throws WalaException { + Graph result = SlowSparseNumberedGraph.make(); + for (IClass c : cha) { + result.addNode(c); + } + for (IClass c : cha) { + for (IClass x : cha.getImmediateSubclasses(c)) { + result.addEdge(c, x); + } + if (c.isInterface()) { + for (IClass x : cha.getImplementors(c.getReference())) { + result.addEdge(c, x); + } + } + } + return result; + } } \ No newline at end of file diff --git a/com.ibm.wala.core.tests/src/com/ibm/wala/examples/drivers/PDFWalaIR.java b/com.ibm.wala.core.tests/src/com/ibm/wala/examples/drivers/PDFWalaIR.java index 6cc17d800..0e34a419a 100644 --- a/com.ibm.wala.core.tests/src/com/ibm/wala/examples/drivers/PDFWalaIR.java +++ b/com.ibm.wala.core.tests/src/com/ibm/wala/examples/drivers/PDFWalaIR.java @@ -1,154 +1,154 @@ -/******************************************************************************* - * 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.examples.drivers; - -import java.io.File; -import java.io.IOException; -import java.util.Properties; - -import com.ibm.wala.classLoader.IMethod; -import com.ibm.wala.core.tests.callGraph.CallGraphTestUtil; -import com.ibm.wala.examples.properties.WalaExamplesProperties; -import com.ibm.wala.ipa.callgraph.AnalysisCache; -import com.ibm.wala.ipa.callgraph.AnalysisOptions; -import com.ibm.wala.ipa.callgraph.AnalysisScope; -import com.ibm.wala.ipa.callgraph.impl.Everywhere; -import com.ibm.wala.ipa.cha.ClassHierarchy; -import com.ibm.wala.properties.WalaProperties; -import com.ibm.wala.ssa.IR; -import com.ibm.wala.ssa.SSAOptions; -import com.ibm.wala.types.MethodReference; -import com.ibm.wala.util.WalaException; -import com.ibm.wala.util.config.AnalysisScopeReader; -import com.ibm.wala.util.debug.Assertions; -import com.ibm.wala.util.io.FileProvider; -import com.ibm.wala.util.strings.StringStuff; -import com.ibm.wala.viz.PDFViewUtil; - -/** - * This simple example application builds a WALA IR and fires off a PDF viewer to visualize a DOT representation. - */ -public class PDFWalaIR { - - final public static String PDF_FILE = "ir.pdf"; - - /** - * Usage: PDFWalaIR -appJar [jar file name] -sig [method signature] The "jar file - * name" should be something like "c:/temp/testdata/java_cup.jar" The signature should be something like - * "java_cup.lexer.advance()V" - */ - public static void main(String[] args) throws IOException { - run(args); - } - - /** - * @param args -appJar [jar file name] -sig [method signature] The "jar file - * name" should be something like "c:/temp/testdata/java_cup.jar" The signature should be something like - * "java_cup.lexer.advance()V" - */ - public static Process run(String[] args) throws IOException { - validateCommandLine(args); - return run(args[1], args[3]); - } - - /** - * @param appJar should be something like "c:/temp/testdata/java_cup.jar" - * @param methodSig should be something like "java_cup.lexer.advance()V" - * @throws IOException - */ - public static Process run(String appJar, String methodSig) throws IOException { - try { - if (PDFCallGraph.isDirectory(appJar)) { - appJar = PDFCallGraph.findJarFiles(new String[] { appJar }); - } - - // Build an AnalysisScope which represents the set of classes to analyze. In particular, - // we will analyze the contents of the appJar jar file and the Java standard libraries. - AnalysisScope scope = AnalysisScopeReader.makeJavaBinaryAnalysisScope(appJar, (new FileProvider()) - .getFile(CallGraphTestUtil.REGRESSION_EXCLUSIONS)); - - // Build a class hierarchy representing all classes to analyze. This step will read the class - // files and organize them into a tree. - ClassHierarchy cha = ClassHierarchy.make(scope); - - // Create a name representing the method whose IR we will visualize - MethodReference mr = StringStuff.makeMethodReference(methodSig); - - // Resolve the method name into the IMethod, the canonical representation of the method information. - IMethod m = cha.resolveMethod(mr); - if (m == null) { - Assertions.UNREACHABLE("could not resolve " + mr); - } - - // Set up options which govern analysis choices. In particular, we will use all Pi nodes when - // building the IR. - AnalysisOptions options = new AnalysisOptions(); - options.getSSAOptions().setPiNodePolicy(SSAOptions.getAllBuiltInPiNodes()); - - // Create an object which caches IRs and related information, reconstructing them lazily on demand. - AnalysisCache cache = new AnalysisCache(); - - // Build the IR and cache it. - IR ir = cache.getSSACache().findOrCreateIR(m, Everywhere.EVERYWHERE, options.getSSAOptions()); - - if (ir == null) { - Assertions.UNREACHABLE("Null IR for " + m); - } - - System.err.println(ir.toString()); - - Properties wp = null; - try { - wp = WalaProperties.loadProperties(); - wp.putAll(WalaExamplesProperties.loadProperties()); - } catch (WalaException e) { - e.printStackTrace(); - Assertions.UNREACHABLE(); - } - String psFile = wp.getProperty(WalaProperties.OUTPUT_DIR) + File.separatorChar + PDFWalaIR.PDF_FILE; - String dotFile = wp.getProperty(WalaProperties.OUTPUT_DIR) + File.separatorChar + PDFTypeHierarchy.DOT_FILE; - String dotExe = wp.getProperty(WalaExamplesProperties.DOT_EXE); - String gvExe = wp.getProperty(WalaExamplesProperties.PDFVIEW_EXE); - - return PDFViewUtil.ghostviewIR(cha, ir, psFile, dotFile, dotExe, gvExe); - - } catch (WalaException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - return null; - } - } - - /** - * Validate that the command-line arguments obey the expected usage. - * - * Usage: - *
        - *
      • args[0] : "-appJar" - *
      • args[1] : something like "c:/temp/testdata/java_cup.jar" - *
      • args[2] : "-sig" - *
      • args[3] : a method signature like "java_cup.lexer.advance()V" + *
      • args[0] : "-appJar" + *
      • args[1] : something like "c:/temp/testdata/java_cup.jar" + *
      • args[2] : "-sig" + *
      • args[3] : a method signature like "java_cup.lexer.advance()V" G; - - /** - * governing call graph - */ - private final CallGraph callGraph; - - /** - * @param P governing pointer analysis - * @throws NullPointerException if P is null - */ - public BasicHeapGraph(final PointerAnalysis P, final CallGraph callGraph) throws NullPointerException { - super(P); - this.callGraph = callGraph; - - final OrdinalSetMapping pointerKeys = getPointerKeys(); - final NumberedNodeManager nodeMgr = new NumberedNodeManager() { - public Iterator iterator() { - return new CompoundIterator(pointerKeys.iterator(), P.getInstanceKeyMapping().iterator()); - } - - public int getNumberOfNodes() { - return pointerKeys.getSize() + P.getInstanceKeyMapping().getSize(); - } - - 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 (!(N instanceof InstanceKey)) { - Assertions.UNREACHABLE(N.getClass().toString()); - } - int inumber = P.getInstanceKeyMapping().getMappedIndex((InstanceKey) N); - return (inumber == -1) ? -1 : inumber + pointerKeys.getMaximumIndex() + 1; - } - } - - public Object getNode(int number) { - if (number > pointerKeys.getMaximumIndex()) { - return P.getInstanceKeyMapping().getMappedObject(number - pointerKeys.getSize()); - } else { - return pointerKeys.getMappedObject(number); - } - } - - public int getMaxNumber() { - return getNumberOfNodes() - 1; - } - - public boolean containsNode(Object n) { - return getNumber(n) != -1; - } - - public Iterator iterateNodes(IntSet s) { - return new NumberedNodeIterator(s, this); - } - }; - - final IBinaryNaturalRelation pred = computePredecessors(nodeMgr); - final IntFunction toNode = new IntFunction() { - public Object apply(int i) { - return nodeMgr.getNode(i); - } - }; - - this.G = new AbstractNumberedGraph() { - private final NumberedEdgeManager edgeMgr = new NumberedEdgeManager() { - public Iterator getPredNodes(Object N) { - int n = nodeMgr.getNumber(N); - IntSet p = pred.getRelated(n); - if (p == null) { - return EmptyIterator.instance(); - } else { - return new IntMapIterator(p.intIterator(), toNode); - } - } - - public IntSet getPredNodeNumbers(Object N) { - int n = nodeMgr.getNumber(N); - IntSet p = pred.getRelated(n); - if (p != null) { - return p; - } else { - return IntSetUtil.make(); - } - } - - public int getPredNodeCount(Object N) { - int n = nodeMgr.getNumber(N); - return pred.getRelatedCount(n); - } - - public Iterator getSuccNodes(Object N) { - int[] succ = computeSuccNodeNumbers(N, nodeMgr); - if (succ == null) { - return EmptyIterator.instance(); - } - SparseIntSet s = factory.make(succ); - return new IntMapIterator(s.intIterator(), toNode); - } - - public IntSet getSuccNodeNumbers(Object N) { - int[] succ = computeSuccNodeNumbers(N, nodeMgr); - if (succ == null) { - return IntSetUtil.make(); - } else { - return IntSetUtil.make(succ); - } - } - - 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; - } - }; - - @Override - protected NumberedNodeManager getNodeManager() { - return nodeMgr; - } - - @Override - protected NumberedEdgeManager getEdgeManager() { - return edgeMgr; - } - }; - } - - private OrdinalSetMapping getPointerKeys() { - MutableMapping result = MutableMapping.make(); - - for (Iterator it = getPointerAnalysis().getPointerKeys().iterator(); it.hasNext();) { - PointerKey p = it.next(); - result.add(p); - } - return result; - - } - - private int[] computeSuccNodeNumbers(Object N, NumberedNodeManager nodeManager) { - if (N instanceof PointerKey) { - PointerKey P = (PointerKey) N; - OrdinalSet S = getPointerAnalysis().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 (T == null) { - 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 { - IClass klass = getHeapModel().getClassHierarchy().lookupClass(T); - if (klass == null) { - assert klass != null : "null klass for type " + T; - } - MutableSparseIntSet result = MutableSparseIntSet.makeEmpty(); - for (Iterator it = klass.getAllInstanceFields().iterator(); it.hasNext();) { - IField f = it.next(); - if (!f.getReference().getFieldType().isPrimitiveType()) { - PointerKey p = getHeapModel().getPointerKeyForInstanceField(I, f); - if (p != null && nodeManager.containsNode(p)) { - result.add(nodeManager.getNumber(p)); - } - } - } - return result.toIntArray(); - } - } 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 IBinaryNaturalRelation computePredecessors(NumberedNodeManager nodeManager) { - BasicNaturalRelation R = new BasicNaturalRelation(new byte[] { BasicNaturalRelation.SIMPLE }, BasicNaturalRelation.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 nodeManager, BasicNaturalRelation 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 nodeManager, BasicNaturalRelation R) { - - ArrayList list = new ArrayList(); - for (Iterator it = nodeManager.iterator(); 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 { - 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()); - } - } - } - - /* - * @see com.ibm.wala.util.graph.NumberedNodeManager#getNumber(com.ibm.wala.util.graph.Node) - */ - public int getNumber(Object N) { - return G.getNumber(N); - } - - /* - * @see com.ibm.wala.util.graph.NumberedNodeManager#getNode(int) - */ - public Object getNode(int number) { - return G.getNode(number); - } - - /* - * @see com.ibm.wala.util.graph.NumberedNodeManager#getMaxNumber() - */ - public int getMaxNumber() { - return G.getMaxNumber(); - } - - /* - * @see com.ibm.wala.util.graph.NodeManager#iterateNodes() - */ - public Iterator iterator() { - return G.iterator(); - } - - /* - * @see com.ibm.wala.util.graph.NodeManager#getNumberOfNodes() - */ - public int getNumberOfNodes() { - return G.getNumberOfNodes(); - } - - /* - * @see com.ibm.wala.util.graph.EdgeManager#getPredNodes(com.ibm.wala.util.graph.Node) - */ - public Iterator getPredNodes(Object N) { - return G.getPredNodes(N); - } - - /* - * @see com.ibm.wala.util.graph.EdgeManager#getPredNodeCount(com.ibm.wala.util.graph.Node) - */ - public int getPredNodeCount(Object N) { - return G.getPredNodeCount(N); - } - - /* - * @see com.ibm.wala.util.graph.EdgeManager#getSuccNodes(com.ibm.wala.util.graph.Node) - */ - public Iterator getSuccNodes(Object N) { - return G.getSuccNodes(N); - } - - /* - * @see com.ibm.wala.util.graph.EdgeManager#getSuccNodeCount(com.ibm.wala.util.graph.Node) - */ - public int getSuccNodeCount(Object N) { - return G.getSuccNodeCount(N); - } - - /* - * @see com.ibm.wala.util.graph.NodeManager#addNode(com.ibm.wala.util.graph.Node) - */ - public void addNode(Object n) throws UnimplementedError { - Assertions.UNREACHABLE(); - } - - /* - * @see com.ibm.wala.util.graph.NodeManager#remove(com.ibm.wala.util.graph.Node) - */ - public void removeNode(Object n) throws UnimplementedError { - Assertions.UNREACHABLE(); - } - - public void addEdge(Object from, Object to) throws UnimplementedError { - Assertions.UNREACHABLE(); - } - - public void removeEdge(Object from, Object to) throws UnimplementedError { - Assertions.UNREACHABLE(); - } - - public boolean hasEdge(Object from, Object to) throws UnimplementedError { - Assertions.UNREACHABLE(); - return false; - } - - public void removeAllIncidentEdges(Object node) throws UnsupportedOperationException { - throw new UnsupportedOperationException(); - } - - /* - * @see com.ibm.wala.util.graph.NodeManager#containsNode(com.ibm.wala.util.graph.Node) - */ - public boolean containsNode(Object N) { - return G.containsNode(N); - } - - @Override - 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(); - } - - public void removeIncomingEdges(Object node) throws UnimplementedError { - Assertions.UNREACHABLE(); - } - - public void removeOutgoingEdges(Object node) throws UnimplementedError { - Assertions.UNREACHABLE(); - } - - public IntSet getSuccNodeNumbers(Object node) throws UnimplementedError { - Assertions.UNREACHABLE(); - return null; - } - - public IntSet getPredNodeNumbers(Object node) throws UnimplementedError { - Assertions.UNREACHABLE(); - return null; - } -} +/******************************************************************************* + * 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.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.types.TypeReference; +import com.ibm.wala.util.collections.CompoundIterator; +import com.ibm.wala.util.collections.EmptyIterator; +import com.ibm.wala.util.collections.IntMapIterator; +import com.ibm.wala.util.debug.Assertions; +import com.ibm.wala.util.debug.UnimplementedError; +import com.ibm.wala.util.functions.IntFunction; +import com.ibm.wala.util.graph.AbstractNumberedGraph; +import com.ibm.wala.util.graph.NumberedEdgeManager; +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.BasicNaturalRelation; +import com.ibm.wala.util.intset.IBinaryNaturalRelation; +import com.ibm.wala.util.intset.IntSet; +import com.ibm.wala.util.intset.IntSetUtil; +import com.ibm.wala.util.intset.MutableMapping; +import com.ibm.wala.util.intset.MutableSparseIntSet; +import com.ibm.wala.util.intset.MutableSparseIntSetFactory; +import com.ibm.wala.util.intset.OrdinalSet; +import com.ibm.wala.util.intset.OrdinalSetMapping; +import com.ibm.wala.util.intset.SparseIntSet; + +/** + * Basic implementation of {@link HeapGraph} + */ +public class BasicHeapGraph extends HeapGraph { + + private final static boolean VERBOSE = false; + + private final static int VERBOSE_INTERVAL = 10000; + + private final static MutableSparseIntSetFactory factory = new MutableSparseIntSetFactory(); + + /** + * The backing graph + */ + private final NumberedGraph G; + + /** + * governing call graph + */ + private final CallGraph callGraph; + + /** + * @param P governing pointer analysis + * @throws NullPointerException if P is null + */ + public BasicHeapGraph(final PointerAnalysis P, final CallGraph callGraph) throws NullPointerException { + super(P); + this.callGraph = callGraph; + + final OrdinalSetMapping pointerKeys = getPointerKeys(); + final NumberedNodeManager nodeMgr = new NumberedNodeManager() { + public Iterator iterator() { + return new CompoundIterator(pointerKeys.iterator(), P.getInstanceKeyMapping().iterator()); + } + + public int getNumberOfNodes() { + return pointerKeys.getSize() + P.getInstanceKeyMapping().getSize(); + } + + 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 (!(N instanceof InstanceKey)) { + Assertions.UNREACHABLE(N.getClass().toString()); + } + int inumber = P.getInstanceKeyMapping().getMappedIndex((InstanceKey) N); + return (inumber == -1) ? -1 : inumber + pointerKeys.getMaximumIndex() + 1; + } + } + + public Object getNode(int number) { + if (number > pointerKeys.getMaximumIndex()) { + return P.getInstanceKeyMapping().getMappedObject(number - pointerKeys.getSize()); + } else { + return pointerKeys.getMappedObject(number); + } + } + + public int getMaxNumber() { + return getNumberOfNodes() - 1; + } + + public boolean containsNode(Object n) { + return getNumber(n) != -1; + } + + public Iterator iterateNodes(IntSet s) { + return new NumberedNodeIterator(s, this); + } + }; + + final IBinaryNaturalRelation pred = computePredecessors(nodeMgr); + final IntFunction toNode = new IntFunction() { + public Object apply(int i) { + return nodeMgr.getNode(i); + } + }; + + this.G = new AbstractNumberedGraph() { + private final NumberedEdgeManager edgeMgr = new NumberedEdgeManager() { + public Iterator getPredNodes(Object N) { + int n = nodeMgr.getNumber(N); + IntSet p = pred.getRelated(n); + if (p == null) { + return EmptyIterator.instance(); + } else { + return new IntMapIterator(p.intIterator(), toNode); + } + } + + public IntSet getPredNodeNumbers(Object N) { + int n = nodeMgr.getNumber(N); + IntSet p = pred.getRelated(n); + if (p != null) { + return p; + } else { + return IntSetUtil.make(); + } + } + + public int getPredNodeCount(Object N) { + int n = nodeMgr.getNumber(N); + return pred.getRelatedCount(n); + } + + public Iterator getSuccNodes(Object N) { + int[] succ = computeSuccNodeNumbers(N, nodeMgr); + if (succ == null) { + return EmptyIterator.instance(); + } + SparseIntSet s = factory.make(succ); + return new IntMapIterator(s.intIterator(), toNode); + } + + public IntSet getSuccNodeNumbers(Object N) { + int[] succ = computeSuccNodeNumbers(N, nodeMgr); + if (succ == null) { + return IntSetUtil.make(); + } else { + return IntSetUtil.make(succ); + } + } + + 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; + } + }; + + @Override + protected NumberedNodeManager getNodeManager() { + return nodeMgr; + } + + @Override + protected NumberedEdgeManager getEdgeManager() { + return edgeMgr; + } + }; + } + + private OrdinalSetMapping getPointerKeys() { + MutableMapping result = MutableMapping.make(); + + for (Iterator it = getPointerAnalysis().getPointerKeys().iterator(); it.hasNext();) { + PointerKey p = it.next(); + result.add(p); + } + return result; + + } + + private int[] computeSuccNodeNumbers(Object N, NumberedNodeManager nodeManager) { + if (N instanceof PointerKey) { + PointerKey P = (PointerKey) N; + OrdinalSet S = getPointerAnalysis().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 (T == null) { + 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 { + IClass klass = getHeapModel().getClassHierarchy().lookupClass(T); + if (klass == null) { + assert klass != null : "null klass for type " + T; + } + MutableSparseIntSet result = MutableSparseIntSet.makeEmpty(); + for (Iterator it = klass.getAllInstanceFields().iterator(); it.hasNext();) { + IField f = it.next(); + if (!f.getReference().getFieldType().isPrimitiveType()) { + PointerKey p = getHeapModel().getPointerKeyForInstanceField(I, f); + if (p != null && nodeManager.containsNode(p)) { + result.add(nodeManager.getNumber(p)); + } + } + } + return result.toIntArray(); + } + } 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 IBinaryNaturalRelation computePredecessors(NumberedNodeManager nodeManager) { + BasicNaturalRelation R = new BasicNaturalRelation(new byte[] { BasicNaturalRelation.SIMPLE }, BasicNaturalRelation.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 nodeManager, BasicNaturalRelation 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 nodeManager, BasicNaturalRelation R) { + + ArrayList list = new ArrayList(); + for (Iterator it = nodeManager.iterator(); 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 { + 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()); + } + } + } + + /* + * @see com.ibm.wala.util.graph.NumberedNodeManager#getNumber(com.ibm.wala.util.graph.Node) + */ + public int getNumber(Object N) { + return G.getNumber(N); + } + + /* + * @see com.ibm.wala.util.graph.NumberedNodeManager#getNode(int) + */ + public Object getNode(int number) { + return G.getNode(number); + } + + /* + * @see com.ibm.wala.util.graph.NumberedNodeManager#getMaxNumber() + */ + public int getMaxNumber() { + return G.getMaxNumber(); + } + + /* + * @see com.ibm.wala.util.graph.NodeManager#iterateNodes() + */ + public Iterator iterator() { + return G.iterator(); + } + + /* + * @see com.ibm.wala.util.graph.NodeManager#getNumberOfNodes() + */ + public int getNumberOfNodes() { + return G.getNumberOfNodes(); + } + + /* + * @see com.ibm.wala.util.graph.EdgeManager#getPredNodes(com.ibm.wala.util.graph.Node) + */ + public Iterator getPredNodes(Object N) { + return G.getPredNodes(N); + } + + /* + * @see com.ibm.wala.util.graph.EdgeManager#getPredNodeCount(com.ibm.wala.util.graph.Node) + */ + public int getPredNodeCount(Object N) { + return G.getPredNodeCount(N); + } + + /* + * @see com.ibm.wala.util.graph.EdgeManager#getSuccNodes(com.ibm.wala.util.graph.Node) + */ + public Iterator getSuccNodes(Object N) { + return G.getSuccNodes(N); + } + + /* + * @see com.ibm.wala.util.graph.EdgeManager#getSuccNodeCount(com.ibm.wala.util.graph.Node) + */ + public int getSuccNodeCount(Object N) { + return G.getSuccNodeCount(N); + } + + /* + * @see com.ibm.wala.util.graph.NodeManager#addNode(com.ibm.wala.util.graph.Node) + */ + public void addNode(Object n) throws UnimplementedError { + Assertions.UNREACHABLE(); + } + + /* + * @see com.ibm.wala.util.graph.NodeManager#remove(com.ibm.wala.util.graph.Node) + */ + public void removeNode(Object n) throws UnimplementedError { + Assertions.UNREACHABLE(); + } + + public void addEdge(Object from, Object to) throws UnimplementedError { + Assertions.UNREACHABLE(); + } + + public void removeEdge(Object from, Object to) throws UnimplementedError { + Assertions.UNREACHABLE(); + } + + public boolean hasEdge(Object from, Object to) throws UnimplementedError { + Assertions.UNREACHABLE(); + return false; + } + + public void removeAllIncidentEdges(Object node) throws UnsupportedOperationException { + throw new UnsupportedOperationException(); + } + + /* + * @see com.ibm.wala.util.graph.NodeManager#containsNode(com.ibm.wala.util.graph.Node) + */ + public boolean containsNode(Object N) { + return G.containsNode(N); + } + + @Override + 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(); + } + + public void removeIncomingEdges(Object node) throws UnimplementedError { + Assertions.UNREACHABLE(); + } + + public void removeOutgoingEdges(Object node) throws UnimplementedError { + Assertions.UNREACHABLE(); + } + + public IntSet getSuccNodeNumbers(Object node) throws UnimplementedError { + Assertions.UNREACHABLE(); + return null; + } + + public IntSet getPredNodeNumbers(Object node) throws UnimplementedError { + Assertions.UNREACHABLE(); + return null; + } +} diff --git a/com.ibm.wala.core/src/com/ibm/wala/analysis/pointers/HeapGraph.java b/com.ibm.wala.core/src/com/ibm/wala/analysis/pointers/HeapGraph.java index 7d514cf1f..9b3b242ce 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/analysis/pointers/HeapGraph.java +++ b/com.ibm.wala.core/src/com/ibm/wala/analysis/pointers/HeapGraph.java @@ -1,77 +1,77 @@ -/******************************************************************************* - * Copyright (c) 2002 - 2006 IBM Corporation. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * IBM Corporation - initial API and implementation - *******************************************************************************/ -package com.ibm.wala.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.ipa.callgraph.propagation.PointerAnalysis; -import com.ibm.wala.ipa.callgraph.propagation.PointerKey; -import com.ibm.wala.util.collections.Filter; -import com.ibm.wala.util.graph.Graph; -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 {@link Graph} view of a pointer analysis solution. - * - * Nodes in the Graph are {@link PointerKey}s and {@link InstanceKey}s. - * - * 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 modeled by I, or - P - * represents the array contents of array instance I. - */ -public abstract class HeapGraph implements NumberedGraph { - - private final PointerAnalysis pa; - - protected HeapGraph(PointerAnalysis pa) { - if (pa == null) { - throw new IllegalArgumentException("null pa "); - } - this.pa = pa; - } - - public Iterator iterateNodes(IntSet s) { - return new NumberedNodeIterator(s, this); - } - - public Collection getReachableInstances(Set roots) { - Filter f = new Filter() { - public boolean accepts(Object o) { - return (o instanceof InstanceKey); - } - }; - return DFS.getReachableNodes(this, roots, f); - } - - public void removeNodeAndEdges(Object N) throws UnsupportedOperationException { - throw new UnsupportedOperationException(); - } - - /** - * @return the heap model used in this pointer analysis. - */ - public HeapModel getHeapModel() { - return pa.getHeapModel(); - } - - public PointerAnalysis getPointerAnalysis() { - return pa; - } - -} +/******************************************************************************* + * 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.ipa.callgraph.propagation.PointerAnalysis; +import com.ibm.wala.ipa.callgraph.propagation.PointerKey; +import com.ibm.wala.util.collections.Filter; +import com.ibm.wala.util.graph.Graph; +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 {@link Graph} view of a pointer analysis solution. + * + * Nodes in the Graph are {@link PointerKey}s and {@link InstanceKey}s. + * + * 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 modeled by I, or - P + * represents the array contents of array instance I. + */ +public abstract class HeapGraph implements NumberedGraph { + + private final PointerAnalysis pa; + + protected HeapGraph(PointerAnalysis pa) { + if (pa == null) { + throw new IllegalArgumentException("null pa "); + } + this.pa = pa; + } + + public Iterator iterateNodes(IntSet s) { + return new NumberedNodeIterator(s, this); + } + + public Collection getReachableInstances(Set roots) { + Filter f = new Filter() { + public boolean accepts(Object o) { + return (o instanceof InstanceKey); + } + }; + return DFS.getReachableNodes(this, roots, f); + } + + public void removeNodeAndEdges(Object N) throws UnsupportedOperationException { + throw new UnsupportedOperationException(); + } + + /** + * @return the heap model used in this pointer analysis. + */ + public HeapModel getHeapModel() { + return pa.getHeapModel(); + } + + public PointerAnalysis getPointerAnalysis() { + return pa; + } + +} diff --git a/com.ibm.wala.core/src/com/ibm/wala/analysis/reflection/AbstractReflectionInterpreter.java b/com.ibm.wala.core/src/com/ibm/wala/analysis/reflection/AbstractReflectionInterpreter.java index cb298b77e..4b42dc984 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/analysis/reflection/AbstractReflectionInterpreter.java +++ b/com.ibm.wala.core/src/com/ibm/wala/analysis/reflection/AbstractReflectionInterpreter.java @@ -1,270 +1,270 @@ -/******************************************************************************* - * Copyright (c) 2008 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.io.Serializable; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.HashSet; -import java.util.Map; - -import com.ibm.wala.analysis.typeInference.ConeType; -import com.ibm.wala.analysis.typeInference.TypeAbstraction; -import com.ibm.wala.classLoader.CallSiteReference; -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.AnalysisCache; -import com.ibm.wala.ipa.callgraph.AnalysisOptions; -import com.ibm.wala.ipa.callgraph.propagation.SSAContextInterpreter; -import com.ibm.wala.ipa.cha.IClassHierarchy; -import com.ibm.wala.shrikeBT.IInvokeInstruction; -import com.ibm.wala.ssa.SSAInstruction; -import com.ibm.wala.ssa.SSAInstructionFactory; -import com.ibm.wala.ssa.SSAInvokeInstruction; -import com.ibm.wala.ssa.SSANewInstruction; -import com.ibm.wala.ssa.SSAReturnInstruction; -import com.ibm.wala.types.MethodReference; -import com.ibm.wala.types.TypeReference; -import static com.ibm.wala.types.TypeName.*; -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.warnings.Warning; - -/** - * An abstract superclass of various {@link SSAContextInterpreter}s that deal with reflection methods. - */ -public abstract class AbstractReflectionInterpreter implements SSAContextInterpreter { - - protected static final boolean DEBUG = false; - - protected final static int CONE_BOUND = 10; - - protected int indexLocal = 100; - - protected final Map typeIndexMap = HashMapFactory.make(); - - /** - * Governing analysis options - */ - protected AnalysisOptions options; - - /** - * cache of analysis information - */ - protected AnalysisCache cache; - - - protected int getLocalForType(TypeReference T) { - Integer I = typeIndexMap.get(T); - if (I == null) { - typeIndexMap.put(T, I = new Integer(indexLocal += 2)); - } - return I.intValue(); - } - - protected int getExceptionsForType(TypeReference T) { - return getLocalForType(T) + 1; - } - - protected int getCallSiteForType(TypeReference T) { - return getLocalForType(T); - } - - protected int getNewSiteForType(TypeReference T) { - return getLocalForType(T) + 1; - } - - /** - * @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. - */ - protected TypeAbstraction typeRef2TypeAbstraction(IClassHierarchy cha, TypeReference type) { - IClass klass = cha.lookupClass(type); - if (klass != null) { - return new ConeType(klass); - } - Assertions.UNREACHABLE(type.toString()); - return null; - } - - /** - * A warning when we expect excessive pollution from a factory method - */ - protected 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; - } - - @Override - public String getMsg() { - return getClass().toString() + " : " + T + " " + nImplementors; - } - - public static ManySubtypesWarning create(TypeAbstraction T, int n) { - return new ManySubtypesWarning(T, n); - } - } - - /** - * A warning when we fail to find subtypes for a factory method - */ - protected static class NoSubtypesWarning extends Warning { - - final TypeAbstraction T; - - NoSubtypesWarning(TypeAbstraction T) { - super(Warning.SEVERE); - this.T = T; - } - - @Override - public String getMsg() { - return getClass().toString() + " : " + T; - } - - public static NoSubtypesWarning create(TypeAbstraction T) { - return new NoSubtypesWarning(T); - } - } - - /** - * A warning when we find flow of a factory allocation to a cast to {@link Serializable} - */ - protected static class IgnoreSerializableWarning extends Warning { - - final private static IgnoreSerializableWarning instance = new IgnoreSerializableWarning(); - - @Override - public String getMsg() { - return getClass().toString(); - } - - public static IgnoreSerializableWarning create() { - return instance; - } - } - - protected class SpecializedMethod extends SyntheticMethod { - - /** - * Set of types that we have already inserted an allocation for. - */ - protected final HashSet typesAllocated = HashSetFactory.make(5); - - /** - * List of synthetic allocation statements we model for this specialized instance - */ - final protected ArrayList allocations = new ArrayList(); - - /** - * List of synthetic invoke instructions we model for this specialized instance. - */ - final protected ArrayList calls = new ArrayList(); - - /** - * List of all instructions - */ - protected final ArrayList allInstructions = new ArrayList(); - - private final SSAInstructionFactory insts = declaringClass.getClassLoader().getInstructionFactory(); - - public SpecializedMethod(MethodReference method, IClass declaringClass, boolean isStatic, boolean isFactory) { - super(method, declaringClass, isStatic, isFactory); - } - - public SpecializedMethod(IMethod method, IClass declaringClass, boolean isStatic, boolean isFactory) { - super(method, declaringClass, isStatic, isFactory); - } - - /** - * @param T type allocated by the instruction. - */ - protected void addInstruction(final TypeReference T, SSAInstruction instr, boolean isAllocation) { - if (isAllocation) { - if (typesAllocated.contains(T)) { - return; - } else { - typesAllocated.add(T); - } - } - - allInstructions.add(instr); - if (isAllocation) { - allocations.add(instr); - } - } - - /** - * @param t type of object to allocate - * @return value number of the newly allocated object - */ - protected int addStatementsForConcreteSimpleType(final TypeReference t) { - // assert we haven't allocated this type already. - assert !typesAllocated.contains(t); - if (DEBUG) { - System.err.println(("addStatementsForConcreteType: " + t)); - } - NewSiteReference ref = NewSiteReference.make(getNewSiteForType(t), t); - int alloc = getLocalForType(t); - - if (t.isArrayType()) { - // for now, just allocate an array of size 1 in each dimension. - int dims = 0; - int dim = t.getDerivedMask(); - if ((dim&ElementMask) == PrimitiveMask) { - dim >>= 2; - } - while ((dim&ElementMask) == ArrayMask) { - dims++; - dim >>=2; - } - - int[] extents = new int[dims]; - Arrays.fill(extents, 1); - SSANewInstruction a = insts.NewInstruction(alloc, ref, extents); - addInstruction(t, a, true); - } else { - SSANewInstruction a = insts.NewInstruction(alloc, ref); - addInstruction(t, a, true); - addCtorInvokeInstruction(t, alloc); - } - - SSAReturnInstruction r = insts.ReturnInstruction(alloc, false); - addInstruction(t, r, false); - return alloc; - } - - /** - * Add an instruction to invoke the default constructor on the object of value number alloc of type t. - */ - protected void addCtorInvokeInstruction(final TypeReference t, int alloc) { - 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 = insts.InvokeInstruction(params, exc, site); - calls.add(s); - allInstructions.add(s); - } - } +/******************************************************************************* + * Copyright (c) 2008 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.io.Serializable; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashSet; +import java.util.Map; + +import com.ibm.wala.analysis.typeInference.ConeType; +import com.ibm.wala.analysis.typeInference.TypeAbstraction; +import com.ibm.wala.classLoader.CallSiteReference; +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.AnalysisCache; +import com.ibm.wala.ipa.callgraph.AnalysisOptions; +import com.ibm.wala.ipa.callgraph.propagation.SSAContextInterpreter; +import com.ibm.wala.ipa.cha.IClassHierarchy; +import com.ibm.wala.shrikeBT.IInvokeInstruction; +import com.ibm.wala.ssa.SSAInstruction; +import com.ibm.wala.ssa.SSAInstructionFactory; +import com.ibm.wala.ssa.SSAInvokeInstruction; +import com.ibm.wala.ssa.SSANewInstruction; +import com.ibm.wala.ssa.SSAReturnInstruction; +import com.ibm.wala.types.MethodReference; +import com.ibm.wala.types.TypeReference; +import static com.ibm.wala.types.TypeName.*; +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.warnings.Warning; + +/** + * An abstract superclass of various {@link SSAContextInterpreter}s that deal with reflection methods. + */ +public abstract class AbstractReflectionInterpreter implements SSAContextInterpreter { + + protected static final boolean DEBUG = false; + + protected final static int CONE_BOUND = 10; + + protected int indexLocal = 100; + + protected final Map typeIndexMap = HashMapFactory.make(); + + /** + * Governing analysis options + */ + protected AnalysisOptions options; + + /** + * cache of analysis information + */ + protected AnalysisCache cache; + + + protected int getLocalForType(TypeReference T) { + Integer I = typeIndexMap.get(T); + if (I == null) { + typeIndexMap.put(T, I = new Integer(indexLocal += 2)); + } + return I.intValue(); + } + + protected int getExceptionsForType(TypeReference T) { + return getLocalForType(T) + 1; + } + + protected int getCallSiteForType(TypeReference T) { + return getLocalForType(T); + } + + protected int getNewSiteForType(TypeReference T) { + return getLocalForType(T) + 1; + } + + /** + * @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. + */ + protected TypeAbstraction typeRef2TypeAbstraction(IClassHierarchy cha, TypeReference type) { + IClass klass = cha.lookupClass(type); + if (klass != null) { + return new ConeType(klass); + } + Assertions.UNREACHABLE(type.toString()); + return null; + } + + /** + * A warning when we expect excessive pollution from a factory method + */ + protected 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; + } + + @Override + public String getMsg() { + return getClass().toString() + " : " + T + " " + nImplementors; + } + + public static ManySubtypesWarning create(TypeAbstraction T, int n) { + return new ManySubtypesWarning(T, n); + } + } + + /** + * A warning when we fail to find subtypes for a factory method + */ + protected static class NoSubtypesWarning extends Warning { + + final TypeAbstraction T; + + NoSubtypesWarning(TypeAbstraction T) { + super(Warning.SEVERE); + this.T = T; + } + + @Override + public String getMsg() { + return getClass().toString() + " : " + T; + } + + public static NoSubtypesWarning create(TypeAbstraction T) { + return new NoSubtypesWarning(T); + } + } + + /** + * A warning when we find flow of a factory allocation to a cast to {@link Serializable} + */ + protected static class IgnoreSerializableWarning extends Warning { + + final private static IgnoreSerializableWarning instance = new IgnoreSerializableWarning(); + + @Override + public String getMsg() { + return getClass().toString(); + } + + public static IgnoreSerializableWarning create() { + return instance; + } + } + + protected class SpecializedMethod extends SyntheticMethod { + + /** + * Set of types that we have already inserted an allocation for. + */ + protected final HashSet typesAllocated = HashSetFactory.make(5); + + /** + * List of synthetic allocation statements we model for this specialized instance + */ + final protected ArrayList allocations = new ArrayList(); + + /** + * List of synthetic invoke instructions we model for this specialized instance. + */ + final protected ArrayList calls = new ArrayList(); + + /** + * List of all instructions + */ + protected final ArrayList allInstructions = new ArrayList(); + + private final SSAInstructionFactory insts = declaringClass.getClassLoader().getInstructionFactory(); + + public SpecializedMethod(MethodReference method, IClass declaringClass, boolean isStatic, boolean isFactory) { + super(method, declaringClass, isStatic, isFactory); + } + + public SpecializedMethod(IMethod method, IClass declaringClass, boolean isStatic, boolean isFactory) { + super(method, declaringClass, isStatic, isFactory); + } + + /** + * @param T type allocated by the instruction. + */ + protected void addInstruction(final TypeReference T, SSAInstruction instr, boolean isAllocation) { + if (isAllocation) { + if (typesAllocated.contains(T)) { + return; + } else { + typesAllocated.add(T); + } + } + + allInstructions.add(instr); + if (isAllocation) { + allocations.add(instr); + } + } + + /** + * @param t type of object to allocate + * @return value number of the newly allocated object + */ + protected int addStatementsForConcreteSimpleType(final TypeReference t) { + // assert we haven't allocated this type already. + assert !typesAllocated.contains(t); + if (DEBUG) { + System.err.println(("addStatementsForConcreteType: " + t)); + } + NewSiteReference ref = NewSiteReference.make(getNewSiteForType(t), t); + int alloc = getLocalForType(t); + + if (t.isArrayType()) { + // for now, just allocate an array of size 1 in each dimension. + int dims = 0; + int dim = t.getDerivedMask(); + if ((dim&ElementMask) == PrimitiveMask) { + dim >>= 2; + } + while ((dim&ElementMask) == ArrayMask) { + dims++; + dim >>=2; + } + + int[] extents = new int[dims]; + Arrays.fill(extents, 1); + SSANewInstruction a = insts.NewInstruction(alloc, ref, extents); + addInstruction(t, a, true); + } else { + SSANewInstruction a = insts.NewInstruction(alloc, ref); + addInstruction(t, a, true); + addCtorInvokeInstruction(t, alloc); + } + + SSAReturnInstruction r = insts.ReturnInstruction(alloc, false); + addInstruction(t, r, false); + return alloc; + } + + /** + * Add an instruction to invoke the default constructor on the object of value number alloc of type t. + */ + protected void addCtorInvokeInstruction(final TypeReference t, int alloc) { + 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 = insts.InvokeInstruction(params, exc, site); + calls.add(s); + allInstructions.add(s); + } + } } \ No newline at end of file diff --git a/com.ibm.wala.core/src/com/ibm/wala/analysis/reflection/ClassFactoryContextInterpreter.java b/com.ibm.wala.core/src/com/ibm/wala/analysis/reflection/ClassFactoryContextInterpreter.java index 10ead8f3b..49ea6f3e3 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/analysis/reflection/ClassFactoryContextInterpreter.java +++ b/com.ibm.wala.core/src/com/ibm/wala/analysis/reflection/ClassFactoryContextInterpreter.java @@ -1,145 +1,145 @@ -/******************************************************************************* - * Copyright (c) 2008 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.Iterator; - -import com.ibm.wala.cfg.ControlFlowGraph; -import com.ibm.wala.cfg.InducedCFG; -import com.ibm.wala.classLoader.CallSiteReference; -import com.ibm.wala.classLoader.IClass; -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.propagation.SSAContextInterpreter; -import com.ibm.wala.ipa.summaries.SyntheticIR; -import com.ibm.wala.ssa.DefUse; -import com.ibm.wala.ssa.IR; -import com.ibm.wala.ssa.ISSABasicBlock; -import com.ibm.wala.ssa.SSAInstruction; -import com.ibm.wala.ssa.SSAInstructionFactory; -import com.ibm.wala.ssa.SSALoadMetadataInstruction; -import com.ibm.wala.ssa.SSAOptions; -import com.ibm.wala.ssa.SSAReturnInstruction; -import com.ibm.wala.ssa.SSAThrowInstruction; -import com.ibm.wala.types.FieldReference; -import com.ibm.wala.types.TypeReference; -import com.ibm.wala.util.collections.EmptyIterator; -import com.ibm.wala.util.collections.NonNullSingletonIterator; - -/** - * An {@link SSAContextInterpreter} specialized to interpret reflective class factories (e.g. Class.forName()) in a - * {@link JavaTypeContext} which represents the point-type of the class object created by the call. - */ -public class ClassFactoryContextInterpreter implements SSAContextInterpreter { - - private static final boolean DEBUG = false; - - public IR getIR(CGNode node) { - if (node == null) { - throw new IllegalArgumentException("node is null"); - } - assert understands(node); - if (DEBUG) { - System.err.println("generating IR for " + node); - } - IR result = makeIR(node.getMethod(), (JavaTypeContext) node.getContext()); - return result; - } - - public int getNumberOfStatements(CGNode node) { - assert understands(node); - return getIR(node).getInstructions().length; - } - - /* - * @see com.ibm.wala.ipa.callgraph.propagation.rta.RTAContextInterpreter#understands(com.ibm.wala.ipa.callgraph.CGNode) - */ - public boolean understands(CGNode node) { - if (node == null) { - throw new IllegalArgumentException("node is null"); - } - if (!(node.getContext() instanceof JavaTypeContext)) { - return false; - } - return ClassFactoryContextSelector.isClassFactory(node.getMethod().getReference()); - } - - /* - * @see com.ibm.wala.ipa.callgraph.propagation.rta.RTAContextInterpreter#iterateNewSites(com.ibm.wala.ipa.callgraph.CGNode) - */ - public Iterator iterateNewSites(CGNode node) { - if (node == null) { - throw new IllegalArgumentException("node is null"); - } - assert understands(node); - JavaTypeContext context = (JavaTypeContext) node.getContext(); - TypeReference tr = context.getType().getTypeReference(); - if (tr != null) { - return new NonNullSingletonIterator(NewSiteReference.make(0, tr)); - } - return EmptyIterator.instance(); - } - - /* - * @see com.ibm.wala.ipa.callgraph.propagation.rta.RTAContextInterpreter#iterateCallSites(com.ibm.wala.ipa.callgraph.CGNode) - */ - public Iterator iterateCallSites(CGNode node) { - assert understands(node); - return EmptyIterator.instance(); - } - - private SSAInstruction[] makeStatements(JavaTypeContext context) { - SSAInstructionFactory insts = context.getType().getType().getClassLoader().getInstructionFactory(); - ArrayList statements = new ArrayList(); - // vn1 is the string parameter - int retValue = 2; - TypeReference tr = context.getType().getTypeReference(); - if (tr != null) { - SSALoadMetadataInstruction l = insts.LoadMetadataInstruction(retValue, TypeReference.JavaLangClass, tr); - statements.add(l); - SSAReturnInstruction R = insts.ReturnInstruction(retValue, false); - statements.add(R); - } else { - SSAThrowInstruction t = insts.ThrowInstruction(retValue); - statements.add(t); - } - SSAInstruction[] result = new SSAInstruction[statements.size()]; - statements.toArray(result); - return result; - } - - private IR makeIR(IMethod method, JavaTypeContext context) { - SSAInstruction instrs[] = makeStatements(context); - return new SyntheticIR(method, context, new InducedCFG(instrs, method, context), instrs, SSAOptions.defaultOptions(), null); - } - - public boolean recordFactoryType(CGNode node, IClass klass) { - return false; - } - - public Iterator iterateFieldsRead(CGNode node) { - return EmptyIterator.instance(); - } - - public Iterator iterateFieldsWritten(CGNode node) { - return EmptyIterator.instance(); - } - - public ControlFlowGraph getCFG(CGNode N) { - return getIR(N).getControlFlowGraph(); - } - - public DefUse getDU(CGNode node) { - return new DefUse(getIR(node)); - } -} +/******************************************************************************* + * Copyright (c) 2008 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.Iterator; + +import com.ibm.wala.cfg.ControlFlowGraph; +import com.ibm.wala.cfg.InducedCFG; +import com.ibm.wala.classLoader.CallSiteReference; +import com.ibm.wala.classLoader.IClass; +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.propagation.SSAContextInterpreter; +import com.ibm.wala.ipa.summaries.SyntheticIR; +import com.ibm.wala.ssa.DefUse; +import com.ibm.wala.ssa.IR; +import com.ibm.wala.ssa.ISSABasicBlock; +import com.ibm.wala.ssa.SSAInstruction; +import com.ibm.wala.ssa.SSAInstructionFactory; +import com.ibm.wala.ssa.SSALoadMetadataInstruction; +import com.ibm.wala.ssa.SSAOptions; +import com.ibm.wala.ssa.SSAReturnInstruction; +import com.ibm.wala.ssa.SSAThrowInstruction; +import com.ibm.wala.types.FieldReference; +import com.ibm.wala.types.TypeReference; +import com.ibm.wala.util.collections.EmptyIterator; +import com.ibm.wala.util.collections.NonNullSingletonIterator; + +/** + * An {@link SSAContextInterpreter} specialized to interpret reflective class factories (e.g. Class.forName()) in a + * {@link JavaTypeContext} which represents the point-type of the class object created by the call. + */ +public class ClassFactoryContextInterpreter implements SSAContextInterpreter { + + private static final boolean DEBUG = false; + + public IR getIR(CGNode node) { + if (node == null) { + throw new IllegalArgumentException("node is null"); + } + assert understands(node); + if (DEBUG) { + System.err.println("generating IR for " + node); + } + IR result = makeIR(node.getMethod(), (JavaTypeContext) node.getContext()); + return result; + } + + public int getNumberOfStatements(CGNode node) { + assert understands(node); + return getIR(node).getInstructions().length; + } + + /* + * @see com.ibm.wala.ipa.callgraph.propagation.rta.RTAContextInterpreter#understands(com.ibm.wala.ipa.callgraph.CGNode) + */ + public boolean understands(CGNode node) { + if (node == null) { + throw new IllegalArgumentException("node is null"); + } + if (!(node.getContext() instanceof JavaTypeContext)) { + return false; + } + return ClassFactoryContextSelector.isClassFactory(node.getMethod().getReference()); + } + + /* + * @see com.ibm.wala.ipa.callgraph.propagation.rta.RTAContextInterpreter#iterateNewSites(com.ibm.wala.ipa.callgraph.CGNode) + */ + public Iterator iterateNewSites(CGNode node) { + if (node == null) { + throw new IllegalArgumentException("node is null"); + } + assert understands(node); + JavaTypeContext context = (JavaTypeContext) node.getContext(); + TypeReference tr = context.getType().getTypeReference(); + if (tr != null) { + return new NonNullSingletonIterator(NewSiteReference.make(0, tr)); + } + return EmptyIterator.instance(); + } + + /* + * @see com.ibm.wala.ipa.callgraph.propagation.rta.RTAContextInterpreter#iterateCallSites(com.ibm.wala.ipa.callgraph.CGNode) + */ + public Iterator iterateCallSites(CGNode node) { + assert understands(node); + return EmptyIterator.instance(); + } + + private SSAInstruction[] makeStatements(JavaTypeContext context) { + SSAInstructionFactory insts = context.getType().getType().getClassLoader().getInstructionFactory(); + ArrayList statements = new ArrayList(); + // vn1 is the string parameter + int retValue = 2; + TypeReference tr = context.getType().getTypeReference(); + if (tr != null) { + SSALoadMetadataInstruction l = insts.LoadMetadataInstruction(retValue, TypeReference.JavaLangClass, tr); + statements.add(l); + SSAReturnInstruction R = insts.ReturnInstruction(retValue, false); + statements.add(R); + } else { + SSAThrowInstruction t = insts.ThrowInstruction(retValue); + statements.add(t); + } + SSAInstruction[] result = new SSAInstruction[statements.size()]; + statements.toArray(result); + return result; + } + + private IR makeIR(IMethod method, JavaTypeContext context) { + SSAInstruction instrs[] = makeStatements(context); + return new SyntheticIR(method, context, new InducedCFG(instrs, method, context), instrs, SSAOptions.defaultOptions(), null); + } + + public boolean recordFactoryType(CGNode node, IClass klass) { + return false; + } + + public Iterator iterateFieldsRead(CGNode node) { + return EmptyIterator.instance(); + } + + public Iterator iterateFieldsWritten(CGNode node) { + return EmptyIterator.instance(); + } + + public ControlFlowGraph getCFG(CGNode N) { + return getIR(N).getControlFlowGraph(); + } + + public DefUse getDU(CGNode node) { + return new DefUse(getIR(node)); + } +} diff --git a/com.ibm.wala.core/src/com/ibm/wala/analysis/reflection/ClassFactoryContextSelector.java b/com.ibm.wala.core/src/com/ibm/wala/analysis/reflection/ClassFactoryContextSelector.java index 3f9c6c664..dc6df81f0 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/analysis/reflection/ClassFactoryContextSelector.java +++ b/com.ibm.wala.core/src/com/ibm/wala/analysis/reflection/ClassFactoryContextSelector.java @@ -1,129 +1,129 @@ -/******************************************************************************* - * Copyright (c) 2008 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.PointType; -import com.ibm.wala.classLoader.CallSiteReference; -import com.ibm.wala.classLoader.IClass; -import com.ibm.wala.classLoader.IMethod; -import com.ibm.wala.ipa.callgraph.CGNode; -import com.ibm.wala.ipa.callgraph.Context; -import com.ibm.wala.ipa.callgraph.ContextSelector; -import com.ibm.wala.ipa.callgraph.propagation.InstanceKey; -import com.ibm.wala.ipa.cha.IClassHierarchy; -import com.ibm.wala.ssa.IR; -import com.ibm.wala.ssa.SSAAbstractInvokeInstruction; -import com.ibm.wala.ssa.SymbolTable; -import com.ibm.wala.types.ClassLoaderReference; -import com.ibm.wala.types.Descriptor; -import com.ibm.wala.types.MethodReference; -import com.ibm.wala.types.TypeReference; -import com.ibm.wala.util.intset.EmptyIntSet; -import com.ibm.wala.util.intset.IntSet; -import com.ibm.wala.util.intset.IntSetUtil; -import com.ibm.wala.util.strings.Atom; -import com.ibm.wala.util.strings.StringStuff; - -/** - * A {@link ContextSelector} to intercept calls to reflective class factories (e.g. Class.forName()) when the parameter is a string - * constant - */ -class ClassFactoryContextSelector implements ContextSelector { - - public final static Atom forNameAtom = Atom.findOrCreateUnicodeAtom("forName"); - - private final static Descriptor forNameDescriptor = Descriptor.findOrCreateUTF8("(Ljava/lang/String;)Ljava/lang/Class;"); - - public final static MethodReference FOR_NAME_REF = MethodReference.findOrCreate(TypeReference.JavaLangClass, forNameAtom, - forNameDescriptor); - - public final static Atom loadClassAtom = Atom.findOrCreateUnicodeAtom("loadClass"); - - private final static Descriptor loadClassDescriptor = Descriptor.findOrCreateUTF8("(Ljava/lang/String;)Ljava/lang/Class;"); - - private final static TypeReference CLASSLOADER = TypeReference.findOrCreate(ClassLoaderReference.Primordial, - "Ljava/lang/ClassLoader"); - - public final static MethodReference LOAD_CLASS_REF = MethodReference - .findOrCreate(CLASSLOADER, loadClassAtom, loadClassDescriptor); - - public ClassFactoryContextSelector() { - } - - public static boolean isClassFactory(MethodReference m) { - if (m.equals(FOR_NAME_REF)) { - return true; - } - if (m.equals(LOAD_CLASS_REF)) { - return true; - } - return false; - } - - public int getUseOfStringParameter(SSAAbstractInvokeInstruction call) { - if (call.isStatic()) { - return call.getUse(0); - } else { - return call.getUse(1); - } - } - - /** - * If the {@link CallSiteReference} invokes Class.forName(s) and s is a string constant, return a {@link JavaTypeContext} - * representing the type named by s, if we can resolve it in the {@link IClassHierarchy}. - * - * @see com.ibm.wala.ipa.callgraph.ContextSelector#getCalleeTarget(com.ibm.wala.ipa.callgraph.CGNode, - * com.ibm.wala.classLoader.CallSiteReference, com.ibm.wala.classLoader.IMethod, - * InstanceKey[]) - */ - public Context getCalleeTarget(CGNode caller, CallSiteReference site, IMethod callee, InstanceKey[] receiver) { - if (isClassFactory(callee.getReference())) { - IR ir = caller.getIR(); - SymbolTable symbolTable = ir.getSymbolTable(); - SSAAbstractInvokeInstruction[] invokeInstructions = caller.getIR().getCalls(site); - if (invokeInstructions.length != 1) { - return null; - } - int use = getUseOfStringParameter(invokeInstructions[0]); - if (symbolTable.isStringConstant(use)) { - String className = StringStuff.deployment2CanonicalTypeString(symbolTable.getStringValue(use)); - TypeReference t = TypeReference.findOrCreate(caller.getMethod().getDeclaringClass().getClassLoader().getReference(), - className); - IClass klass = caller.getClassHierarchy().lookupClass(t); - if (klass != null) { - return new JavaTypeContext(new PointType(klass)); - } - } - } - return null; - } - - private static final IntSet thisParameter = IntSetUtil.make(new int[]{0}); - - private static final IntSet firstParameter = IntSetUtil.make(new int[]{1}); - - public IntSet getRelevantParameters(CGNode caller, CallSiteReference site) { - if (isClassFactory(site.getDeclaredTarget())) { - SSAAbstractInvokeInstruction[] invokeInstructions = caller.getIR().getCalls(site); - if (invokeInstructions.length != 1) { - if (invokeInstructions[0].isStatic()) { - return thisParameter; - } else { - return firstParameter; - } - } else { - return EmptyIntSet.instance; - } - } else { - return EmptyIntSet.instance; - } - } +/******************************************************************************* + * Copyright (c) 2008 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.PointType; +import com.ibm.wala.classLoader.CallSiteReference; +import com.ibm.wala.classLoader.IClass; +import com.ibm.wala.classLoader.IMethod; +import com.ibm.wala.ipa.callgraph.CGNode; +import com.ibm.wala.ipa.callgraph.Context; +import com.ibm.wala.ipa.callgraph.ContextSelector; +import com.ibm.wala.ipa.callgraph.propagation.InstanceKey; +import com.ibm.wala.ipa.cha.IClassHierarchy; +import com.ibm.wala.ssa.IR; +import com.ibm.wala.ssa.SSAAbstractInvokeInstruction; +import com.ibm.wala.ssa.SymbolTable; +import com.ibm.wala.types.ClassLoaderReference; +import com.ibm.wala.types.Descriptor; +import com.ibm.wala.types.MethodReference; +import com.ibm.wala.types.TypeReference; +import com.ibm.wala.util.intset.EmptyIntSet; +import com.ibm.wala.util.intset.IntSet; +import com.ibm.wala.util.intset.IntSetUtil; +import com.ibm.wala.util.strings.Atom; +import com.ibm.wala.util.strings.StringStuff; + +/** + * A {@link ContextSelector} to intercept calls to reflective class factories (e.g. Class.forName()) when the parameter is a string + * constant + */ +class ClassFactoryContextSelector implements ContextSelector { + + public final static Atom forNameAtom = Atom.findOrCreateUnicodeAtom("forName"); + + private final static Descriptor forNameDescriptor = Descriptor.findOrCreateUTF8("(Ljava/lang/String;)Ljava/lang/Class;"); + + public final static MethodReference FOR_NAME_REF = MethodReference.findOrCreate(TypeReference.JavaLangClass, forNameAtom, + forNameDescriptor); + + public final static Atom loadClassAtom = Atom.findOrCreateUnicodeAtom("loadClass"); + + private final static Descriptor loadClassDescriptor = Descriptor.findOrCreateUTF8("(Ljava/lang/String;)Ljava/lang/Class;"); + + private final static TypeReference CLASSLOADER = TypeReference.findOrCreate(ClassLoaderReference.Primordial, + "Ljava/lang/ClassLoader"); + + public final static MethodReference LOAD_CLASS_REF = MethodReference + .findOrCreate(CLASSLOADER, loadClassAtom, loadClassDescriptor); + + public ClassFactoryContextSelector() { + } + + public static boolean isClassFactory(MethodReference m) { + if (m.equals(FOR_NAME_REF)) { + return true; + } + if (m.equals(LOAD_CLASS_REF)) { + return true; + } + return false; + } + + public int getUseOfStringParameter(SSAAbstractInvokeInstruction call) { + if (call.isStatic()) { + return call.getUse(0); + } else { + return call.getUse(1); + } + } + + /** + * If the {@link CallSiteReference} invokes Class.forName(s) and s is a string constant, return a {@link JavaTypeContext} + * representing the type named by s, if we can resolve it in the {@link IClassHierarchy}. + * + * @see com.ibm.wala.ipa.callgraph.ContextSelector#getCalleeTarget(com.ibm.wala.ipa.callgraph.CGNode, + * com.ibm.wala.classLoader.CallSiteReference, com.ibm.wala.classLoader.IMethod, + * InstanceKey[]) + */ + public Context getCalleeTarget(CGNode caller, CallSiteReference site, IMethod callee, InstanceKey[] receiver) { + if (isClassFactory(callee.getReference())) { + IR ir = caller.getIR(); + SymbolTable symbolTable = ir.getSymbolTable(); + SSAAbstractInvokeInstruction[] invokeInstructions = caller.getIR().getCalls(site); + if (invokeInstructions.length != 1) { + return null; + } + int use = getUseOfStringParameter(invokeInstructions[0]); + if (symbolTable.isStringConstant(use)) { + String className = StringStuff.deployment2CanonicalTypeString(symbolTable.getStringValue(use)); + TypeReference t = TypeReference.findOrCreate(caller.getMethod().getDeclaringClass().getClassLoader().getReference(), + className); + IClass klass = caller.getClassHierarchy().lookupClass(t); + if (klass != null) { + return new JavaTypeContext(new PointType(klass)); + } + } + } + return null; + } + + private static final IntSet thisParameter = IntSetUtil.make(new int[]{0}); + + private static final IntSet firstParameter = IntSetUtil.make(new int[]{1}); + + public IntSet getRelevantParameters(CGNode caller, CallSiteReference site) { + if (isClassFactory(site.getDeclaredTarget())) { + SSAAbstractInvokeInstruction[] invokeInstructions = caller.getIR().getCalls(site); + if (invokeInstructions.length != 1) { + if (invokeInstructions[0].isStatic()) { + return thisParameter; + } else { + return firstParameter; + } + } else { + return EmptyIntSet.instance; + } + } else { + return EmptyIntSet.instance; + } + } } \ No newline at end of file diff --git a/com.ibm.wala.core/src/com/ibm/wala/analysis/reflection/ClassNewInstanceContextInterpreter.java b/com.ibm.wala.core/src/com/ibm/wala/analysis/reflection/ClassNewInstanceContextInterpreter.java index d7785f18a..e972c9d66 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/analysis/reflection/ClassNewInstanceContextInterpreter.java +++ b/com.ibm.wala.core/src/com/ibm/wala/analysis/reflection/ClassNewInstanceContextInterpreter.java @@ -1,173 +1,173 @@ -/******************************************************************************* - * Copyright (c) 2008 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.Iterator; - -import com.ibm.wala.cfg.ControlFlowGraph; -import com.ibm.wala.cfg.InducedCFG; -import com.ibm.wala.classLoader.CallSiteReference; -import com.ibm.wala.classLoader.IClass; -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.propagation.SSAContextInterpreter; -import com.ibm.wala.ipa.cha.IClassHierarchy; -import com.ibm.wala.ipa.summaries.SyntheticIR; -import com.ibm.wala.ssa.DefUse; -import com.ibm.wala.ssa.IR; -import com.ibm.wala.ssa.ISSABasicBlock; -import com.ibm.wala.ssa.SSAInstruction; -import com.ibm.wala.ssa.SSAInstructionFactory; -import com.ibm.wala.ssa.SSAOptions; -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.TypeReference; -import com.ibm.wala.util.collections.EmptyIterator; -import com.ibm.wala.util.collections.NonNullSingletonIterator; -import com.ibm.wala.util.strings.Atom; - -/** - * An {@link SSAContextInterpreter} specialized to interpret Class.newInstance in a {@link JavaTypeContext} which represents the - * point-type of the class object created by the call. - */ -public class ClassNewInstanceContextInterpreter extends AbstractReflectionInterpreter { - - public final static Atom newInstanceAtom = Atom.findOrCreateUnicodeAtom("newInstance"); - - private final static Descriptor classNewInstanceDescriptor = Descriptor.findOrCreateUTF8("()Ljava/lang/Object;"); - - public final static MethodReference CLASS_NEW_INSTANCE_REF = MethodReference.findOrCreate(TypeReference.JavaLangClass, - newInstanceAtom, classNewInstanceDescriptor); - - private final static Atom defCtorAtom = Atom.findOrCreateUnicodeAtom(""); - - private final static Descriptor defCtorDescriptor = Descriptor.findOrCreateUTF8("()V"); - - private final static Selector defCtorSelector = new Selector(defCtorAtom, defCtorDescriptor); - - private final IClassHierarchy cha; - - public ClassNewInstanceContextInterpreter(IClassHierarchy cha) { - this.cha = cha; - } - - public IR getIR(CGNode node) { - if (node == null) { - throw new IllegalArgumentException("node is null"); - } - assert understands(node); - if (DEBUG) { - System.err.println("generating IR for " + node); - } - IR result = makeIR(node.getMethod(), (JavaTypeContext) node.getContext()); - return result; - } - - public int getNumberOfStatements(CGNode node) { - assert understands(node); - return getIR(node).getInstructions().length; - } - - public boolean understands(CGNode node) { - if (node == null) { - throw new IllegalArgumentException("node is null"); - } - if (!(node.getContext() instanceof JavaTypeContext)) { - return false; - } - return node.getMethod().getReference().equals(CLASS_NEW_INSTANCE_REF); - } - - public Iterator iterateNewSites(CGNode node) { - if (node == null) { - throw new IllegalArgumentException("node is null"); - } - assert understands(node); - JavaTypeContext context = (JavaTypeContext) node.getContext(); - TypeReference tr = context.getType().getTypeReference(); - if (tr != null) { - return new NonNullSingletonIterator(NewSiteReference.make(0, tr)); - } - return EmptyIterator.instance(); - } - - public Iterator iterateCallSites(CGNode node) { - assert understands(node); - return EmptyIterator.instance(); - } - - private IR makeIR(IMethod method, JavaTypeContext context) { - SSAInstructionFactory insts = context.getType().getType().getClassLoader().getInstructionFactory(); - TypeReference tr = context.getType().getTypeReference(); - if (tr != null) { - SpecializedMethod m = new SpecializedMethod(method, method.getDeclaringClass(), method.isStatic(), false); - IClass klass = cha.lookupClass(tr); - IMethod publicDefaultCtor = getPublicDefaultCtor(klass); - if (publicDefaultCtor != null) { - m.addStatementsForConcreteSimpleType(tr); - } else if (klass.getMethod(defCtorSelector) == null) { - TypeReference instantiationExceptionRef = TypeReference.findOrCreateClass(ClassLoaderReference.Primordial, "java/lang", - "InstantiationException"); - int xobj = method.getNumberOfParameters() + 1; - SSAInstruction newStatement = insts.NewInstruction(xobj, NewSiteReference.make(2, instantiationExceptionRef)); - m.addInstruction(tr, newStatement, true); - SSAInstruction throwStatement = insts.ThrowInstruction(xobj); - m.addInstruction(tr, throwStatement, false); - } else { - TypeReference illegalAccessExceptionRef = TypeReference.findOrCreateClass(ClassLoaderReference.Primordial, "java/lang", - "IllegalAccessException"); - int xobj = method.getNumberOfParameters() + 1; - SSAInstruction newStatement = insts.NewInstruction(xobj, NewSiteReference.make(2, illegalAccessExceptionRef)); - m.addInstruction(tr, newStatement, true); - SSAInstruction throwStatement = insts.ThrowInstruction(xobj); - m.addInstruction(tr, throwStatement, false); - } - - SSAInstruction[] instrs = new SSAInstruction[m.allInstructions.size()]; - m.allInstructions. toArray(instrs); - return new SyntheticIR(method, context, new InducedCFG(instrs, method, context), instrs, SSAOptions.defaultOptions(), null); - } - - return null; - } - - private IMethod getPublicDefaultCtor(IClass klass) { - IMethod ctorMethod = klass.getMethod(defCtorSelector); - if (ctorMethod != null && ctorMethod.isPublic()) { - return ctorMethod; - } - return null; - } - - public boolean recordFactoryType(CGNode node, IClass klass) { - return false; - } - - public Iterator iterateFieldsRead(CGNode node) { - return EmptyIterator.instance(); - } - - public Iterator iterateFieldsWritten(CGNode node) { - return EmptyIterator.instance(); - } - - public ControlFlowGraph getCFG(CGNode N) { - return getIR(N).getControlFlowGraph(); - } - - public DefUse getDU(CGNode node) { - return new DefUse(getIR(node)); - } -} +/******************************************************************************* + * Copyright (c) 2008 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.Iterator; + +import com.ibm.wala.cfg.ControlFlowGraph; +import com.ibm.wala.cfg.InducedCFG; +import com.ibm.wala.classLoader.CallSiteReference; +import com.ibm.wala.classLoader.IClass; +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.propagation.SSAContextInterpreter; +import com.ibm.wala.ipa.cha.IClassHierarchy; +import com.ibm.wala.ipa.summaries.SyntheticIR; +import com.ibm.wala.ssa.DefUse; +import com.ibm.wala.ssa.IR; +import com.ibm.wala.ssa.ISSABasicBlock; +import com.ibm.wala.ssa.SSAInstruction; +import com.ibm.wala.ssa.SSAInstructionFactory; +import com.ibm.wala.ssa.SSAOptions; +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.TypeReference; +import com.ibm.wala.util.collections.EmptyIterator; +import com.ibm.wala.util.collections.NonNullSingletonIterator; +import com.ibm.wala.util.strings.Atom; + +/** + * An {@link SSAContextInterpreter} specialized to interpret Class.newInstance in a {@link JavaTypeContext} which represents the + * point-type of the class object created by the call. + */ +public class ClassNewInstanceContextInterpreter extends AbstractReflectionInterpreter { + + public final static Atom newInstanceAtom = Atom.findOrCreateUnicodeAtom("newInstance"); + + private final static Descriptor classNewInstanceDescriptor = Descriptor.findOrCreateUTF8("()Ljava/lang/Object;"); + + public final static MethodReference CLASS_NEW_INSTANCE_REF = MethodReference.findOrCreate(TypeReference.JavaLangClass, + newInstanceAtom, classNewInstanceDescriptor); + + private final static Atom defCtorAtom = Atom.findOrCreateUnicodeAtom(""); + + private final static Descriptor defCtorDescriptor = Descriptor.findOrCreateUTF8("()V"); + + private final static Selector defCtorSelector = new Selector(defCtorAtom, defCtorDescriptor); + + private final IClassHierarchy cha; + + public ClassNewInstanceContextInterpreter(IClassHierarchy cha) { + this.cha = cha; + } + + public IR getIR(CGNode node) { + if (node == null) { + throw new IllegalArgumentException("node is null"); + } + assert understands(node); + if (DEBUG) { + System.err.println("generating IR for " + node); + } + IR result = makeIR(node.getMethod(), (JavaTypeContext) node.getContext()); + return result; + } + + public int getNumberOfStatements(CGNode node) { + assert understands(node); + return getIR(node).getInstructions().length; + } + + public boolean understands(CGNode node) { + if (node == null) { + throw new IllegalArgumentException("node is null"); + } + if (!(node.getContext() instanceof JavaTypeContext)) { + return false; + } + return node.getMethod().getReference().equals(CLASS_NEW_INSTANCE_REF); + } + + public Iterator iterateNewSites(CGNode node) { + if (node == null) { + throw new IllegalArgumentException("node is null"); + } + assert understands(node); + JavaTypeContext context = (JavaTypeContext) node.getContext(); + TypeReference tr = context.getType().getTypeReference(); + if (tr != null) { + return new NonNullSingletonIterator(NewSiteReference.make(0, tr)); + } + return EmptyIterator.instance(); + } + + public Iterator iterateCallSites(CGNode node) { + assert understands(node); + return EmptyIterator.instance(); + } + + private IR makeIR(IMethod method, JavaTypeContext context) { + SSAInstructionFactory insts = context.getType().getType().getClassLoader().getInstructionFactory(); + TypeReference tr = context.getType().getTypeReference(); + if (tr != null) { + SpecializedMethod m = new SpecializedMethod(method, method.getDeclaringClass(), method.isStatic(), false); + IClass klass = cha.lookupClass(tr); + IMethod publicDefaultCtor = getPublicDefaultCtor(klass); + if (publicDefaultCtor != null) { + m.addStatementsForConcreteSimpleType(tr); + } else if (klass.getMethod(defCtorSelector) == null) { + TypeReference instantiationExceptionRef = TypeReference.findOrCreateClass(ClassLoaderReference.Primordial, "java/lang", + "InstantiationException"); + int xobj = method.getNumberOfParameters() + 1; + SSAInstruction newStatement = insts.NewInstruction(xobj, NewSiteReference.make(2, instantiationExceptionRef)); + m.addInstruction(tr, newStatement, true); + SSAInstruction throwStatement = insts.ThrowInstruction(xobj); + m.addInstruction(tr, throwStatement, false); + } else { + TypeReference illegalAccessExceptionRef = TypeReference.findOrCreateClass(ClassLoaderReference.Primordial, "java/lang", + "IllegalAccessException"); + int xobj = method.getNumberOfParameters() + 1; + SSAInstruction newStatement = insts.NewInstruction(xobj, NewSiteReference.make(2, illegalAccessExceptionRef)); + m.addInstruction(tr, newStatement, true); + SSAInstruction throwStatement = insts.ThrowInstruction(xobj); + m.addInstruction(tr, throwStatement, false); + } + + SSAInstruction[] instrs = new SSAInstruction[m.allInstructions.size()]; + m.allInstructions. toArray(instrs); + return new SyntheticIR(method, context, new InducedCFG(instrs, method, context), instrs, SSAOptions.defaultOptions(), null); + } + + return null; + } + + private IMethod getPublicDefaultCtor(IClass klass) { + IMethod ctorMethod = klass.getMethod(defCtorSelector); + if (ctorMethod != null && ctorMethod.isPublic()) { + return ctorMethod; + } + return null; + } + + public boolean recordFactoryType(CGNode node, IClass klass) { + return false; + } + + public Iterator iterateFieldsRead(CGNode node) { + return EmptyIterator.instance(); + } + + public Iterator iterateFieldsWritten(CGNode node) { + return EmptyIterator.instance(); + } + + public ControlFlowGraph getCFG(CGNode N) { + return getIR(N).getControlFlowGraph(); + } + + public DefUse getDU(CGNode node) { + return new DefUse(getIR(node)); + } +} diff --git a/com.ibm.wala.core/src/com/ibm/wala/analysis/reflection/ClassNewInstanceContextSelector.java b/com.ibm.wala.core/src/com/ibm/wala/analysis/reflection/ClassNewInstanceContextSelector.java index 248f85e27..f2f84eeb8 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/analysis/reflection/ClassNewInstanceContextSelector.java +++ b/com.ibm.wala.core/src/com/ibm/wala/analysis/reflection/ClassNewInstanceContextSelector.java @@ -1,68 +1,68 @@ -/******************************************************************************* - * Copyright (c) 2008 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.PointType; -import com.ibm.wala.classLoader.CallSiteReference; -import com.ibm.wala.classLoader.IClass; -import com.ibm.wala.classLoader.IMethod; -import com.ibm.wala.ipa.callgraph.CGNode; -import com.ibm.wala.ipa.callgraph.Context; -import com.ibm.wala.ipa.callgraph.ContextSelector; -import com.ibm.wala.ipa.callgraph.propagation.ConstantKey; -import com.ibm.wala.ipa.callgraph.propagation.InstanceKey; -import com.ibm.wala.util.intset.EmptyIntSet; -import com.ibm.wala.util.intset.IntSet; -import com.ibm.wala.util.intset.IntSetUtil; - -/** - * A {@link ContextSelector} to intercept calls to Class.newInstance() - */ -class ClassNewInstanceContextSelector implements ContextSelector { - - public ClassNewInstanceContextSelector() { - } - - /** - * If receiver is a {@link ConstantKey} whose value is an {@link IClass}, return a {@link JavaTypeContext} - * representing the type of the IClass. (This corresponds to the case where we know the exact type that will be - * allocated by the Class.newInstance() call.) Otherwise, return null. - */ - public Context getCalleeTarget(CGNode caller, CallSiteReference site, IMethod callee, InstanceKey[] receiver) { - if (callee.getReference().equals(ClassNewInstanceContextInterpreter.CLASS_NEW_INSTANCE_REF) && isTypeConstant(receiver[0])) { - IClass c = (IClass) ((ConstantKey) receiver[0]).getValue(); - if (!c.isAbstract() && !c.isInterface()) { - return new JavaTypeContext(new PointType(c)); - } - } - return null; - } - - private boolean isTypeConstant(InstanceKey instance) { - if (instance instanceof ConstantKey) { - ConstantKey c = (ConstantKey) instance; - if (c.getValue() instanceof IClass) { - return true; - } - } - return false; - } - - private static final IntSet thisParameter = IntSetUtil.make(new int[]{0}); - - public IntSet getRelevantParameters(CGNode caller, CallSiteReference site) { - if (site.isDispatch() || site.getDeclaredTarget().getNumberOfParameters() > 0) { - return thisParameter; - } else { - return EmptyIntSet.instance; - } - } +/******************************************************************************* + * Copyright (c) 2008 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.PointType; +import com.ibm.wala.classLoader.CallSiteReference; +import com.ibm.wala.classLoader.IClass; +import com.ibm.wala.classLoader.IMethod; +import com.ibm.wala.ipa.callgraph.CGNode; +import com.ibm.wala.ipa.callgraph.Context; +import com.ibm.wala.ipa.callgraph.ContextSelector; +import com.ibm.wala.ipa.callgraph.propagation.ConstantKey; +import com.ibm.wala.ipa.callgraph.propagation.InstanceKey; +import com.ibm.wala.util.intset.EmptyIntSet; +import com.ibm.wala.util.intset.IntSet; +import com.ibm.wala.util.intset.IntSetUtil; + +/** + * A {@link ContextSelector} to intercept calls to Class.newInstance() + */ +class ClassNewInstanceContextSelector implements ContextSelector { + + public ClassNewInstanceContextSelector() { + } + + /** + * If receiver is a {@link ConstantKey} whose value is an {@link IClass}, return a {@link JavaTypeContext} + * representing the type of the IClass. (This corresponds to the case where we know the exact type that will be + * allocated by the Class.newInstance() call.) Otherwise, return null. + */ + public Context getCalleeTarget(CGNode caller, CallSiteReference site, IMethod callee, InstanceKey[] receiver) { + if (callee.getReference().equals(ClassNewInstanceContextInterpreter.CLASS_NEW_INSTANCE_REF) && isTypeConstant(receiver[0])) { + IClass c = (IClass) ((ConstantKey) receiver[0]).getValue(); + if (!c.isAbstract() && !c.isInterface()) { + return new JavaTypeContext(new PointType(c)); + } + } + return null; + } + + private boolean isTypeConstant(InstanceKey instance) { + if (instance instanceof ConstantKey) { + ConstantKey c = (ConstantKey) instance; + if (c.getValue() instanceof IClass) { + return true; + } + } + return false; + } + + private static final IntSet thisParameter = IntSetUtil.make(new int[]{0}); + + public IntSet getRelevantParameters(CGNode caller, CallSiteReference site) { + if (site.isDispatch() || site.getDeclaredTarget().getNumberOfParameters() > 0) { + return thisParameter; + } else { + return EmptyIntSet.instance; + } + } } \ No newline at end of file diff --git a/com.ibm.wala.core/src/com/ibm/wala/analysis/reflection/CloneInterpreter.java b/com.ibm.wala.core/src/com/ibm/wala/analysis/reflection/CloneInterpreter.java index 79461a789..c2c122c2a 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/analysis/reflection/CloneInterpreter.java +++ b/com.ibm.wala.core/src/com/ibm/wala/analysis/reflection/CloneInterpreter.java @@ -1,259 +1,259 @@ -/******************************************************************************* - * 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.ArrayClass; -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.Language; -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.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.ISSABasicBlock; -import com.ibm.wala.ssa.SSAGetInstruction; -import com.ibm.wala.ssa.SSAInstruction; -import com.ibm.wala.ssa.SSAInstructionFactory; -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.FieldReference; -import com.ibm.wala.types.MethodReference; -import com.ibm.wala.types.TypeName; -import com.ibm.wala.types.TypeReference; -import com.ibm.wala.util.collections.HashMapFactory; -import com.ibm.wala.util.collections.NonNullSingletonIterator; -import com.ibm.wala.util.strings.Atom; - -/** - * A context interpreter for java.lang.Object.clone - * - * TODO: The current implementation does not model CloneNotSupportedExceptions - */ -public class CloneInterpreter implements SSAContextInterpreter { - - /** - * Comment for cloneAtom - */ - public final static Atom cloneAtom = Atom.findOrCreateUnicodeAtom("clone"); - - private final static Descriptor cloneDesc = Descriptor.findOrCreateUTF8("()Ljava/lang/Object;"); - - /** - * Comment for CLONE - */ - 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? - */ - final private Map IRCache = HashMapFactory.make(); - - private final SSAInstructionFactory insts = Language.JAVA.instructionFactory(); - - public IR getIR(CGNode node) { - if (node == null) { - throw new IllegalArgumentException("node is null"); - } - 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); - IRCache.put(cls.getReference(), result); - } - return result; - } - - public int getNumberOfStatements(CGNode node) { - assert understands(node); - return getIR(node).getInstructions().length; - } - - public boolean understands(CGNode node) { - if (node == null) { - throw new IllegalArgumentException("node is null"); - } - return (node.getMethod().getReference().equals(CLONE) && ContextUtil.getConcreteClassFromContext(node.getContext()) != null); - } - - public Iterator iterateNewSites(CGNode node) { - if (node == null) { - throw new IllegalArgumentException("node is null"); - } - assert understands(node); - IClass cls = ContextUtil.getConcreteClassFromContext(node.getContext()); - return new NonNullSingletonIterator(NewSiteReference.make(NEW_PC, cls.getReference())); - } - - public Iterator iterateCallSites(CGNode node) { - assert understands(node); - return new NonNullSingletonIterator(ARRAYCOPY_SITE); - } - - /** - * @return an array of statements that encode the behavior of the clone method for a given type. - */ - private SSAInstruction[] makeStatements(IClass klass) { - assert klass != null; - - ArrayList statements = new ArrayList(); - // 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(insts.ArrayLengthInstruction(length, 1)); - int[] sizes = new int[((ArrayClass)klass).getDimensionality()]; - Arrays.fill(sizes, length); - N = insts.NewInstruction(retValue, ref, sizes); - } else { - N = insts.NewInstruction(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 = insts.InvokeInstruction(params, exceptionValue, ARRAYCOPY_SITE); - statements.add(S); - } else { - // copy the fields over, one by one. - // TODO: - IClass k = klass; - while (k != null) { - for (Iterator it = klass.getDeclaredInstanceFields().iterator(); it.hasNext();) { - IField f = it.next(); - int tempValue = nextLocal++; - SSAGetInstruction G = insts.GetInstruction(tempValue, 1, f.getReference()); - statements.add(G); - SSAPutInstruction P = insts.PutInstruction(retValue, tempValue, f.getReference()); - statements.add(P); - } - k = k.getSuperclass(); - } - - } - - SSAReturnInstruction R = insts.ReturnInstruction(retValue, false); - statements.add(R); - - SSAInstruction[] result = new SSAInstruction[statements.size()]; - Iterator 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) { - assert klass != null; - SSAInstruction instrs[] = makeStatements(klass); - return new SyntheticIR(method, context, new InducedCFG(instrs, method, context), instrs, SSAOptions.defaultOptions(), null); - } - - /* - * @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; - } - - public Iterator iterateFieldsRead(CGNode node) { - SSAInstruction[] statements = getIR(node).getInstructions(); - return CodeScanner.getFieldsRead(statements).iterator(); - } - - public Iterator iterateFieldsWritten(CGNode node) { - SSAInstruction[] statements = getIR(node).getInstructions(); - return CodeScanner.getFieldsWritten(statements).iterator(); - } - - public Set getCaughtExceptions(CGNode node) { - SSAInstruction[] statements = getIR(node).getInstructions(); - return CodeScanner.getCaughtExceptions(node.getMethod().getDeclaringClass().getClassLoader().getLanguage(), statements); - } - - public boolean hasObjectArrayLoad(CGNode node) { - SSAInstruction[] statements = getIR(node).getInstructions(); - return CodeScanner.hasObjectArrayLoad(statements); - } - - public boolean hasObjectArrayStore(CGNode node) { - SSAInstruction[] statements = getIR(node).getInstructions(); - return CodeScanner.hasObjectArrayStore(statements); - } - - public Iterator iterateCastTypes(CGNode node) { - SSAInstruction[] statements = getIR(node).getInstructions(); - return CodeScanner.iterateCastTypes(statements); - } - - public ControlFlowGraph getCFG(CGNode N) { - return getIR(N).getControlFlowGraph(); - } - - public DefUse getDU(CGNode node) { - return new DefUse(getIR(node)); - } -} +/******************************************************************************* + * 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.ArrayClass; +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.Language; +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.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.ISSABasicBlock; +import com.ibm.wala.ssa.SSAGetInstruction; +import com.ibm.wala.ssa.SSAInstruction; +import com.ibm.wala.ssa.SSAInstructionFactory; +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.FieldReference; +import com.ibm.wala.types.MethodReference; +import com.ibm.wala.types.TypeName; +import com.ibm.wala.types.TypeReference; +import com.ibm.wala.util.collections.HashMapFactory; +import com.ibm.wala.util.collections.NonNullSingletonIterator; +import com.ibm.wala.util.strings.Atom; + +/** + * A context interpreter for java.lang.Object.clone + * + * TODO: The current implementation does not model CloneNotSupportedExceptions + */ +public class CloneInterpreter implements SSAContextInterpreter { + + /** + * Comment for cloneAtom + */ + public final static Atom cloneAtom = Atom.findOrCreateUnicodeAtom("clone"); + + private final static Descriptor cloneDesc = Descriptor.findOrCreateUTF8("()Ljava/lang/Object;"); + + /** + * Comment for CLONE + */ + 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? + */ + final private Map IRCache = HashMapFactory.make(); + + private final SSAInstructionFactory insts = Language.JAVA.instructionFactory(); + + public IR getIR(CGNode node) { + if (node == null) { + throw new IllegalArgumentException("node is null"); + } + 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); + IRCache.put(cls.getReference(), result); + } + return result; + } + + public int getNumberOfStatements(CGNode node) { + assert understands(node); + return getIR(node).getInstructions().length; + } + + public boolean understands(CGNode node) { + if (node == null) { + throw new IllegalArgumentException("node is null"); + } + return (node.getMethod().getReference().equals(CLONE) && ContextUtil.getConcreteClassFromContext(node.getContext()) != null); + } + + public Iterator iterateNewSites(CGNode node) { + if (node == null) { + throw new IllegalArgumentException("node is null"); + } + assert understands(node); + IClass cls = ContextUtil.getConcreteClassFromContext(node.getContext()); + return new NonNullSingletonIterator(NewSiteReference.make(NEW_PC, cls.getReference())); + } + + public Iterator iterateCallSites(CGNode node) { + assert understands(node); + return new NonNullSingletonIterator(ARRAYCOPY_SITE); + } + + /** + * @return an array of statements that encode the behavior of the clone method for a given type. + */ + private SSAInstruction[] makeStatements(IClass klass) { + assert klass != null; + + ArrayList statements = new ArrayList(); + // 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(insts.ArrayLengthInstruction(length, 1)); + int[] sizes = new int[((ArrayClass)klass).getDimensionality()]; + Arrays.fill(sizes, length); + N = insts.NewInstruction(retValue, ref, sizes); + } else { + N = insts.NewInstruction(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 = insts.InvokeInstruction(params, exceptionValue, ARRAYCOPY_SITE); + statements.add(S); + } else { + // copy the fields over, one by one. + // TODO: + IClass k = klass; + while (k != null) { + for (Iterator it = klass.getDeclaredInstanceFields().iterator(); it.hasNext();) { + IField f = it.next(); + int tempValue = nextLocal++; + SSAGetInstruction G = insts.GetInstruction(tempValue, 1, f.getReference()); + statements.add(G); + SSAPutInstruction P = insts.PutInstruction(retValue, tempValue, f.getReference()); + statements.add(P); + } + k = k.getSuperclass(); + } + + } + + SSAReturnInstruction R = insts.ReturnInstruction(retValue, false); + statements.add(R); + + SSAInstruction[] result = new SSAInstruction[statements.size()]; + Iterator 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) { + assert klass != null; + SSAInstruction instrs[] = makeStatements(klass); + return new SyntheticIR(method, context, new InducedCFG(instrs, method, context), instrs, SSAOptions.defaultOptions(), null); + } + + /* + * @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; + } + + public Iterator iterateFieldsRead(CGNode node) { + SSAInstruction[] statements = getIR(node).getInstructions(); + return CodeScanner.getFieldsRead(statements).iterator(); + } + + public Iterator iterateFieldsWritten(CGNode node) { + SSAInstruction[] statements = getIR(node).getInstructions(); + return CodeScanner.getFieldsWritten(statements).iterator(); + } + + public Set getCaughtExceptions(CGNode node) { + SSAInstruction[] statements = getIR(node).getInstructions(); + return CodeScanner.getCaughtExceptions(node.getMethod().getDeclaringClass().getClassLoader().getLanguage(), statements); + } + + public boolean hasObjectArrayLoad(CGNode node) { + SSAInstruction[] statements = getIR(node).getInstructions(); + return CodeScanner.hasObjectArrayLoad(statements); + } + + public boolean hasObjectArrayStore(CGNode node) { + SSAInstruction[] statements = getIR(node).getInstructions(); + return CodeScanner.hasObjectArrayStore(statements); + } + + public Iterator iterateCastTypes(CGNode node) { + SSAInstruction[] statements = getIR(node).getInstructions(); + return CodeScanner.iterateCastTypes(statements); + } + + public ControlFlowGraph getCFG(CGNode N) { + return getIR(N).getControlFlowGraph(); + } + + public DefUse getDU(CGNode node) { + return new DefUse(getIR(node)); + } +} diff --git a/com.ibm.wala.core/src/com/ibm/wala/analysis/reflection/FactoryBypassInterpreter.java b/com.ibm.wala.core/src/com/ibm/wala/analysis/reflection/FactoryBypassInterpreter.java index 61a3af2cd..3abd8382b 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/analysis/reflection/FactoryBypassInterpreter.java +++ b/com.ibm.wala.core/src/com/ibm/wala/analysis/reflection/FactoryBypassInterpreter.java @@ -1,624 +1,624 @@ -/******************************************************************************* - * 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.ArrayClass; -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.AnalysisCache; -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.cha.IClassHierarchy; -import com.ibm.wala.ipa.summaries.SummarizedMethod; -import com.ibm.wala.ipa.summaries.SyntheticIR; -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.ISSABasicBlock; -import com.ibm.wala.ssa.SSAInstruction; -import com.ibm.wala.ssa.SSAInstructionFactory; -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.FieldReference; -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.warnings.Warnings; - -/** - * Logic to interpret "factory" methods in context. - */ -class FactoryBypassInterpreter extends AbstractReflectionInterpreter { - - /** - * A Map from CallerSiteContext -> Set represents the types a factory method might create in a particular context - */ - private final Map> map = HashMapFactory.make(); - - /** - * A cache of synthetic method implementations, indexed by Context - */ - private final Map syntheticMethodCache = HashMapFactory.make(); - - /** - * @param options governing analysis options - */ - public FactoryBypassInterpreter(AnalysisOptions options, AnalysisCache cache) { - this.options = options; - this.cache = cache; - } - - public IR getIR(CGNode node) { - if (node == null) { - throw new IllegalArgumentException("node is null"); - } - if (DEBUG) { - System.err.println("generating IR for " + node); - } - SpecializedFactoryMethod m = findOrCreateSpecializedFactoryMethod(node); - return cache.getSSACache().findOrCreateIR(m, node.getContext(), options.getSSAOptions()); - } - - private Set getTypesForContext(Context context) { - // first try user spec - // XMLReflectionReader spec = (XMLReflectionReader) userSpec; - // if (spec != null && context instanceof CallerSiteContext) { - // CallerSiteContext site = (CallerSiteContext) context; - // MemberReference m = site.getCaller().getMethod().getReference(); - // ReflectionSummary summary = spec.getSummary(m); - // if (summary != null) { - // Set types = summary.getTypesForProgramLocation(site.getCallSite().getProgramCounter()); - // if (types != null) { - // return types; - // } - // } - // } - - Set types = map.get(context); - return types; - } - - /* - * @see com.ibm.wala.ipa.callgraph.propagation.SSAContextInterpreter#getNumberOfStatements(com.ibm.wala.ipa.callgraph.CGNode) - */ - public int getNumberOfStatements(CGNode node) { - if (node == null) { - throw new IllegalArgumentException("node is null"); - } - SpecializedFactoryMethod m = findOrCreateSpecializedFactoryMethod(node); - return m.allInstructions.size(); - } - - /* - * @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) { - if (node == null) { - throw new IllegalArgumentException("node is null"); - } - if (node.getMethod().isSynthetic()) { - SyntheticMethod s = (SyntheticMethod) node.getMethod(); - if (s.isFactoryMethod()) { - return getTypesForContext(node.getContext()) != null; - } - } - return false; - - } - - public Iterator iterateNewSites(CGNode node) { - if (node == null) { - throw new IllegalArgumentException("node is null"); - } - SpecializedFactoryMethod m = findOrCreateSpecializedFactoryMethod(node); - HashSet result = HashSetFactory.make(5); - for (Iterator it = m.getAllocationStatements().iterator(); it.hasNext();) { - SSANewInstruction s = (SSANewInstruction) it.next(); - result.add(s.getNewSite()); - } - return result.iterator(); - } - - public Iterator getInvokeStatements(CGNode node) { - if (node == null) { - throw new IllegalArgumentException("node is null"); - } - SpecializedFactoryMethod m = findOrCreateSpecializedFactoryMethod(node); - return m.getInvokeStatements().iterator(); - } - - public Iterator iterateCallSites(CGNode node) { - final Iterator I = getInvokeStatements(node); - return new Iterator() { - public boolean hasNext() { - return I.hasNext(); - } - - public CallSiteReference next() { - SSAInvokeInstruction s = (SSAInvokeInstruction) I.next(); - return s.getCallSite(); - } - - public void remove() { - Assertions.UNREACHABLE(); - } - }; - } - - public boolean recordType(IClassHierarchy cha, Context context, TypeReference type) { - Set 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(cha, type); - m.addStatementsForTypeAbstraction(T); - cache.getSSACache().invalidate(m, context); - } - return true; - } - } - - /* - * @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) { - if (klass == null) { - throw new IllegalArgumentException("klass is null"); - } - if (node == null) { - throw new IllegalArgumentException("node is null"); - } - return recordType(node.getMethod().getClassHierarchy(), node.getContext(), klass.getReference()); - } - - public Iterator iterateFieldsRead(CGNode node) { - if (node == null) { - throw new IllegalArgumentException("node is null"); - } - SpecializedFactoryMethod m = findOrCreateSpecializedFactoryMethod(node); - try { - return CodeScanner.getFieldsRead(m).iterator(); - } catch (InvalidClassFileException e) { - e.printStackTrace(); - Assertions.UNREACHABLE(); - return null; - } - } - - public Iterator iterateFieldsWritten(CGNode node) { - if (node == null) { - throw new IllegalArgumentException("node is null"); - } - SpecializedFactoryMethod m = findOrCreateSpecializedFactoryMethod(node); - try { - return CodeScanner.getFieldsWritten(m).iterator(); - } 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) { - if (node == null) { - throw new IllegalArgumentException("node is null"); - } - SpecializedFactoryMethod m = findOrCreateSpecializedFactoryMethod(node); - try { - return CodeScanner.getCaughtExceptions(m); - } catch (InvalidClassFileException e) { - e.printStackTrace(); - Assertions.UNREACHABLE(); - return null; - } - } - - public boolean hasObjectArrayLoad(CGNode node) { - if (node == null) { - throw new IllegalArgumentException("node is null"); - } - SpecializedFactoryMethod m = findOrCreateSpecializedFactoryMethod(node); - try { - return CodeScanner.hasObjectArrayLoad(m); - } catch (InvalidClassFileException e) { - e.printStackTrace(); - Assertions.UNREACHABLE(); - return false; - } - } - - public boolean hasObjectArrayStore(CGNode node) { - if (node == null) { - throw new IllegalArgumentException("node is null"); - } - SpecializedFactoryMethod m = findOrCreateSpecializedFactoryMethod(node); - try { - return CodeScanner.hasObjectArrayStore(m); - } catch (InvalidClassFileException e) { - e.printStackTrace(); - Assertions.UNREACHABLE(); - return false; - } - } - - public Iterator iterateCastTypes(CGNode node) { - if (node == null) { - throw new IllegalArgumentException("node is null"); - } - SpecializedFactoryMethod m = findOrCreateSpecializedFactoryMethod(node); - try { - return CodeScanner.iterateCastTypes(m); - } catch (InvalidClassFileException e) { - e.printStackTrace(); - Assertions.UNREACHABLE(); - return null; - } - } - - /* - * @see com.ibm.wala.ipa.callgraph.propagation.SSAContextInterpreter#getCFG(com.ibm.wala.ipa.callgraph.CGNode) - */ - public ControlFlowGraph getCFG(CGNode N) { - return getIR(N).getControlFlowGraph(); - } - - public DefUse getDU(CGNode node) { - if (node == null) { - throw new IllegalArgumentException("node is null"); - } - SpecializedFactoryMethod m = findOrCreateSpecializedFactoryMethod(node); - return cache.getSSACache().findOrCreateDU(m, node.getContext(), options.getSSAOptions()); - } - - protected class SpecializedFactoryMethod extends SpecializedMethod { - - /** - * List of synthetic invoke instructions we model for this specialized instance. - */ - final private ArrayList calls = new ArrayList(); - - /** - * 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 final SSAInstructionFactory insts = declaringClass.getClassLoader().getInstructionFactory(); - - private void initValueNumberForConstantOne() { - if (valueNumberForConstantOne == -1) { - valueNumberForConstantOne = nextLocal++; - } - } - - protected SpecializedFactoryMethod(final SummarizedMethod m, Context context, final Set S) { - super(m, m.getDeclaringClass(), m.isStatic(), true); - - this.context = context; - if (DEBUG) { - System.err.println(("Create SpecializedFactoryMethod " + m + S)); - } - - this.method = m; - assert S != null; - 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(m.getClassHierarchy(), type); - addStatementsForTypeAbstraction(T); - } - } - - protected void addStatementsForTypeAbstraction(TypeAbstraction T) { - - if (DEBUG) { - System.err.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); - - if (DEBUG) { - IClass klass = options.getClassTargetSelector().getAllocatedTarget(null, site); - System.err.println(("Selected allocated target: " + klass + " for " + T)); - } - if (T instanceof PointType) { - if (!typesAllocated.contains(ref)) { - addStatementsForConcreteType(ref); - } - } else if (T instanceof ConeType) { - if (DEBUG) { - System.err.println(("Cone clause for " + T)); - } - if (((ConeType) T).isInterface()) { - Set implementors = T.getType().getClassHierarchy().getImplementors(ref); - if (DEBUG) { - System.err.println(("Implementors for " + T + " " + implementors)); - } - if (implementors.isEmpty()) { - if (DEBUG) { - System.err.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 = T.getType().getClassHierarchy().computeSubClasses(ref); - if (DEBUG) { - System.err.println(("Subclasses for " + T + " " + subclasses)); - } - if (subclasses.isEmpty()) { - if (DEBUG) { - System.err.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) { - // This code has clearly bitrotted, since iteratePoints() returns an Iterator - // and we need an Iterator. Commenting out for now. --MS - Assertions.UNREACHABLE(); - // 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) { - int alloc = addStatementsForConcreteSimpleType(T); - if (alloc == -1) { - return; - } - 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 = insts.InvokeInstruction(params, exc, site); - calls.add(s); - allInstructions.add(s); - } - } - - private int addOriginalStatements(SummarizedMethod m) { - SSAInstruction[] original = m.getStatements(options.getSSAOptions()); - // 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 = insts.ReturnInstruction(nextLocal, false); - allInstructions.add(r); - } - - for (; it.hasNext();) { - IClass klass = it.next(); - TypeReference T = klass.getReference(); - if (klass.isAbstract() || klass.isInterface() || typesAllocated.contains(T)) { - continue; - } - typesAllocated.add(T); - int i = getLocalForType(T); - NewSiteReference ref = NewSiteReference.make(getNewSiteForType(T), T); - SSANewInstruction a = null; - if (T.isArrayType()) { - int[] sizes = new int[((ArrayClass)klass).getDimensionality()]; - initValueNumberForConstantOne(); - Arrays.fill(sizes, valueNumberForConstantOne); - a = insts.NewInstruction(i, ref, sizes); - - } else { - a = insts.NewInstruction(i, ref); - } - allocations.add(a); - allInstructions.add(a); - SSAReturnInstruction r = insts.ReturnInstruction(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 = insts.InvokeInstruction(params, getExceptionsForType(T), site); - calls.add(s); - allInstructions.add(s); - } - } - - public List getAllocationStatements() { - return allocations; - } - - public List 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) - */ - @Override - public boolean equals(Object obj) { - return this == obj; - } - - @Override - public int hashCode() { // TODO: change this to avoid non-determinism! - return System.identityHashCode(this); - } - - @Override - public String toString() { - return super.toString(); - } - - @Override - public SSAInstruction[] getStatements() { - SSAInstruction[] result = new SSAInstruction[allInstructions.size()]; - int i = 0; - for (Iterator it = allInstructions.iterator(); it.hasNext();) { - result[i++] = it.next(); - } - return result; - } - - @Override - public IClass getDeclaringClass() { - assert method.getDeclaringClass() != null : "null declaring class for original method " + method; - return method.getDeclaringClass(); - } - - @Override - public int getNumberOfParameters() { - return method.getNumberOfParameters(); - } - - @Override - public TypeReference getParameterType(int i) { - return method.getParameterType(i); - } - - /* - * @see com.ibm.wala.classLoader.IMethod#getIR(com.ibm.wala.util.WarningSet) - */ - @Override - public IR makeIR(Context C, SSAOptions options) { - SSAInstruction[] instrs = getStatements(); - Map 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); - } - } -} +/******************************************************************************* + * 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.ArrayClass; +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.AnalysisCache; +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.cha.IClassHierarchy; +import com.ibm.wala.ipa.summaries.SummarizedMethod; +import com.ibm.wala.ipa.summaries.SyntheticIR; +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.ISSABasicBlock; +import com.ibm.wala.ssa.SSAInstruction; +import com.ibm.wala.ssa.SSAInstructionFactory; +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.FieldReference; +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.warnings.Warnings; + +/** + * Logic to interpret "factory" methods in context. + */ +class FactoryBypassInterpreter extends AbstractReflectionInterpreter { + + /** + * A Map from CallerSiteContext -> Set represents the types a factory method might create in a particular context + */ + private final Map> map = HashMapFactory.make(); + + /** + * A cache of synthetic method implementations, indexed by Context + */ + private final Map syntheticMethodCache = HashMapFactory.make(); + + /** + * @param options governing analysis options + */ + public FactoryBypassInterpreter(AnalysisOptions options, AnalysisCache cache) { + this.options = options; + this.cache = cache; + } + + public IR getIR(CGNode node) { + if (node == null) { + throw new IllegalArgumentException("node is null"); + } + if (DEBUG) { + System.err.println("generating IR for " + node); + } + SpecializedFactoryMethod m = findOrCreateSpecializedFactoryMethod(node); + return cache.getSSACache().findOrCreateIR(m, node.getContext(), options.getSSAOptions()); + } + + private Set getTypesForContext(Context context) { + // first try user spec + // XMLReflectionReader spec = (XMLReflectionReader) userSpec; + // if (spec != null && context instanceof CallerSiteContext) { + // CallerSiteContext site = (CallerSiteContext) context; + // MemberReference m = site.getCaller().getMethod().getReference(); + // ReflectionSummary summary = spec.getSummary(m); + // if (summary != null) { + // Set types = summary.getTypesForProgramLocation(site.getCallSite().getProgramCounter()); + // if (types != null) { + // return types; + // } + // } + // } + + Set types = map.get(context); + return types; + } + + /* + * @see com.ibm.wala.ipa.callgraph.propagation.SSAContextInterpreter#getNumberOfStatements(com.ibm.wala.ipa.callgraph.CGNode) + */ + public int getNumberOfStatements(CGNode node) { + if (node == null) { + throw new IllegalArgumentException("node is null"); + } + SpecializedFactoryMethod m = findOrCreateSpecializedFactoryMethod(node); + return m.allInstructions.size(); + } + + /* + * @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) { + if (node == null) { + throw new IllegalArgumentException("node is null"); + } + if (node.getMethod().isSynthetic()) { + SyntheticMethod s = (SyntheticMethod) node.getMethod(); + if (s.isFactoryMethod()) { + return getTypesForContext(node.getContext()) != null; + } + } + return false; + + } + + public Iterator iterateNewSites(CGNode node) { + if (node == null) { + throw new IllegalArgumentException("node is null"); + } + SpecializedFactoryMethod m = findOrCreateSpecializedFactoryMethod(node); + HashSet result = HashSetFactory.make(5); + for (Iterator it = m.getAllocationStatements().iterator(); it.hasNext();) { + SSANewInstruction s = (SSANewInstruction) it.next(); + result.add(s.getNewSite()); + } + return result.iterator(); + } + + public Iterator getInvokeStatements(CGNode node) { + if (node == null) { + throw new IllegalArgumentException("node is null"); + } + SpecializedFactoryMethod m = findOrCreateSpecializedFactoryMethod(node); + return m.getInvokeStatements().iterator(); + } + + public Iterator iterateCallSites(CGNode node) { + final Iterator I = getInvokeStatements(node); + return new Iterator() { + public boolean hasNext() { + return I.hasNext(); + } + + public CallSiteReference next() { + SSAInvokeInstruction s = (SSAInvokeInstruction) I.next(); + return s.getCallSite(); + } + + public void remove() { + Assertions.UNREACHABLE(); + } + }; + } + + public boolean recordType(IClassHierarchy cha, Context context, TypeReference type) { + Set 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(cha, type); + m.addStatementsForTypeAbstraction(T); + cache.getSSACache().invalidate(m, context); + } + return true; + } + } + + /* + * @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) { + if (klass == null) { + throw new IllegalArgumentException("klass is null"); + } + if (node == null) { + throw new IllegalArgumentException("node is null"); + } + return recordType(node.getMethod().getClassHierarchy(), node.getContext(), klass.getReference()); + } + + public Iterator iterateFieldsRead(CGNode node) { + if (node == null) { + throw new IllegalArgumentException("node is null"); + } + SpecializedFactoryMethod m = findOrCreateSpecializedFactoryMethod(node); + try { + return CodeScanner.getFieldsRead(m).iterator(); + } catch (InvalidClassFileException e) { + e.printStackTrace(); + Assertions.UNREACHABLE(); + return null; + } + } + + public Iterator iterateFieldsWritten(CGNode node) { + if (node == null) { + throw new IllegalArgumentException("node is null"); + } + SpecializedFactoryMethod m = findOrCreateSpecializedFactoryMethod(node); + try { + return CodeScanner.getFieldsWritten(m).iterator(); + } 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) { + if (node == null) { + throw new IllegalArgumentException("node is null"); + } + SpecializedFactoryMethod m = findOrCreateSpecializedFactoryMethod(node); + try { + return CodeScanner.getCaughtExceptions(m); + } catch (InvalidClassFileException e) { + e.printStackTrace(); + Assertions.UNREACHABLE(); + return null; + } + } + + public boolean hasObjectArrayLoad(CGNode node) { + if (node == null) { + throw new IllegalArgumentException("node is null"); + } + SpecializedFactoryMethod m = findOrCreateSpecializedFactoryMethod(node); + try { + return CodeScanner.hasObjectArrayLoad(m); + } catch (InvalidClassFileException e) { + e.printStackTrace(); + Assertions.UNREACHABLE(); + return false; + } + } + + public boolean hasObjectArrayStore(CGNode node) { + if (node == null) { + throw new IllegalArgumentException("node is null"); + } + SpecializedFactoryMethod m = findOrCreateSpecializedFactoryMethod(node); + try { + return CodeScanner.hasObjectArrayStore(m); + } catch (InvalidClassFileException e) { + e.printStackTrace(); + Assertions.UNREACHABLE(); + return false; + } + } + + public Iterator iterateCastTypes(CGNode node) { + if (node == null) { + throw new IllegalArgumentException("node is null"); + } + SpecializedFactoryMethod m = findOrCreateSpecializedFactoryMethod(node); + try { + return CodeScanner.iterateCastTypes(m); + } catch (InvalidClassFileException e) { + e.printStackTrace(); + Assertions.UNREACHABLE(); + return null; + } + } + + /* + * @see com.ibm.wala.ipa.callgraph.propagation.SSAContextInterpreter#getCFG(com.ibm.wala.ipa.callgraph.CGNode) + */ + public ControlFlowGraph getCFG(CGNode N) { + return getIR(N).getControlFlowGraph(); + } + + public DefUse getDU(CGNode node) { + if (node == null) { + throw new IllegalArgumentException("node is null"); + } + SpecializedFactoryMethod m = findOrCreateSpecializedFactoryMethod(node); + return cache.getSSACache().findOrCreateDU(m, node.getContext(), options.getSSAOptions()); + } + + protected class SpecializedFactoryMethod extends SpecializedMethod { + + /** + * List of synthetic invoke instructions we model for this specialized instance. + */ + final private ArrayList calls = new ArrayList(); + + /** + * 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 final SSAInstructionFactory insts = declaringClass.getClassLoader().getInstructionFactory(); + + private void initValueNumberForConstantOne() { + if (valueNumberForConstantOne == -1) { + valueNumberForConstantOne = nextLocal++; + } + } + + protected SpecializedFactoryMethod(final SummarizedMethod m, Context context, final Set S) { + super(m, m.getDeclaringClass(), m.isStatic(), true); + + this.context = context; + if (DEBUG) { + System.err.println(("Create SpecializedFactoryMethod " + m + S)); + } + + this.method = m; + assert S != null; + 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(m.getClassHierarchy(), type); + addStatementsForTypeAbstraction(T); + } + } + + protected void addStatementsForTypeAbstraction(TypeAbstraction T) { + + if (DEBUG) { + System.err.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); + + if (DEBUG) { + IClass klass = options.getClassTargetSelector().getAllocatedTarget(null, site); + System.err.println(("Selected allocated target: " + klass + " for " + T)); + } + if (T instanceof PointType) { + if (!typesAllocated.contains(ref)) { + addStatementsForConcreteType(ref); + } + } else if (T instanceof ConeType) { + if (DEBUG) { + System.err.println(("Cone clause for " + T)); + } + if (((ConeType) T).isInterface()) { + Set implementors = T.getType().getClassHierarchy().getImplementors(ref); + if (DEBUG) { + System.err.println(("Implementors for " + T + " " + implementors)); + } + if (implementors.isEmpty()) { + if (DEBUG) { + System.err.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 = T.getType().getClassHierarchy().computeSubClasses(ref); + if (DEBUG) { + System.err.println(("Subclasses for " + T + " " + subclasses)); + } + if (subclasses.isEmpty()) { + if (DEBUG) { + System.err.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) { + // This code has clearly bitrotted, since iteratePoints() returns an Iterator + // and we need an Iterator. Commenting out for now. --MS + Assertions.UNREACHABLE(); + // 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) { + int alloc = addStatementsForConcreteSimpleType(T); + if (alloc == -1) { + return; + } + 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 = insts.InvokeInstruction(params, exc, site); + calls.add(s); + allInstructions.add(s); + } + } + + private int addOriginalStatements(SummarizedMethod m) { + SSAInstruction[] original = m.getStatements(options.getSSAOptions()); + // 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 = insts.ReturnInstruction(nextLocal, false); + allInstructions.add(r); + } + + for (; it.hasNext();) { + IClass klass = it.next(); + TypeReference T = klass.getReference(); + if (klass.isAbstract() || klass.isInterface() || typesAllocated.contains(T)) { + continue; + } + typesAllocated.add(T); + int i = getLocalForType(T); + NewSiteReference ref = NewSiteReference.make(getNewSiteForType(T), T); + SSANewInstruction a = null; + if (T.isArrayType()) { + int[] sizes = new int[((ArrayClass)klass).getDimensionality()]; + initValueNumberForConstantOne(); + Arrays.fill(sizes, valueNumberForConstantOne); + a = insts.NewInstruction(i, ref, sizes); + + } else { + a = insts.NewInstruction(i, ref); + } + allocations.add(a); + allInstructions.add(a); + SSAReturnInstruction r = insts.ReturnInstruction(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 = insts.InvokeInstruction(params, getExceptionsForType(T), site); + calls.add(s); + allInstructions.add(s); + } + } + + public List getAllocationStatements() { + return allocations; + } + + public List 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) + */ + @Override + public boolean equals(Object obj) { + return this == obj; + } + + @Override + public int hashCode() { // TODO: change this to avoid non-determinism! + return System.identityHashCode(this); + } + + @Override + public String toString() { + return super.toString(); + } + + @Override + public SSAInstruction[] getStatements() { + SSAInstruction[] result = new SSAInstruction[allInstructions.size()]; + int i = 0; + for (Iterator it = allInstructions.iterator(); it.hasNext();) { + result[i++] = it.next(); + } + return result; + } + + @Override + public IClass getDeclaringClass() { + assert method.getDeclaringClass() != null : "null declaring class for original method " + method; + return method.getDeclaringClass(); + } + + @Override + public int getNumberOfParameters() { + return method.getNumberOfParameters(); + } + + @Override + public TypeReference getParameterType(int i) { + return method.getParameterType(i); + } + + /* + * @see com.ibm.wala.classLoader.IMethod#getIR(com.ibm.wala.util.WarningSet) + */ + @Override + public IR makeIR(Context C, SSAOptions options) { + SSAInstruction[] instrs = getStatements(); + Map 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); + } + } +} diff --git a/com.ibm.wala.core/src/com/ibm/wala/analysis/reflection/FactoryContextSelector.java b/com.ibm.wala.core/src/com/ibm/wala/analysis/reflection/FactoryContextSelector.java index 7385a7bde..0d2f04599 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/analysis/reflection/FactoryContextSelector.java +++ b/com.ibm.wala.core/src/com/ibm/wala/analysis/reflection/FactoryContextSelector.java @@ -1,53 +1,53 @@ -/******************************************************************************* - * Copyright (c) 2002 - 2006 IBM Corporation. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * IBM Corporation - initial API and implementation - *******************************************************************************/ -package com.ibm.wala.analysis.reflection; - -import com.ibm.wala.classLoader.CallSiteReference; -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.propagation.InstanceKey; -import com.ibm.wala.ipa.callgraph.propagation.cfa.CallString; -import com.ibm.wala.ipa.callgraph.propagation.cfa.CallStringContext; -import com.ibm.wala.util.intset.EmptyIntSet; -import com.ibm.wala.util.intset.IntSet; - -/** - * For synthetic methods marked as "Factories", we analyze in a context defined by the caller. - */ -class FactoryContextSelector implements ContextSelector { - - public FactoryContextSelector() { - } - - /* - * @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 == null) { - throw new IllegalArgumentException("callee is null"); - } - if (callee.isSynthetic()) { - SyntheticMethod s = (SyntheticMethod) callee; - if (s.isFactoryMethod()) { - return new CallStringContext(new CallString(site, caller.getMethod())); - } - } - return null; - } - - public IntSet getRelevantParameters(CGNode caller, CallSiteReference site) { - return EmptyIntSet.instance; - } - -} +/******************************************************************************* + * 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.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.propagation.InstanceKey; +import com.ibm.wala.ipa.callgraph.propagation.cfa.CallString; +import com.ibm.wala.ipa.callgraph.propagation.cfa.CallStringContext; +import com.ibm.wala.util.intset.EmptyIntSet; +import com.ibm.wala.util.intset.IntSet; + +/** + * For synthetic methods marked as "Factories", we analyze in a context defined by the caller. + */ +class FactoryContextSelector implements ContextSelector { + + public FactoryContextSelector() { + } + + /* + * @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 == null) { + throw new IllegalArgumentException("callee is null"); + } + if (callee.isSynthetic()) { + SyntheticMethod s = (SyntheticMethod) callee; + if (s.isFactoryMethod()) { + return new CallStringContext(new CallString(site, caller.getMethod())); + } + } + return null; + } + + public IntSet getRelevantParameters(CGNode caller, CallSiteReference site) { + return EmptyIntSet.instance; + } + +} diff --git a/com.ibm.wala.core/src/com/ibm/wala/analysis/reflection/GetClassContextInterpeter.java b/com.ibm.wala.core/src/com/ibm/wala/analysis/reflection/GetClassContextInterpeter.java index 0c406cd2c..b03758c46 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/analysis/reflection/GetClassContextInterpeter.java +++ b/com.ibm.wala.core/src/com/ibm/wala/analysis/reflection/GetClassContextInterpeter.java @@ -1,123 +1,123 @@ -/******************************************************************************* - * Copyright (c) 2008 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.Iterator; - -import com.ibm.wala.cfg.ControlFlowGraph; -import com.ibm.wala.cfg.InducedCFG; -import com.ibm.wala.classLoader.CallSiteReference; -import com.ibm.wala.classLoader.IClass; -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.propagation.SSAContextInterpreter; -import com.ibm.wala.ipa.summaries.SyntheticIR; -import com.ibm.wala.ssa.DefUse; -import com.ibm.wala.ssa.IR; -import com.ibm.wala.ssa.ISSABasicBlock; -import com.ibm.wala.ssa.SSAInstruction; -import com.ibm.wala.ssa.SSAInstructionFactory; -import com.ibm.wala.ssa.SSALoadMetadataInstruction; -import com.ibm.wala.ssa.SSAOptions; -import com.ibm.wala.ssa.SSAReturnInstruction; -import com.ibm.wala.types.FieldReference; -import com.ibm.wala.types.TypeReference; -import com.ibm.wala.util.collections.EmptyIterator; - -/** - * {@link SSAContextInterpreter} specialized to interpret Object.getClass() in a {@link JavaTypeContext} - */ -public class GetClassContextInterpeter implements SSAContextInterpreter { - - private static final boolean DEBUG = false; - - public IR getIR(CGNode node) { - if (node == null) { - throw new IllegalArgumentException("node is null"); - } - assert understands(node); - if (DEBUG) { - System.err.println("generating IR for " + node); - } - IR result = makeIR(node.getMethod(), (JavaTypeContext) node.getContext()); - return result; - } - - public int getNumberOfStatements(CGNode node) { - assert understands(node); - return getIR(node).getInstructions().length; - } - - public boolean understands(CGNode node) { - if (node == null) { - throw new IllegalArgumentException("node is null"); - } - if (!(node.getContext() instanceof JavaTypeContext)) { - return false; - } - return node.getMethod().getReference().equals(GetClassContextSelector.GET_CLASS); - } - - public Iterator iterateNewSites(CGNode node) { - return EmptyIterator.instance(); - } - - public Iterator iterateCallSites(CGNode node) { - return EmptyIterator.instance(); - } - - private SSAInstruction[] makeStatements(JavaTypeContext context) { - ArrayList statements = new ArrayList(); - int nextLocal = 2; - int retValue = nextLocal++; - TypeReference tr = context.getType().getTypeReference(); - SSAInstructionFactory insts = context.getType().getType().getClassLoader().getInstructionFactory(); - if (tr != null) { - SSALoadMetadataInstruction l = insts.LoadMetadataInstruction(retValue, TypeReference.JavaLangClass, tr); - statements.add(l); - SSAReturnInstruction R = insts.ReturnInstruction(retValue, false); - statements.add(R); - } - SSAInstruction[] result = new SSAInstruction[statements.size()]; - Iterator it = statements.iterator(); - for (int i = 0; i < result.length; i++) { - result[i] = it.next(); - } - return result; - } - - private IR makeIR(IMethod method, JavaTypeContext context) { - SSAInstruction instrs[] = makeStatements(context); - return new SyntheticIR(method, context, new InducedCFG(instrs, method, context), instrs, SSAOptions.defaultOptions(), null); - } - - public boolean recordFactoryType(CGNode node, IClass klass) { - return false; - } - - public Iterator iterateFieldsRead(CGNode node) { - return EmptyIterator.instance(); - } - - public Iterator iterateFieldsWritten(CGNode node) { - return EmptyIterator.instance(); - } - - public ControlFlowGraph getCFG(CGNode N) { - return getIR(N).getControlFlowGraph(); - } - - public DefUse getDU(CGNode node) { - return new DefUse(getIR(node)); - } -} +/******************************************************************************* + * Copyright (c) 2008 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.Iterator; + +import com.ibm.wala.cfg.ControlFlowGraph; +import com.ibm.wala.cfg.InducedCFG; +import com.ibm.wala.classLoader.CallSiteReference; +import com.ibm.wala.classLoader.IClass; +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.propagation.SSAContextInterpreter; +import com.ibm.wala.ipa.summaries.SyntheticIR; +import com.ibm.wala.ssa.DefUse; +import com.ibm.wala.ssa.IR; +import com.ibm.wala.ssa.ISSABasicBlock; +import com.ibm.wala.ssa.SSAInstruction; +import com.ibm.wala.ssa.SSAInstructionFactory; +import com.ibm.wala.ssa.SSALoadMetadataInstruction; +import com.ibm.wala.ssa.SSAOptions; +import com.ibm.wala.ssa.SSAReturnInstruction; +import com.ibm.wala.types.FieldReference; +import com.ibm.wala.types.TypeReference; +import com.ibm.wala.util.collections.EmptyIterator; + +/** + * {@link SSAContextInterpreter} specialized to interpret Object.getClass() in a {@link JavaTypeContext} + */ +public class GetClassContextInterpeter implements SSAContextInterpreter { + + private static final boolean DEBUG = false; + + public IR getIR(CGNode node) { + if (node == null) { + throw new IllegalArgumentException("node is null"); + } + assert understands(node); + if (DEBUG) { + System.err.println("generating IR for " + node); + } + IR result = makeIR(node.getMethod(), (JavaTypeContext) node.getContext()); + return result; + } + + public int getNumberOfStatements(CGNode node) { + assert understands(node); + return getIR(node).getInstructions().length; + } + + public boolean understands(CGNode node) { + if (node == null) { + throw new IllegalArgumentException("node is null"); + } + if (!(node.getContext() instanceof JavaTypeContext)) { + return false; + } + return node.getMethod().getReference().equals(GetClassContextSelector.GET_CLASS); + } + + public Iterator iterateNewSites(CGNode node) { + return EmptyIterator.instance(); + } + + public Iterator iterateCallSites(CGNode node) { + return EmptyIterator.instance(); + } + + private SSAInstruction[] makeStatements(JavaTypeContext context) { + ArrayList statements = new ArrayList(); + int nextLocal = 2; + int retValue = nextLocal++; + TypeReference tr = context.getType().getTypeReference(); + SSAInstructionFactory insts = context.getType().getType().getClassLoader().getInstructionFactory(); + if (tr != null) { + SSALoadMetadataInstruction l = insts.LoadMetadataInstruction(retValue, TypeReference.JavaLangClass, tr); + statements.add(l); + SSAReturnInstruction R = insts.ReturnInstruction(retValue, false); + statements.add(R); + } + SSAInstruction[] result = new SSAInstruction[statements.size()]; + Iterator it = statements.iterator(); + for (int i = 0; i < result.length; i++) { + result[i] = it.next(); + } + return result; + } + + private IR makeIR(IMethod method, JavaTypeContext context) { + SSAInstruction instrs[] = makeStatements(context); + return new SyntheticIR(method, context, new InducedCFG(instrs, method, context), instrs, SSAOptions.defaultOptions(), null); + } + + public boolean recordFactoryType(CGNode node, IClass klass) { + return false; + } + + public Iterator iterateFieldsRead(CGNode node) { + return EmptyIterator.instance(); + } + + public Iterator iterateFieldsWritten(CGNode node) { + return EmptyIterator.instance(); + } + + public ControlFlowGraph getCFG(CGNode N) { + return getIR(N).getControlFlowGraph(); + } + + public DefUse getDU(CGNode node) { + return new DefUse(getIR(node)); + } +} diff --git a/com.ibm.wala.core/src/com/ibm/wala/analysis/reflection/GetClassContextSelector.java b/com.ibm.wala.core/src/com/ibm/wala/analysis/reflection/GetClassContextSelector.java index fa69db771..694e00542 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/analysis/reflection/GetClassContextSelector.java +++ b/com.ibm.wala.core/src/com/ibm/wala/analysis/reflection/GetClassContextSelector.java @@ -1,59 +1,59 @@ -/******************************************************************************* - * Copyright (c) 2008 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.PointType; -import com.ibm.wala.classLoader.CallSiteReference; -import com.ibm.wala.classLoader.IMethod; -import com.ibm.wala.ipa.callgraph.CGNode; -import com.ibm.wala.ipa.callgraph.Context; -import com.ibm.wala.ipa.callgraph.ContextSelector; -import com.ibm.wala.ipa.callgraph.propagation.InstanceKey; -import com.ibm.wala.types.MethodReference; -import com.ibm.wala.types.TypeReference; -import com.ibm.wala.util.intset.EmptyIntSet; -import com.ibm.wala.util.intset.IntSet; -import com.ibm.wala.util.intset.IntSetUtil; - -/** - * A {@link ContextSelector} to intercept calls to Object.getClass() - */ -class GetClassContextSelector implements ContextSelector { - - public final static MethodReference GET_CLASS = MethodReference.findOrCreate(TypeReference.JavaLangObject, "getClass", - "()Ljava/lang/Class;"); - - public GetClassContextSelector() { - } - - /* - * @see com.ibm.wala.ipa.callgraph.ContextSelector#getCalleeTarget(com.ibm.wala.ipa.callgraph.CGNode, - * com.ibm.wala.classLoader.CallSiteReference, com.ibm.wala.classLoader.IMethod, - * com.ibm.wala.ipa.callgraph.propagation.InstanceKey) - */ - public Context getCalleeTarget(CGNode caller, CallSiteReference site, IMethod callee, InstanceKey[] receiver) { - if (callee.getReference().equals(GET_CLASS)) { - return new JavaTypeContext(new PointType(receiver[0].getConcreteType())); - } - return null; - } - - private static final IntSet thisParameter = IntSetUtil.make(new int[]{0}); - - public IntSet getRelevantParameters(CGNode caller, CallSiteReference site) { - if (site.isDispatch() || site.getDeclaredTarget().getNumberOfParameters() > 0) { - return thisParameter; - } else { - return EmptyIntSet.instance; - } - } - +/******************************************************************************* + * Copyright (c) 2008 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.PointType; +import com.ibm.wala.classLoader.CallSiteReference; +import com.ibm.wala.classLoader.IMethod; +import com.ibm.wala.ipa.callgraph.CGNode; +import com.ibm.wala.ipa.callgraph.Context; +import com.ibm.wala.ipa.callgraph.ContextSelector; +import com.ibm.wala.ipa.callgraph.propagation.InstanceKey; +import com.ibm.wala.types.MethodReference; +import com.ibm.wala.types.TypeReference; +import com.ibm.wala.util.intset.EmptyIntSet; +import com.ibm.wala.util.intset.IntSet; +import com.ibm.wala.util.intset.IntSetUtil; + +/** + * A {@link ContextSelector} to intercept calls to Object.getClass() + */ +class GetClassContextSelector implements ContextSelector { + + public final static MethodReference GET_CLASS = MethodReference.findOrCreate(TypeReference.JavaLangObject, "getClass", + "()Ljava/lang/Class;"); + + public GetClassContextSelector() { + } + + /* + * @see com.ibm.wala.ipa.callgraph.ContextSelector#getCalleeTarget(com.ibm.wala.ipa.callgraph.CGNode, + * com.ibm.wala.classLoader.CallSiteReference, com.ibm.wala.classLoader.IMethod, + * com.ibm.wala.ipa.callgraph.propagation.InstanceKey) + */ + public Context getCalleeTarget(CGNode caller, CallSiteReference site, IMethod callee, InstanceKey[] receiver) { + if (callee.getReference().equals(GET_CLASS)) { + return new JavaTypeContext(new PointType(receiver[0].getConcreteType())); + } + return null; + } + + private static final IntSet thisParameter = IntSetUtil.make(new int[]{0}); + + public IntSet getRelevantParameters(CGNode caller, CallSiteReference site) { + if (site.isDispatch() || site.getDeclaredTarget().getNumberOfParameters() > 0) { + return thisParameter; + } else { + return EmptyIntSet.instance; + } + } + } \ No newline at end of file diff --git a/com.ibm.wala.core/src/com/ibm/wala/analysis/reflection/IllegalArgumentExceptionContext.java b/com.ibm.wala.core/src/com/ibm/wala/analysis/reflection/IllegalArgumentExceptionContext.java index 6553bd640..6049a6ff3 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/analysis/reflection/IllegalArgumentExceptionContext.java +++ b/com.ibm.wala.core/src/com/ibm/wala/analysis/reflection/IllegalArgumentExceptionContext.java @@ -1,23 +1,23 @@ -/******************************************************************************* - * Copyright (c) 2007 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.Context; -import com.ibm.wala.ipa.callgraph.ContextItem; -import com.ibm.wala.ipa.callgraph.ContextKey; - - -public class IllegalArgumentExceptionContext implements Context { - - public ContextItem get(ContextKey name) { - return null; - } -} +/******************************************************************************* + * Copyright (c) 2007 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.Context; +import com.ibm.wala.ipa.callgraph.ContextItem; +import com.ibm.wala.ipa.callgraph.ContextKey; + + +public class IllegalArgumentExceptionContext implements Context { + + public ContextItem get(ContextKey name) { + return null; + } +} diff --git a/com.ibm.wala.core/src/com/ibm/wala/analysis/reflection/InstanceKeyWithNode.java b/com.ibm.wala.core/src/com/ibm/wala/analysis/reflection/InstanceKeyWithNode.java index 40613f934..4cca598d9 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/analysis/reflection/InstanceKeyWithNode.java +++ b/com.ibm.wala.core/src/com/ibm/wala/analysis/reflection/InstanceKeyWithNode.java @@ -1,25 +1,25 @@ -/******************************************************************************* - * Copyright (c) 2002 - 2006 IBM Corporation. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * IBM Corporation - initial API and implementation - *******************************************************************************/ -package com.ibm.wala.analysis.reflection; - -import com.ibm.wala.ipa.callgraph.CGNode; -import com.ibm.wala.ipa.callgraph.propagation.InstanceKey; - -/** - * An instance key which has an associated {@link CGNode}. - */ -public interface InstanceKeyWithNode extends InstanceKey { - - /** - * @return the node which created this instance. - */ - CGNode getNode(); -} +/******************************************************************************* + * 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 {@link CGNode}. + */ +public interface InstanceKeyWithNode extends InstanceKey { + + /** + * @return the node which created this instance. + */ + CGNode getNode(); +} diff --git a/com.ibm.wala.core/src/com/ibm/wala/analysis/reflection/JavaLangClassContextInterpreter.java b/com.ibm.wala.core/src/com/ibm/wala/analysis/reflection/JavaLangClassContextInterpreter.java index f0428c103..70481fb3b 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/analysis/reflection/JavaLangClassContextInterpreter.java +++ b/com.ibm.wala.core/src/com/ibm/wala/analysis/reflection/JavaLangClassContextInterpreter.java @@ -1,426 +1,426 @@ -/******************************************************************************* - * Copyright (c) 2008 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.Collection; -import java.util.Iterator; -import java.util.Map; - -import com.ibm.wala.cfg.ControlFlowGraph; -import com.ibm.wala.cfg.InducedCFG; -import com.ibm.wala.classLoader.CallSiteReference; -import com.ibm.wala.classLoader.IClass; -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.propagation.SSAContextInterpreter; -import com.ibm.wala.ipa.summaries.SyntheticIR; -import com.ibm.wala.ssa.ConstantValue; -import com.ibm.wala.ssa.DefUse; -import com.ibm.wala.ssa.IR; -import com.ibm.wala.ssa.ISSABasicBlock; -import com.ibm.wala.ssa.SSAArrayStoreInstruction; -import com.ibm.wala.ssa.SSAInstruction; -import com.ibm.wala.ssa.SSAInstructionFactory; -import com.ibm.wala.ssa.SSANewInstruction; -import com.ibm.wala.ssa.SSAOptions; -import com.ibm.wala.ssa.SSAReturnInstruction; -import com.ibm.wala.types.FieldReference; -import com.ibm.wala.types.MethodReference; -import com.ibm.wala.types.TypeReference; -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.NonNullSingletonIterator; -import com.ibm.wala.util.debug.Assertions; - -/** - * An {@link SSAContextInterpreter} specialized to interpret methods on java.lang.Class in a {@link JavaTypeContext} which - * represents the point-type of the class object created by the call. - * - * Currently supported methods: - *
          - *
        • getConstructor - *
        • getConstructors - *
        • getMethod - *
        • getMethods - *
        • getDeclaredConstructor - *
        • getDeclaredConstructors - *
        • getDeclaredMethod - *
        • getDeclaredMethods - *
        - */ -public class JavaLangClassContextInterpreter implements SSAContextInterpreter { - - public final static MethodReference GET_CONSTRUCTOR = MethodReference.findOrCreate(TypeReference.JavaLangClass, "getConstructor", - "([Ljava/lang/Class;)Ljava/lang/reflect/Constructor;"); - - public final static MethodReference GET_CONSTRUCTORS = MethodReference.findOrCreate(TypeReference.JavaLangClass, - "getConstructors", "()[Ljava/lang/reflect/Constructor;"); - - public final static MethodReference GET_METHOD = MethodReference.findOrCreate(TypeReference.JavaLangClass, "getMethod", - "(Ljava/lang/String;[Ljava/lang/Class;)Ljava/lang/reflect/Method;"); - - public final static MethodReference GET_METHODS = MethodReference.findOrCreate(TypeReference.JavaLangClass, "getMethods", - "()[Ljava/lang/reflect/Method;"); - - public final static MethodReference GET_DECLARED_CONSTRUCTOR = MethodReference.findOrCreate(TypeReference.JavaLangClass, - "getDeclaredConstructor", "([Ljava/lang/Class;)Ljava/lang/reflect/Constructor;"); - - public final static MethodReference GET_DECLARED_CONSTRUCTORS = MethodReference.findOrCreate(TypeReference.JavaLangClass, - "getDeclaredConstructors", "()[Ljava/lang/reflect/Constructor;"); - - public final static MethodReference GET_DECLARED_METHOD = MethodReference.findOrCreate(TypeReference.JavaLangClass, - "getDeclaredMethod", "(Ljava/lang/String;[Ljava/lang/Class;)Ljava/lang/reflect/Method;"); - - public final static MethodReference GET_DECLARED_METHODS = MethodReference.findOrCreate(TypeReference.JavaLangClass, - "getDeclaredMethods", "()[Ljava/lang/reflect/Method;"); - - private static final boolean DEBUG = false; - - /* - * @see com.ibm.wala.ipa.callgraph.propagation.SSAContextInterpreter#getIR(com.ibm.wala.ipa.callgraph.CGNode) - */ - public IR getIR(CGNode node) { - if (node == null) { - throw new IllegalArgumentException("node is null"); - } - assert understands(node); - if (DEBUG) { - System.err.println("generating IR for " + node); - } - IMethod method = node.getMethod(); - JavaTypeContext context = (JavaTypeContext) node.getContext(); - Map constants = HashMapFactory.make(); - if (method.getReference().equals(GET_CONSTRUCTOR)) { - SSAInstruction instrs[] = makeGetCtorStatements(context, constants); - return new SyntheticIR(method, context, new InducedCFG(instrs, method, context), instrs, SSAOptions.defaultOptions(), - constants); - } - if (method.getReference().equals(GET_CONSTRUCTORS)) { - SSAInstruction instrs[] = makeGetCtorsStatements(context, constants); - return new SyntheticIR(method, context, new InducedCFG(instrs, method, context), instrs, SSAOptions.defaultOptions(), - constants); - } - if (method.getReference().equals(GET_METHOD)) { - SSAInstruction instrs[] = makeGetMethodStatements(context, constants); - return new SyntheticIR(method, context, new InducedCFG(instrs, method, context), instrs, SSAOptions.defaultOptions(), - constants); - } - if (method.getReference().equals(GET_METHODS)) { - SSAInstruction instrs[] = makeGetMethodsStatments(context, constants); - return new SyntheticIR(method, context, new InducedCFG(instrs, method, context), instrs, SSAOptions.defaultOptions(), - constants); - } - if (method.getReference().equals(GET_DECLARED_CONSTRUCTOR)) { - SSAInstruction instrs[] = makeGetDeclCtorStatements(context, constants); - return new SyntheticIR(method, context, new InducedCFG(instrs, method, context), instrs, SSAOptions.defaultOptions(), - constants); - } - if (method.getReference().equals(GET_DECLARED_CONSTRUCTORS)) { - SSAInstruction instrs[] = makeGetDeclCtorsStatements(context, constants); - return new SyntheticIR(method, context, new InducedCFG(instrs, method, context), instrs, SSAOptions.defaultOptions(), - constants); - } - if (method.getReference().equals(GET_DECLARED_METHOD)) { - SSAInstruction instrs[] = makeGetDeclaredMethodStatements(context, constants); - return new SyntheticIR(method, context, new InducedCFG(instrs, method, context), instrs, SSAOptions.defaultOptions(), - constants); - } - if (method.getReference().equals(GET_DECLARED_METHODS)) { - SSAInstruction instrs[] = makeGetDeclaredMethodsStatements(context, constants); - return new SyntheticIR(method, context, new InducedCFG(instrs, method, context), instrs, SSAOptions.defaultOptions(), - constants); - } - Assertions.UNREACHABLE("Unexpected method " + node); - return null; - } - - /* - * @see com.ibm.wala.ipa.callgraph.propagation.SSAContextInterpreter#getNumberOfStatements(com.ibm.wala.ipa.callgraph.CGNode) - */ - public int getNumberOfStatements(CGNode node) { - assert understands(node); - return getIR(node).getInstructions().length; - } - - /* - * @see com.ibm.wala.ipa.callgraph.propagation.rta.RTAContextInterpreter#understands(com.ibm.wala.ipa.callgraph.CGNode) - */ - public boolean understands(CGNode node) { - if (node == null) { - throw new IllegalArgumentException("node is null"); - } - if (!(node.getContext() instanceof JavaTypeContext)) { - return false; - } - MethodReference mRef = node.getMethod().getReference(); - return mRef.equals(GET_CONSTRUCTOR) || mRef.equals(GET_CONSTRUCTORS) || mRef.equals(GET_METHOD) || mRef.equals(GET_METHODS) - || mRef.equals(GET_DECLARED_CONSTRUCTOR) || mRef.equals(GET_DECLARED_CONSTRUCTORS) || mRef.equals(GET_DECLARED_METHOD) - || mRef.equals(GET_DECLARED_METHODS); - } - - public Iterator iterateNewSites(CGNode node) { - if (node == null) { - throw new IllegalArgumentException("node is null"); - } - assert understands(node); - JavaTypeContext context = (JavaTypeContext) node.getContext(); - TypeReference tr = context.getType().getTypeReference(); - if (tr != null) { - return new NonNullSingletonIterator(NewSiteReference.make(0, tr)); - } - return EmptyIterator.instance(); - } - - public Iterator iterateCallSites(CGNode node) { - assert understands(node); - return EmptyIterator.instance(); - } - - /** - * Get all non-constructor, non-class-initializer methods declared by a class - */ - private Collection getDeclaredNormalMethods(IClass cls) { - Collection result = HashSetFactory.make(); - for (IMethod m : cls.getDeclaredMethods()) { - if (!m.isInit() && !m.isClinit()) { - result.add(m); - } - } - return result; - } - - /** - * Get all non-constructor, non-class-initializer methods declared by a class and all its superclasses - */ - private Collection getAllNormalPublicMethods(IClass cls) { - Collection result = HashSetFactory.make(); - Collection allMethods = null; - allMethods = cls.getAllMethods(); - for (IMethod m : allMethods) { - if (!m.isInit() && !m.isClinit() && m.isPublic()) { - result.add(m); - } - } - return result; - } - - /** - * Get all the constructors of a class - */ - private Collection getConstructors(IClass cls) { - Collection result = HashSetFactory.make(); - for (IMethod m : cls.getDeclaredMethods()) { - if (m.isInit()) { - result.add(m); - } - } - return result; - } - - /** - * Get all the public constructors of a class - */ - private Collection getPublicConstructors(IClass cls) { - Collection result = HashSetFactory.make(); - for (IMethod m : cls.getDeclaredMethods()) { - if (m.isInit() && m.isPublic()) { - result.add(m); - } - } - return result; - } - - /** - * create statements for methods like getConstructors() and getMethods(), which return an array of methods. - * - * @param returnValues the possible return values for this method. - */ - private SSAInstruction[] getMethodArrayStatements(MethodReference ref, Collection returnValues, JavaTypeContext context, - Map constants) { - ArrayList statements = new ArrayList(); - int nextLocal = ref.getNumberOfParameters() + 2; - int retValue = nextLocal++; - IClass cls = context.getType().getType(); - SSAInstructionFactory insts = context.getType().getType().getClassLoader().getInstructionFactory(); - if (cls != null) { - TypeReference arrType = ref.getReturnType(); - NewSiteReference site = new NewSiteReference(retValue, arrType); - int sizeVn = nextLocal++; - constants.put(sizeVn, new ConstantValue(returnValues.size())); - SSANewInstruction allocArr = insts.NewInstruction(retValue, site, new int[] { sizeVn }); - statements.add(allocArr); - - int i = 0; - for (IMethod m : returnValues) { - int c = nextLocal++; - constants.put(c, new ConstantValue(m)); - int index = i++; - int indexVn = nextLocal++; - constants.put(indexVn, new ConstantValue(index)); - SSAArrayStoreInstruction store = insts - .ArrayStoreInstruction(retValue, indexVn, c, TypeReference.JavaLangReflectConstructor); - statements.add(store); - } - SSAReturnInstruction R = insts.ReturnInstruction(retValue, false); - statements.add(R); - } else { - // SJF: This is incorrect. TODO: fix and enable. - // SSAThrowInstruction t = insts.ThrowInstruction(retValue); - // statements.add(t); - } - SSAInstruction[] result = new SSAInstruction[statements.size()]; - Iterator it = statements.iterator(); - for (int i = 0; i < result.length; i++) { - result[i] = it.next(); - } - return result; - } - - /** - * create statements for methods like getConstructor() and getDeclaredMethod(), which return a single method. This creates a - * return statement for each possible return value, each of which is a {@link ConstantValue} for an {@link IMethod}. - * - * @param returnValues the possible return values for this method. - */ - private SSAInstruction[] getParticularMethodStatements(MethodReference ref, Collection returnValues, - JavaTypeContext context, Map constants) { - ArrayList statements = new ArrayList(); - int nextLocal = ref.getNumberOfParameters() + 2; - IClass cls = context.getType().getType(); - SSAInstructionFactory insts = context.getType().getType().getClassLoader().getInstructionFactory(); - if (cls != null) { - for (IMethod m : returnValues) { - int c = nextLocal++; - constants.put(c, new ConstantValue(m)); - SSAReturnInstruction R = insts.ReturnInstruction(c, false); - statements.add(R); - } - } else { - // SJF: This is incorrect. TODO: fix and enable. - // SSAThrowInstruction t = insts.ThrowInstruction(retValue); - // statements.add(t); - } - SSAInstruction[] result = new SSAInstruction[statements.size()]; - Iterator it = statements.iterator(); - for (int i = 0; i < result.length; i++) { - result[i] = it.next(); - } - return result; - } - - /** - * create statements for getConstructor() - */ - private SSAInstruction[] makeGetCtorStatements(JavaTypeContext context, Map constants) { - IClass cls = context.getType().getType(); - if (cls == null) { - return getParticularMethodStatements(GET_CONSTRUCTOR, null, context, constants); - } else { - return getParticularMethodStatements(GET_CONSTRUCTOR, getPublicConstructors(cls), context, constants); - } - } - - // TODO - private SSAInstruction[] makeGetCtorsStatements(JavaTypeContext context, Map constants) { - IClass cls = context.getType().getType(); - if (cls == null) { - return getMethodArrayStatements(GET_DECLARED_CONSTRUCTORS, null, context, constants); - } else { - return getMethodArrayStatements(GET_DECLARED_CONSTRUCTORS, getPublicConstructors(cls), context, constants); - } - } - - private SSAInstruction[] makeGetMethodStatements(JavaTypeContext context, Map constants) { - IClass cls = context.getType().getType(); - if (cls == null) { - return getParticularMethodStatements(GET_METHOD, null, context, constants); - } else { - return getParticularMethodStatements(GET_METHOD, getAllNormalPublicMethods(cls), context, constants); - } - } - - private SSAInstruction[] makeGetMethodsStatments(JavaTypeContext context, Map constants) { - IClass cls = context.getType().getType(); - if (cls == null) { - return getMethodArrayStatements(GET_METHODS, null, context, constants); - } else { - return getMethodArrayStatements(GET_METHODS, getAllNormalPublicMethods(cls), context, constants); - } - } - - /** - * create statements for getConstructor() - */ - private SSAInstruction[] makeGetDeclCtorStatements(JavaTypeContext context, Map constants) { - IClass cls = context.getType().getType(); - if (cls == null) { - return getParticularMethodStatements(GET_DECLARED_CONSTRUCTOR, null, context, constants); - } else { - return getParticularMethodStatements(GET_DECLARED_CONSTRUCTOR, getConstructors(cls), context, constants); - } - } - - private SSAInstruction[] makeGetDeclCtorsStatements(JavaTypeContext context, Map constants) { - IClass cls = context.getType().getType(); - if (cls == null) { - return getMethodArrayStatements(GET_DECLARED_CONSTRUCTORS, null, context, constants); - } else { - return getMethodArrayStatements(GET_DECLARED_CONSTRUCTORS, getConstructors(cls), context, constants); - } - } - - /** - * create statements for getDeclaredMethod() - */ - private SSAInstruction[] makeGetDeclaredMethodStatements(JavaTypeContext context, Map constants) { - IClass cls = context.getType().getType(); - if (cls == null) { - return getParticularMethodStatements(GET_DECLARED_METHOD, null, context, constants); - } else { - return getParticularMethodStatements(GET_DECLARED_METHOD, getDeclaredNormalMethods(cls), context, constants); - } - } - - /** - * create statements for getDeclaredMethod() - */ - private SSAInstruction[] makeGetDeclaredMethodsStatements(JavaTypeContext context, Map constants) { - IClass cls = context.getType().getType(); - if (cls == null) { - return getMethodArrayStatements(GET_DECLARED_METHODS, null, context, constants); - } else { - return getMethodArrayStatements(GET_DECLARED_METHODS, getDeclaredNormalMethods(cls), context, constants); - } - } - - public boolean recordFactoryType(CGNode node, IClass klass) { - return false; - } - - public Iterator iterateFieldsRead(CGNode node) { - return EmptyIterator.instance(); - } - - public Iterator iterateFieldsWritten(CGNode node) { - return EmptyIterator.instance(); - } - - public ControlFlowGraph getCFG(CGNode N) { - return getIR(N).getControlFlowGraph(); - } - - public DefUse getDU(CGNode node) { - return new DefUse(getIR(node)); - } -} +/******************************************************************************* + * Copyright (c) 2008 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.Collection; +import java.util.Iterator; +import java.util.Map; + +import com.ibm.wala.cfg.ControlFlowGraph; +import com.ibm.wala.cfg.InducedCFG; +import com.ibm.wala.classLoader.CallSiteReference; +import com.ibm.wala.classLoader.IClass; +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.propagation.SSAContextInterpreter; +import com.ibm.wala.ipa.summaries.SyntheticIR; +import com.ibm.wala.ssa.ConstantValue; +import com.ibm.wala.ssa.DefUse; +import com.ibm.wala.ssa.IR; +import com.ibm.wala.ssa.ISSABasicBlock; +import com.ibm.wala.ssa.SSAArrayStoreInstruction; +import com.ibm.wala.ssa.SSAInstruction; +import com.ibm.wala.ssa.SSAInstructionFactory; +import com.ibm.wala.ssa.SSANewInstruction; +import com.ibm.wala.ssa.SSAOptions; +import com.ibm.wala.ssa.SSAReturnInstruction; +import com.ibm.wala.types.FieldReference; +import com.ibm.wala.types.MethodReference; +import com.ibm.wala.types.TypeReference; +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.NonNullSingletonIterator; +import com.ibm.wala.util.debug.Assertions; + +/** + * An {@link SSAContextInterpreter} specialized to interpret methods on java.lang.Class in a {@link JavaTypeContext} which + * represents the point-type of the class object created by the call. + * + * Currently supported methods: + *
          + *
        • getConstructor + *
        • getConstructors + *
        • getMethod + *
        • getMethods + *
        • getDeclaredConstructor + *
        • getDeclaredConstructors + *
        • getDeclaredMethod + *
        • getDeclaredMethods + *
        + */ +public class JavaLangClassContextInterpreter implements SSAContextInterpreter { + + public final static MethodReference GET_CONSTRUCTOR = MethodReference.findOrCreate(TypeReference.JavaLangClass, "getConstructor", + "([Ljava/lang/Class;)Ljava/lang/reflect/Constructor;"); + + public final static MethodReference GET_CONSTRUCTORS = MethodReference.findOrCreate(TypeReference.JavaLangClass, + "getConstructors", "()[Ljava/lang/reflect/Constructor;"); + + public final static MethodReference GET_METHOD = MethodReference.findOrCreate(TypeReference.JavaLangClass, "getMethod", + "(Ljava/lang/String;[Ljava/lang/Class;)Ljava/lang/reflect/Method;"); + + public final static MethodReference GET_METHODS = MethodReference.findOrCreate(TypeReference.JavaLangClass, "getMethods", + "()[Ljava/lang/reflect/Method;"); + + public final static MethodReference GET_DECLARED_CONSTRUCTOR = MethodReference.findOrCreate(TypeReference.JavaLangClass, + "getDeclaredConstructor", "([Ljava/lang/Class;)Ljava/lang/reflect/Constructor;"); + + public final static MethodReference GET_DECLARED_CONSTRUCTORS = MethodReference.findOrCreate(TypeReference.JavaLangClass, + "getDeclaredConstructors", "()[Ljava/lang/reflect/Constructor;"); + + public final static MethodReference GET_DECLARED_METHOD = MethodReference.findOrCreate(TypeReference.JavaLangClass, + "getDeclaredMethod", "(Ljava/lang/String;[Ljava/lang/Class;)Ljava/lang/reflect/Method;"); + + public final static MethodReference GET_DECLARED_METHODS = MethodReference.findOrCreate(TypeReference.JavaLangClass, + "getDeclaredMethods", "()[Ljava/lang/reflect/Method;"); + + private static final boolean DEBUG = false; + + /* + * @see com.ibm.wala.ipa.callgraph.propagation.SSAContextInterpreter#getIR(com.ibm.wala.ipa.callgraph.CGNode) + */ + public IR getIR(CGNode node) { + if (node == null) { + throw new IllegalArgumentException("node is null"); + } + assert understands(node); + if (DEBUG) { + System.err.println("generating IR for " + node); + } + IMethod method = node.getMethod(); + JavaTypeContext context = (JavaTypeContext) node.getContext(); + Map constants = HashMapFactory.make(); + if (method.getReference().equals(GET_CONSTRUCTOR)) { + SSAInstruction instrs[] = makeGetCtorStatements(context, constants); + return new SyntheticIR(method, context, new InducedCFG(instrs, method, context), instrs, SSAOptions.defaultOptions(), + constants); + } + if (method.getReference().equals(GET_CONSTRUCTORS)) { + SSAInstruction instrs[] = makeGetCtorsStatements(context, constants); + return new SyntheticIR(method, context, new InducedCFG(instrs, method, context), instrs, SSAOptions.defaultOptions(), + constants); + } + if (method.getReference().equals(GET_METHOD)) { + SSAInstruction instrs[] = makeGetMethodStatements(context, constants); + return new SyntheticIR(method, context, new InducedCFG(instrs, method, context), instrs, SSAOptions.defaultOptions(), + constants); + } + if (method.getReference().equals(GET_METHODS)) { + SSAInstruction instrs[] = makeGetMethodsStatments(context, constants); + return new SyntheticIR(method, context, new InducedCFG(instrs, method, context), instrs, SSAOptions.defaultOptions(), + constants); + } + if (method.getReference().equals(GET_DECLARED_CONSTRUCTOR)) { + SSAInstruction instrs[] = makeGetDeclCtorStatements(context, constants); + return new SyntheticIR(method, context, new InducedCFG(instrs, method, context), instrs, SSAOptions.defaultOptions(), + constants); + } + if (method.getReference().equals(GET_DECLARED_CONSTRUCTORS)) { + SSAInstruction instrs[] = makeGetDeclCtorsStatements(context, constants); + return new SyntheticIR(method, context, new InducedCFG(instrs, method, context), instrs, SSAOptions.defaultOptions(), + constants); + } + if (method.getReference().equals(GET_DECLARED_METHOD)) { + SSAInstruction instrs[] = makeGetDeclaredMethodStatements(context, constants); + return new SyntheticIR(method, context, new InducedCFG(instrs, method, context), instrs, SSAOptions.defaultOptions(), + constants); + } + if (method.getReference().equals(GET_DECLARED_METHODS)) { + SSAInstruction instrs[] = makeGetDeclaredMethodsStatements(context, constants); + return new SyntheticIR(method, context, new InducedCFG(instrs, method, context), instrs, SSAOptions.defaultOptions(), + constants); + } + Assertions.UNREACHABLE("Unexpected method " + node); + return null; + } + + /* + * @see com.ibm.wala.ipa.callgraph.propagation.SSAContextInterpreter#getNumberOfStatements(com.ibm.wala.ipa.callgraph.CGNode) + */ + public int getNumberOfStatements(CGNode node) { + assert understands(node); + return getIR(node).getInstructions().length; + } + + /* + * @see com.ibm.wala.ipa.callgraph.propagation.rta.RTAContextInterpreter#understands(com.ibm.wala.ipa.callgraph.CGNode) + */ + public boolean understands(CGNode node) { + if (node == null) { + throw new IllegalArgumentException("node is null"); + } + if (!(node.getContext() instanceof JavaTypeContext)) { + return false; + } + MethodReference mRef = node.getMethod().getReference(); + return mRef.equals(GET_CONSTRUCTOR) || mRef.equals(GET_CONSTRUCTORS) || mRef.equals(GET_METHOD) || mRef.equals(GET_METHODS) + || mRef.equals(GET_DECLARED_CONSTRUCTOR) || mRef.equals(GET_DECLARED_CONSTRUCTORS) || mRef.equals(GET_DECLARED_METHOD) + || mRef.equals(GET_DECLARED_METHODS); + } + + public Iterator iterateNewSites(CGNode node) { + if (node == null) { + throw new IllegalArgumentException("node is null"); + } + assert understands(node); + JavaTypeContext context = (JavaTypeContext) node.getContext(); + TypeReference tr = context.getType().getTypeReference(); + if (tr != null) { + return new NonNullSingletonIterator(NewSiteReference.make(0, tr)); + } + return EmptyIterator.instance(); + } + + public Iterator iterateCallSites(CGNode node) { + assert understands(node); + return EmptyIterator.instance(); + } + + /** + * Get all non-constructor, non-class-initializer methods declared by a class + */ + private Collection getDeclaredNormalMethods(IClass cls) { + Collection result = HashSetFactory.make(); + for (IMethod m : cls.getDeclaredMethods()) { + if (!m.isInit() && !m.isClinit()) { + result.add(m); + } + } + return result; + } + + /** + * Get all non-constructor, non-class-initializer methods declared by a class and all its superclasses + */ + private Collection getAllNormalPublicMethods(IClass cls) { + Collection result = HashSetFactory.make(); + Collection allMethods = null; + allMethods = cls.getAllMethods(); + for (IMethod m : allMethods) { + if (!m.isInit() && !m.isClinit() && m.isPublic()) { + result.add(m); + } + } + return result; + } + + /** + * Get all the constructors of a class + */ + private Collection getConstructors(IClass cls) { + Collection result = HashSetFactory.make(); + for (IMethod m : cls.getDeclaredMethods()) { + if (m.isInit()) { + result.add(m); + } + } + return result; + } + + /** + * Get all the public constructors of a class + */ + private Collection getPublicConstructors(IClass cls) { + Collection result = HashSetFactory.make(); + for (IMethod m : cls.getDeclaredMethods()) { + if (m.isInit() && m.isPublic()) { + result.add(m); + } + } + return result; + } + + /** + * create statements for methods like getConstructors() and getMethods(), which return an array of methods. + * + * @param returnValues the possible return values for this method. + */ + private SSAInstruction[] getMethodArrayStatements(MethodReference ref, Collection returnValues, JavaTypeContext context, + Map constants) { + ArrayList statements = new ArrayList(); + int nextLocal = ref.getNumberOfParameters() + 2; + int retValue = nextLocal++; + IClass cls = context.getType().getType(); + SSAInstructionFactory insts = context.getType().getType().getClassLoader().getInstructionFactory(); + if (cls != null) { + TypeReference arrType = ref.getReturnType(); + NewSiteReference site = new NewSiteReference(retValue, arrType); + int sizeVn = nextLocal++; + constants.put(sizeVn, new ConstantValue(returnValues.size())); + SSANewInstruction allocArr = insts.NewInstruction(retValue, site, new int[] { sizeVn }); + statements.add(allocArr); + + int i = 0; + for (IMethod m : returnValues) { + int c = nextLocal++; + constants.put(c, new ConstantValue(m)); + int index = i++; + int indexVn = nextLocal++; + constants.put(indexVn, new ConstantValue(index)); + SSAArrayStoreInstruction store = insts + .ArrayStoreInstruction(retValue, indexVn, c, TypeReference.JavaLangReflectConstructor); + statements.add(store); + } + SSAReturnInstruction R = insts.ReturnInstruction(retValue, false); + statements.add(R); + } else { + // SJF: This is incorrect. TODO: fix and enable. + // SSAThrowInstruction t = insts.ThrowInstruction(retValue); + // statements.add(t); + } + SSAInstruction[] result = new SSAInstruction[statements.size()]; + Iterator it = statements.iterator(); + for (int i = 0; i < result.length; i++) { + result[i] = it.next(); + } + return result; + } + + /** + * create statements for methods like getConstructor() and getDeclaredMethod(), which return a single method. This creates a + * return statement for each possible return value, each of which is a {@link ConstantValue} for an {@link IMethod}. + * + * @param returnValues the possible return values for this method. + */ + private SSAInstruction[] getParticularMethodStatements(MethodReference ref, Collection returnValues, + JavaTypeContext context, Map constants) { + ArrayList statements = new ArrayList(); + int nextLocal = ref.getNumberOfParameters() + 2; + IClass cls = context.getType().getType(); + SSAInstructionFactory insts = context.getType().getType().getClassLoader().getInstructionFactory(); + if (cls != null) { + for (IMethod m : returnValues) { + int c = nextLocal++; + constants.put(c, new ConstantValue(m)); + SSAReturnInstruction R = insts.ReturnInstruction(c, false); + statements.add(R); + } + } else { + // SJF: This is incorrect. TODO: fix and enable. + // SSAThrowInstruction t = insts.ThrowInstruction(retValue); + // statements.add(t); + } + SSAInstruction[] result = new SSAInstruction[statements.size()]; + Iterator it = statements.iterator(); + for (int i = 0; i < result.length; i++) { + result[i] = it.next(); + } + return result; + } + + /** + * create statements for getConstructor() + */ + private SSAInstruction[] makeGetCtorStatements(JavaTypeContext context, Map constants) { + IClass cls = context.getType().getType(); + if (cls == null) { + return getParticularMethodStatements(GET_CONSTRUCTOR, null, context, constants); + } else { + return getParticularMethodStatements(GET_CONSTRUCTOR, getPublicConstructors(cls), context, constants); + } + } + + // TODO + private SSAInstruction[] makeGetCtorsStatements(JavaTypeContext context, Map constants) { + IClass cls = context.getType().getType(); + if (cls == null) { + return getMethodArrayStatements(GET_DECLARED_CONSTRUCTORS, null, context, constants); + } else { + return getMethodArrayStatements(GET_DECLARED_CONSTRUCTORS, getPublicConstructors(cls), context, constants); + } + } + + private SSAInstruction[] makeGetMethodStatements(JavaTypeContext context, Map constants) { + IClass cls = context.getType().getType(); + if (cls == null) { + return getParticularMethodStatements(GET_METHOD, null, context, constants); + } else { + return getParticularMethodStatements(GET_METHOD, getAllNormalPublicMethods(cls), context, constants); + } + } + + private SSAInstruction[] makeGetMethodsStatments(JavaTypeContext context, Map constants) { + IClass cls = context.getType().getType(); + if (cls == null) { + return getMethodArrayStatements(GET_METHODS, null, context, constants); + } else { + return getMethodArrayStatements(GET_METHODS, getAllNormalPublicMethods(cls), context, constants); + } + } + + /** + * create statements for getConstructor() + */ + private SSAInstruction[] makeGetDeclCtorStatements(JavaTypeContext context, Map constants) { + IClass cls = context.getType().getType(); + if (cls == null) { + return getParticularMethodStatements(GET_DECLARED_CONSTRUCTOR, null, context, constants); + } else { + return getParticularMethodStatements(GET_DECLARED_CONSTRUCTOR, getConstructors(cls), context, constants); + } + } + + private SSAInstruction[] makeGetDeclCtorsStatements(JavaTypeContext context, Map constants) { + IClass cls = context.getType().getType(); + if (cls == null) { + return getMethodArrayStatements(GET_DECLARED_CONSTRUCTORS, null, context, constants); + } else { + return getMethodArrayStatements(GET_DECLARED_CONSTRUCTORS, getConstructors(cls), context, constants); + } + } + + /** + * create statements for getDeclaredMethod() + */ + private SSAInstruction[] makeGetDeclaredMethodStatements(JavaTypeContext context, Map constants) { + IClass cls = context.getType().getType(); + if (cls == null) { + return getParticularMethodStatements(GET_DECLARED_METHOD, null, context, constants); + } else { + return getParticularMethodStatements(GET_DECLARED_METHOD, getDeclaredNormalMethods(cls), context, constants); + } + } + + /** + * create statements for getDeclaredMethod() + */ + private SSAInstruction[] makeGetDeclaredMethodsStatements(JavaTypeContext context, Map constants) { + IClass cls = context.getType().getType(); + if (cls == null) { + return getMethodArrayStatements(GET_DECLARED_METHODS, null, context, constants); + } else { + return getMethodArrayStatements(GET_DECLARED_METHODS, getDeclaredNormalMethods(cls), context, constants); + } + } + + public boolean recordFactoryType(CGNode node, IClass klass) { + return false; + } + + public Iterator iterateFieldsRead(CGNode node) { + return EmptyIterator.instance(); + } + + public Iterator iterateFieldsWritten(CGNode node) { + return EmptyIterator.instance(); + } + + public ControlFlowGraph getCFG(CGNode N) { + return getIR(N).getControlFlowGraph(); + } + + public DefUse getDU(CGNode node) { + return new DefUse(getIR(node)); + } +} diff --git a/com.ibm.wala.core/src/com/ibm/wala/analysis/reflection/JavaLangClassContextSelector.java b/com.ibm.wala.core/src/com/ibm/wala/analysis/reflection/JavaLangClassContextSelector.java index 800e8b6b8..e81d61a80 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/analysis/reflection/JavaLangClassContextSelector.java +++ b/com.ibm.wala.core/src/com/ibm/wala/analysis/reflection/JavaLangClassContextSelector.java @@ -1,97 +1,97 @@ -/******************************************************************************* - * Copyright (c) 2008 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.Collection; - -import com.ibm.wala.analysis.typeInference.PointType; -import com.ibm.wala.classLoader.CallSiteReference; -import com.ibm.wala.classLoader.IClass; -import com.ibm.wala.classLoader.IMethod; -import com.ibm.wala.ipa.callgraph.CGNode; -import com.ibm.wala.ipa.callgraph.Context; -import com.ibm.wala.ipa.callgraph.ContextSelector; -import com.ibm.wala.ipa.callgraph.propagation.ConstantKey; -import com.ibm.wala.ipa.callgraph.propagation.InstanceKey; -import com.ibm.wala.ipa.cha.IClassHierarchy; -import com.ibm.wala.types.MethodReference; -import com.ibm.wala.util.collections.HashSetFactory; -import com.ibm.wala.util.intset.EmptyIntSet; -import com.ibm.wala.util.intset.IntSet; -import com.ibm.wala.util.intset.IntSetUtil; - -/** - * A {@link ContextSelector} to intercept calls to certain methods on java.lang.Class when the receiver is a type constant - * - * Currently supported methods: - *
          - *
        • getConstructor - *
        • getConstructors - *
        • getDeclaredMethod - *
        • getMethods - *
        - */ -class JavaLangClassContextSelector implements ContextSelector { - - public JavaLangClassContextSelector() { - } - - /** - * If the {@link CallSiteReference} invokes a method we understand and c is a type constant, return a {@link JavaTypeContext} - * representing the type named by s, if we can resolve it in the {@link IClassHierarchy}. - */ - public Context getCalleeTarget(CGNode caller, CallSiteReference site, IMethod callee, InstanceKey[] receiver) { - if (receiver != null && receiver.length > 0 && mayUnderstand(caller, site, callee, receiver[0])) { - return new JavaTypeContext(new PointType(getTypeConstant(receiver[0]))); - } - return null; - } - - private IClass getTypeConstant(InstanceKey instance) { - if (instance instanceof ConstantKey) { - ConstantKey c = (ConstantKey) instance; - if (c.getValue() instanceof IClass) { - return (IClass) c.getValue(); - } - } - return null; - } - - private static final Collection UNDERSTOOD_METHOD_REFS = HashSetFactory.make(); - - static { - UNDERSTOOD_METHOD_REFS.add(JavaLangClassContextInterpreter.GET_CONSTRUCTOR); - UNDERSTOOD_METHOD_REFS.add(JavaLangClassContextInterpreter.GET_CONSTRUCTORS); - UNDERSTOOD_METHOD_REFS.add(JavaLangClassContextInterpreter.GET_METHOD); - UNDERSTOOD_METHOD_REFS.add(JavaLangClassContextInterpreter.GET_METHODS); - UNDERSTOOD_METHOD_REFS.add(JavaLangClassContextInterpreter.GET_DECLARED_CONSTRUCTOR); - UNDERSTOOD_METHOD_REFS.add(JavaLangClassContextInterpreter.GET_DECLARED_CONSTRUCTORS); - UNDERSTOOD_METHOD_REFS.add(JavaLangClassContextInterpreter.GET_DECLARED_METHOD); - UNDERSTOOD_METHOD_REFS.add(JavaLangClassContextInterpreter.GET_DECLARED_METHODS); - } - - /** - * This object may understand a dispatch to Class.getContructor when the receiver is a type constant. - */ - private boolean mayUnderstand(CGNode caller, CallSiteReference site, IMethod targetMethod, InstanceKey instance) { - return UNDERSTOOD_METHOD_REFS.contains(targetMethod.getReference()) && getTypeConstant(instance) != null; - } - - private static final IntSet thisParameter = IntSetUtil.make(new int[]{0}); - - public IntSet getRelevantParameters(CGNode caller, CallSiteReference site) { - if (site.isDispatch() || site.getDeclaredTarget().getNumberOfParameters() > 0) { - return thisParameter; - } else { - return EmptyIntSet.instance; - } - } +/******************************************************************************* + * Copyright (c) 2008 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.Collection; + +import com.ibm.wala.analysis.typeInference.PointType; +import com.ibm.wala.classLoader.CallSiteReference; +import com.ibm.wala.classLoader.IClass; +import com.ibm.wala.classLoader.IMethod; +import com.ibm.wala.ipa.callgraph.CGNode; +import com.ibm.wala.ipa.callgraph.Context; +import com.ibm.wala.ipa.callgraph.ContextSelector; +import com.ibm.wala.ipa.callgraph.propagation.ConstantKey; +import com.ibm.wala.ipa.callgraph.propagation.InstanceKey; +import com.ibm.wala.ipa.cha.IClassHierarchy; +import com.ibm.wala.types.MethodReference; +import com.ibm.wala.util.collections.HashSetFactory; +import com.ibm.wala.util.intset.EmptyIntSet; +import com.ibm.wala.util.intset.IntSet; +import com.ibm.wala.util.intset.IntSetUtil; + +/** + * A {@link ContextSelector} to intercept calls to certain methods on java.lang.Class when the receiver is a type constant + * + * Currently supported methods: + *
          + *
        • getConstructor + *
        • getConstructors + *
        • getDeclaredMethod + *
        • getMethods + *
        + */ +class JavaLangClassContextSelector implements ContextSelector { + + public JavaLangClassContextSelector() { + } + + /** + * If the {@link CallSiteReference} invokes a method we understand and c is a type constant, return a {@link JavaTypeContext} + * representing the type named by s, if we can resolve it in the {@link IClassHierarchy}. + */ + public Context getCalleeTarget(CGNode caller, CallSiteReference site, IMethod callee, InstanceKey[] receiver) { + if (receiver != null && receiver.length > 0 && mayUnderstand(caller, site, callee, receiver[0])) { + return new JavaTypeContext(new PointType(getTypeConstant(receiver[0]))); + } + return null; + } + + private IClass getTypeConstant(InstanceKey instance) { + if (instance instanceof ConstantKey) { + ConstantKey c = (ConstantKey) instance; + if (c.getValue() instanceof IClass) { + return (IClass) c.getValue(); + } + } + return null; + } + + private static final Collection UNDERSTOOD_METHOD_REFS = HashSetFactory.make(); + + static { + UNDERSTOOD_METHOD_REFS.add(JavaLangClassContextInterpreter.GET_CONSTRUCTOR); + UNDERSTOOD_METHOD_REFS.add(JavaLangClassContextInterpreter.GET_CONSTRUCTORS); + UNDERSTOOD_METHOD_REFS.add(JavaLangClassContextInterpreter.GET_METHOD); + UNDERSTOOD_METHOD_REFS.add(JavaLangClassContextInterpreter.GET_METHODS); + UNDERSTOOD_METHOD_REFS.add(JavaLangClassContextInterpreter.GET_DECLARED_CONSTRUCTOR); + UNDERSTOOD_METHOD_REFS.add(JavaLangClassContextInterpreter.GET_DECLARED_CONSTRUCTORS); + UNDERSTOOD_METHOD_REFS.add(JavaLangClassContextInterpreter.GET_DECLARED_METHOD); + UNDERSTOOD_METHOD_REFS.add(JavaLangClassContextInterpreter.GET_DECLARED_METHODS); + } + + /** + * This object may understand a dispatch to Class.getContructor when the receiver is a type constant. + */ + private boolean mayUnderstand(CGNode caller, CallSiteReference site, IMethod targetMethod, InstanceKey instance) { + return UNDERSTOOD_METHOD_REFS.contains(targetMethod.getReference()) && getTypeConstant(instance) != null; + } + + private static final IntSet thisParameter = IntSetUtil.make(new int[]{0}); + + public IntSet getRelevantParameters(CGNode caller, CallSiteReference site) { + if (site.isDispatch() || site.getDeclaredTarget().getNumberOfParameters() > 0) { + return thisParameter; + } else { + return EmptyIntSet.instance; + } + } } \ No newline at end of file diff --git a/com.ibm.wala.core/src/com/ibm/wala/analysis/reflection/JavaTypeContext.java b/com.ibm.wala.core/src/com/ibm/wala/analysis/reflection/JavaTypeContext.java index 4d4836c3a..93cae38b1 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/analysis/reflection/JavaTypeContext.java +++ b/com.ibm.wala.core/src/com/ibm/wala/analysis/reflection/JavaTypeContext.java @@ -1,77 +1,77 @@ -/******************************************************************************* - * Copyright (c) 2002 - 2006 IBM Corporation. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * IBM Corporation - initial API and implementation - *******************************************************************************/ -package com.ibm.wala.analysis.reflection; - -import com.ibm.wala.analysis.typeInference.PointType; -import com.ibm.wala.analysis.typeInference.TypeAbstraction; -import com.ibm.wala.classLoader.IClass; -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.ipa.callgraph.propagation.FilteredPointerKey; - -/** - * Implement a Context which corresponds to a given type abstraction. Thus, this maps the name "TYPE" to a JavaTypeAbstraction. - */ -public class JavaTypeContext implements Context { - - private final TypeAbstraction type; - - public JavaTypeContext(TypeAbstraction type) { - if (type == null) { - throw new IllegalArgumentException("null type"); - } - this.type = type; - } - - public ContextItem get(ContextKey name) { - if (name == ContextKey.RECEIVER) { - return type; - } else if (name == ContextKey.PARAMETERS[0]) { - if (type instanceof PointType) { - IClass cls = ((PointType) type).getIClass(); - return new FilteredPointerKey.SingleClassFilter(cls); - } else { - return null; - } - } else { - return null; - } - } - - @Override - public String toString() { - return "JavaTypeContext<" + type + ">"; - } - - @Override - public int hashCode() { - return 6367 * type.hashCode(); - } - - @Override - public boolean equals(Object obj) { - if (obj == null) { - return false; - } - if (getClass().equals(obj.getClass())) { - JavaTypeContext other = (JavaTypeContext) obj; - return type.equals(other.type); - } else { - return false; - } - } - - public TypeAbstraction getType() { - return type; - } - -} +/******************************************************************************* + * 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.PointType; +import com.ibm.wala.analysis.typeInference.TypeAbstraction; +import com.ibm.wala.classLoader.IClass; +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.ipa.callgraph.propagation.FilteredPointerKey; + +/** + * Implement a Context which corresponds to a given type abstraction. Thus, this maps the name "TYPE" to a JavaTypeAbstraction. + */ +public class JavaTypeContext implements Context { + + private final TypeAbstraction type; + + public JavaTypeContext(TypeAbstraction type) { + if (type == null) { + throw new IllegalArgumentException("null type"); + } + this.type = type; + } + + public ContextItem get(ContextKey name) { + if (name == ContextKey.RECEIVER) { + return type; + } else if (name == ContextKey.PARAMETERS[0]) { + if (type instanceof PointType) { + IClass cls = ((PointType) type).getIClass(); + return new FilteredPointerKey.SingleClassFilter(cls); + } else { + return null; + } + } else { + return null; + } + } + + @Override + public String toString() { + return "JavaTypeContext<" + type + ">"; + } + + @Override + public int hashCode() { + return 6367 * type.hashCode(); + } + + @Override + public boolean equals(Object obj) { + if (obj == null) { + return false; + } + if (getClass().equals(obj.getClass())) { + JavaTypeContext other = (JavaTypeContext) obj; + return type.equals(other.type); + } else { + return false; + } + } + + public TypeAbstraction getType() { + return type; + } + +} diff --git a/com.ibm.wala.core/src/com/ibm/wala/analysis/reflection/ReflectionContextInterpreter.java b/com.ibm.wala.core/src/com/ibm/wala/analysis/reflection/ReflectionContextInterpreter.java index 6eb4c71d7..86b972a07 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/analysis/reflection/ReflectionContextInterpreter.java +++ b/com.ibm.wala.core/src/com/ibm/wala/analysis/reflection/ReflectionContextInterpreter.java @@ -1,111 +1,111 @@ -/******************************************************************************* - * Copyright (c) 2008 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.Iterator; - -import com.ibm.wala.cfg.ControlFlowGraph; -import com.ibm.wala.classLoader.CallSiteReference; -import com.ibm.wala.classLoader.IClass; -import com.ibm.wala.classLoader.NewSiteReference; -import com.ibm.wala.ipa.callgraph.AnalysisCache; -import com.ibm.wala.ipa.callgraph.AnalysisOptions; -import com.ibm.wala.ipa.callgraph.CGNode; -import com.ibm.wala.ipa.callgraph.propagation.SSAContextInterpreter; -import com.ibm.wala.ipa.callgraph.propagation.cfa.DelegatingSSAContextInterpreter; -import com.ibm.wala.ipa.cha.IClassHierarchy; -import com.ibm.wala.ssa.DefUse; -import com.ibm.wala.ssa.IR; -import com.ibm.wala.ssa.ISSABasicBlock; -import com.ibm.wala.ssa.SSAInstruction; -import com.ibm.wala.types.FieldReference; - -/** - * {@link SSAContextInterpreter} to handle all reflection procession. - */ -public class ReflectionContextInterpreter { - - public static SSAContextInterpreter createReflectionContextInterpreter(IClassHierarchy cha, AnalysisOptions options, - AnalysisCache cache) { - - if (options == null) { - throw new IllegalArgumentException("null options"); - } - - // start with a dummy interpreter that understands nothing - SSAContextInterpreter result = new SSAContextInterpreter() { - public boolean understands(CGNode node) { - return false; - } - - public boolean recordFactoryType(CGNode node, IClass klass) { - // TODO Auto-generated method stub - return false; - } - - public Iterator iterateNewSites(CGNode node) { - // TODO Auto-generated method stub - return null; - } - - public Iterator iterateFieldsWritten(CGNode node) { - // TODO Auto-generated method stub - return null; - } - - public Iterator iterateFieldsRead(CGNode node) { - // TODO Auto-generated method stub - return null; - } - - public Iterator iterateCallSites(CGNode node) { - // TODO Auto-generated method stub - return null; - } - - public int getNumberOfStatements(CGNode node) { - // TODO Auto-generated method stub - return 0; - } - - public IR getIR(CGNode node) { - // TODO Auto-generated method stub - return null; - } - - public DefUse getDU(CGNode node) { - // TODO Auto-generated method stub - return null; - } - - public ControlFlowGraph getCFG(CGNode n) { - // TODO Auto-generated method stub - return null; - } - }; - - if (options.getReflectionOptions().getNumFlowToCastIterations() > 0) { - // need the factory bypass interpreter - result = new DelegatingSSAContextInterpreter(new FactoryBypassInterpreter(options, cache), result); - } - if (!options.getReflectionOptions().isIgnoreStringConstants()) { - result = new DelegatingSSAContextInterpreter(new GetClassContextInterpeter(), new DelegatingSSAContextInterpreter( - new DelegatingSSAContextInterpreter(new ClassFactoryContextInterpreter(), new ClassNewInstanceContextInterpreter(cha)), - result)); - } - if (!options.getReflectionOptions().isIgnoreMethodInvoke()) { - result = new DelegatingSSAContextInterpreter(new ReflectiveInvocationInterpreter(), new DelegatingSSAContextInterpreter( - new JavaLangClassContextInterpreter(), result)); - } - return result; - } - -} +/******************************************************************************* + * Copyright (c) 2008 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.Iterator; + +import com.ibm.wala.cfg.ControlFlowGraph; +import com.ibm.wala.classLoader.CallSiteReference; +import com.ibm.wala.classLoader.IClass; +import com.ibm.wala.classLoader.NewSiteReference; +import com.ibm.wala.ipa.callgraph.AnalysisCache; +import com.ibm.wala.ipa.callgraph.AnalysisOptions; +import com.ibm.wala.ipa.callgraph.CGNode; +import com.ibm.wala.ipa.callgraph.propagation.SSAContextInterpreter; +import com.ibm.wala.ipa.callgraph.propagation.cfa.DelegatingSSAContextInterpreter; +import com.ibm.wala.ipa.cha.IClassHierarchy; +import com.ibm.wala.ssa.DefUse; +import com.ibm.wala.ssa.IR; +import com.ibm.wala.ssa.ISSABasicBlock; +import com.ibm.wala.ssa.SSAInstruction; +import com.ibm.wala.types.FieldReference; + +/** + * {@link SSAContextInterpreter} to handle all reflection procession. + */ +public class ReflectionContextInterpreter { + + public static SSAContextInterpreter createReflectionContextInterpreter(IClassHierarchy cha, AnalysisOptions options, + AnalysisCache cache) { + + if (options == null) { + throw new IllegalArgumentException("null options"); + } + + // start with a dummy interpreter that understands nothing + SSAContextInterpreter result = new SSAContextInterpreter() { + public boolean understands(CGNode node) { + return false; + } + + public boolean recordFactoryType(CGNode node, IClass klass) { + // TODO Auto-generated method stub + return false; + } + + public Iterator iterateNewSites(CGNode node) { + // TODO Auto-generated method stub + return null; + } + + public Iterator iterateFieldsWritten(CGNode node) { + // TODO Auto-generated method stub + return null; + } + + public Iterator iterateFieldsRead(CGNode node) { + // TODO Auto-generated method stub + return null; + } + + public Iterator iterateCallSites(CGNode node) { + // TODO Auto-generated method stub + return null; + } + + public int getNumberOfStatements(CGNode node) { + // TODO Auto-generated method stub + return 0; + } + + public IR getIR(CGNode node) { + // TODO Auto-generated method stub + return null; + } + + public DefUse getDU(CGNode node) { + // TODO Auto-generated method stub + return null; + } + + public ControlFlowGraph getCFG(CGNode n) { + // TODO Auto-generated method stub + return null; + } + }; + + if (options.getReflectionOptions().getNumFlowToCastIterations() > 0) { + // need the factory bypass interpreter + result = new DelegatingSSAContextInterpreter(new FactoryBypassInterpreter(options, cache), result); + } + if (!options.getReflectionOptions().isIgnoreStringConstants()) { + result = new DelegatingSSAContextInterpreter(new GetClassContextInterpeter(), new DelegatingSSAContextInterpreter( + new DelegatingSSAContextInterpreter(new ClassFactoryContextInterpreter(), new ClassNewInstanceContextInterpreter(cha)), + result)); + } + if (!options.getReflectionOptions().isIgnoreMethodInvoke()) { + result = new DelegatingSSAContextInterpreter(new ReflectiveInvocationInterpreter(), new DelegatingSSAContextInterpreter( + new JavaLangClassContextInterpreter(), result)); + } + return result; + } + +} diff --git a/com.ibm.wala.core/src/com/ibm/wala/analysis/reflection/ReflectionContextSelector.java b/com.ibm.wala.core/src/com/ibm/wala/analysis/reflection/ReflectionContextSelector.java index aedb0b219..c9f856e80 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/analysis/reflection/ReflectionContextSelector.java +++ b/com.ibm.wala.core/src/com/ibm/wala/analysis/reflection/ReflectionContextSelector.java @@ -1,57 +1,57 @@ -/******************************************************************************* - * Copyright (c) 2008 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.IMethod; -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.ContextSelector; -import com.ibm.wala.ipa.callgraph.impl.DelegatingContextSelector; -import com.ibm.wala.ipa.callgraph.propagation.InstanceKey; -import com.ibm.wala.util.intset.EmptyIntSet; -import com.ibm.wala.util.intset.IntSet; - -/** - * A {@link ContextSelector} to handle default reflection logic. - */ -public class ReflectionContextSelector { - - public static ContextSelector createReflectionContextSelector(AnalysisOptions options) { - - if (options == null) { - throw new IllegalArgumentException("null options"); - } - - // start with a dummy - ContextSelector result = new ContextSelector() { - public Context getCalleeTarget(CGNode caller, CallSiteReference site, IMethod callee, InstanceKey[] receiver) { - return null; - } - public IntSet getRelevantParameters(CGNode caller, CallSiteReference site) { - return EmptyIntSet.instance; - } - }; - if (options.getReflectionOptions().getNumFlowToCastIterations() > 0) { - result = new DelegatingContextSelector(new FactoryContextSelector(), result); - } - if (!options.getReflectionOptions().isIgnoreStringConstants()) { - result = new DelegatingContextSelector(new DelegatingContextSelector(new DelegatingContextSelector( - new ClassFactoryContextSelector(), new GetClassContextSelector()), new ClassNewInstanceContextSelector()), result); - } - if (!options.getReflectionOptions().isIgnoreMethodInvoke()) { - result = new DelegatingContextSelector(new ReflectiveInvocationSelector(), new DelegatingContextSelector( - new JavaLangClassContextSelector(), result)); - } - return result; - } -} +/******************************************************************************* + * Copyright (c) 2008 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.IMethod; +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.ContextSelector; +import com.ibm.wala.ipa.callgraph.impl.DelegatingContextSelector; +import com.ibm.wala.ipa.callgraph.propagation.InstanceKey; +import com.ibm.wala.util.intset.EmptyIntSet; +import com.ibm.wala.util.intset.IntSet; + +/** + * A {@link ContextSelector} to handle default reflection logic. + */ +public class ReflectionContextSelector { + + public static ContextSelector createReflectionContextSelector(AnalysisOptions options) { + + if (options == null) { + throw new IllegalArgumentException("null options"); + } + + // start with a dummy + ContextSelector result = new ContextSelector() { + public Context getCalleeTarget(CGNode caller, CallSiteReference site, IMethod callee, InstanceKey[] receiver) { + return null; + } + public IntSet getRelevantParameters(CGNode caller, CallSiteReference site) { + return EmptyIntSet.instance; + } + }; + if (options.getReflectionOptions().getNumFlowToCastIterations() > 0) { + result = new DelegatingContextSelector(new FactoryContextSelector(), result); + } + if (!options.getReflectionOptions().isIgnoreStringConstants()) { + result = new DelegatingContextSelector(new DelegatingContextSelector(new DelegatingContextSelector( + new ClassFactoryContextSelector(), new GetClassContextSelector()), new ClassNewInstanceContextSelector()), result); + } + if (!options.getReflectionOptions().isIgnoreMethodInvoke()) { + result = new DelegatingContextSelector(new ReflectiveInvocationSelector(), new DelegatingContextSelector( + new JavaLangClassContextSelector(), result)); + } + return result; + } +} diff --git a/com.ibm.wala.core/src/com/ibm/wala/analysis/reflection/ReflectiveInvocationInterpreter.java b/com.ibm.wala.core/src/com/ibm/wala/analysis/reflection/ReflectiveInvocationInterpreter.java index dc33bc9f0..0568d7bfc 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/analysis/reflection/ReflectiveInvocationInterpreter.java +++ b/com.ibm.wala.core/src/com/ibm/wala/analysis/reflection/ReflectiveInvocationInterpreter.java @@ -1,224 +1,224 @@ -/******************************************************************************* - * Copyright (c) 2008 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.Iterator; -import java.util.Map; - -import com.ibm.wala.cfg.ControlFlowGraph; -import com.ibm.wala.cfg.InducedCFG; -import com.ibm.wala.classLoader.CallSiteReference; -import com.ibm.wala.classLoader.IClass; -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.propagation.ConstantKey; -import com.ibm.wala.ipa.callgraph.propagation.ReceiverInstanceContext; -import com.ibm.wala.ipa.callgraph.propagation.SSAContextInterpreter; -import com.ibm.wala.ipa.summaries.SyntheticIR; -import com.ibm.wala.shrikeBT.IInvokeInstruction; -import com.ibm.wala.shrikeBT.IInvokeInstruction.Dispatch; -import com.ibm.wala.ssa.ConstantValue; -import com.ibm.wala.ssa.DefUse; -import com.ibm.wala.ssa.IR; -import com.ibm.wala.ssa.ISSABasicBlock; -import com.ibm.wala.ssa.SSACheckCastInstruction; -import com.ibm.wala.ssa.SSAInstruction; -import com.ibm.wala.ssa.SSAInstructionFactory; -import com.ibm.wala.ssa.SSAOptions; -import com.ibm.wala.types.FieldReference; -import com.ibm.wala.types.MethodReference; -import com.ibm.wala.types.TypeReference; -import com.ibm.wala.util.collections.EmptyIterator; -import com.ibm.wala.util.collections.HashMapFactory; - -/** - * An {@link SSAContextInterpreter} specialized to interpret reflective invocations such as Constructor.newInstance and - * Method.invoke on an {@link IMethod} constant. - */ -public class ReflectiveInvocationInterpreter extends AbstractReflectionInterpreter { - - public final static MethodReference CTOR_NEW_INSTANCE = MethodReference.findOrCreate(TypeReference.JavaLangReflectConstructor, - "newInstance", "([Ljava/lang/Object;)Ljava/lang/Object;"); - - public final static MethodReference METHOD_INVOKE = MethodReference.findOrCreate(TypeReference.JavaLangReflectMethod, "invoke", - "(Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object;"); - - /* - * @see com.ibm.wala.ipa.callgraph.propagation.SSAContextInterpreter#getIR(com.ibm.wala.ipa.callgraph.CGNode) - */ - public IR getIR(CGNode node) { - if (node == null) { - throw new IllegalArgumentException("node is null"); - } - assert understands(node); - if (DEBUG) { - System.err.println("generating IR for " + node); - } - ReceiverInstanceContext recv = (ReceiverInstanceContext) node.getContext(); - ConstantKey c = (ConstantKey) recv.getReceiver(); - IMethod m = (IMethod) c.getValue(); - IR result = makeIR(node.getMethod(), m, recv); - return result; - } - - /* - * @see com.ibm.wala.ipa.callgraph.propagation.SSAContextInterpreter#getNumberOfStatements(com.ibm.wala.ipa.callgraph.CGNode) - */ - public int getNumberOfStatements(CGNode node) { - assert understands(node); - return getIR(node).getInstructions().length; - } - - /* - * @see com.ibm.wala.ipa.callgraph.propagation.rta.RTAContextInterpreter#understands(com.ibm.wala.ipa.callgraph.CGNode) - */ - public boolean understands(CGNode node) { - if (node == null) { - throw new IllegalArgumentException("node is null"); - } - if (!(node.getContext() instanceof ReceiverInstanceContext)) { - return false; - } - ReceiverInstanceContext r = (ReceiverInstanceContext) node.getContext(); - if (!(r.getReceiver() instanceof ConstantKey)) { - return false; - } - return node.getMethod().getReference().equals(METHOD_INVOKE) || node.getMethod().getReference().equals(CTOR_NEW_INSTANCE); - } - - /* - * @see com.ibm.wala.ipa.callgraph.propagation.rta.RTAContextInterpreter#iterateNewSites(com.ibm.wala.ipa.callgraph.CGNode) - */ - public Iterator iterateNewSites(CGNode node) { - if (node == null) { - throw new IllegalArgumentException("node is null"); - } - assert understands(node); - return getIR(node).iterateNewSites(); - } - - /* - * @see com.ibm.wala.ipa.callgraph.propagation.rta.RTAContextInterpreter#iterateCallSites(com.ibm.wala.ipa.callgraph.CGNode) - */ - public Iterator iterateCallSites(CGNode node) { - assert understands(node); - return getIR(node).iterateCallSites(); - } - - /** - * TODO: clean this up. Create the IR for the synthetic method (e.g. Method.invoke) - * - * @param method is something like Method.invoke or Construction.newInstance - * @param target is the method being called reflectively - */ - private IR makeIR(IMethod method, IMethod target, ReceiverInstanceContext context) { - SSAInstructionFactory insts = method.getDeclaringClass().getClassLoader().getInstructionFactory(); - - SpecializedMethod m = new SpecializedMethod(method, method.getDeclaringClass(), method.isStatic(), false); - Map constants = HashMapFactory.make(); - - int nextLocal = method.getNumberOfParameters() + 1; // nextLocal = first free value number - - int nargs = target.getNumberOfParameters(); // nargs := number of parameters to target, including "this" pointer - int args[] = new int[nargs]; - int pc = 0; - int parametersVn = -1; // parametersVn will hold the value number of parameters array - - if (method.getReference().equals(CTOR_NEW_INSTANCE)) { - // allocate the new object constructed - TypeReference allocatedType = target.getDeclaringClass().getReference(); - m - .addInstruction(allocatedType, insts.NewInstruction(args[0] = nextLocal++, NewSiteReference.make(pc++, allocatedType)), - true); - parametersVn = 2; - } else { - // for Method.invoke, v3 is the parameter to the method being called - parametersVn = 3; - if (target.isStatic()) { - // do nothing - } else { - // set up args[0] == the receiver for method.invoke, held in v2. - // insert a cast for v2 to filter out bogus types - args[0] = nextLocal++; - TypeReference type = target.getParameterType(0); - SSACheckCastInstruction cast = insts.CheckCastInstruction(args[0], 2, type, true); - m.addInstruction(null, cast, false); - } - } - int nextArg = target.isStatic() ? 0 : 1; // nextArg := next index in args[] array that needs to be initialized - int nextParameter = 0; // nextParameter := next index in the parameters[] array that needs to be copied into the args[] array. - - // load each of the parameters into a local variable, args[something] - for (int j = nextArg; j < nargs; j++) { - // load the next parameter into v_temp. - int indexConst = nextLocal++; - constants.put(new Integer(indexConst), new ConstantValue(nextParameter++)); - int temp = nextLocal++; - m.addInstruction(null, insts.ArrayLoadInstruction(temp, parametersVn, indexConst, TypeReference.JavaLangObject), false); - pc++; - - // cast v_temp to the appropriate type and store it in args[j] - args[j] = nextLocal++; - TypeReference type = target.getParameterType(j); - // we insert a cast to filter out bogus types - SSACheckCastInstruction cast = insts.CheckCastInstruction(args[j], temp, type, true); - m.addInstruction(null, cast, false); - pc++; - } - - int exceptions = nextLocal++; - int result = -1; - - // emit the dispatch and return instructions - if (method.getReference().equals(CTOR_NEW_INSTANCE)) { - m.addInstruction(null, insts.InvokeInstruction(args, exceptions, CallSiteReference.make(pc++, target.getReference(), - IInvokeInstruction.Dispatch.SPECIAL)), false); - m.addInstruction(null, insts.ReturnInstruction(args[0], false), false); - } else { - Dispatch d = target.isStatic() ? Dispatch.STATIC : Dispatch.VIRTUAL; - if (target.getReturnType().equals(TypeReference.Void)) { - m.addInstruction(null, insts.InvokeInstruction(args, exceptions, CallSiteReference.make(pc++, target.getReference(), d)), - false); - } else { - result = nextLocal++; - m.addInstruction(null, insts.InvokeInstruction(result, args, exceptions, CallSiteReference.make(pc++, - target.getReference(), d)), false); - m.addInstruction(null, insts.ReturnInstruction(result, false), false); - } - } - - SSAInstruction[] instrs = new SSAInstruction[m.allInstructions.size()]; - m.allInstructions. toArray(instrs); - - return new SyntheticIR(method, context, new InducedCFG(instrs, method, context), instrs, SSAOptions.defaultOptions(), constants); - } - - public boolean recordFactoryType(CGNode node, IClass klass) { - return false; - } - - public Iterator iterateFieldsRead(CGNode node) { - return EmptyIterator.instance(); - } - - public Iterator iterateFieldsWritten(CGNode node) { - return EmptyIterator.instance(); - } - - public ControlFlowGraph getCFG(CGNode N) { - return getIR(N).getControlFlowGraph(); - } - - public DefUse getDU(CGNode node) { - return new DefUse(getIR(node)); - } -} +/******************************************************************************* + * Copyright (c) 2008 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.Iterator; +import java.util.Map; + +import com.ibm.wala.cfg.ControlFlowGraph; +import com.ibm.wala.cfg.InducedCFG; +import com.ibm.wala.classLoader.CallSiteReference; +import com.ibm.wala.classLoader.IClass; +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.propagation.ConstantKey; +import com.ibm.wala.ipa.callgraph.propagation.ReceiverInstanceContext; +import com.ibm.wala.ipa.callgraph.propagation.SSAContextInterpreter; +import com.ibm.wala.ipa.summaries.SyntheticIR; +import com.ibm.wala.shrikeBT.IInvokeInstruction; +import com.ibm.wala.shrikeBT.IInvokeInstruction.Dispatch; +import com.ibm.wala.ssa.ConstantValue; +import com.ibm.wala.ssa.DefUse; +import com.ibm.wala.ssa.IR; +import com.ibm.wala.ssa.ISSABasicBlock; +import com.ibm.wala.ssa.SSACheckCastInstruction; +import com.ibm.wala.ssa.SSAInstruction; +import com.ibm.wala.ssa.SSAInstructionFactory; +import com.ibm.wala.ssa.SSAOptions; +import com.ibm.wala.types.FieldReference; +import com.ibm.wala.types.MethodReference; +import com.ibm.wala.types.TypeReference; +import com.ibm.wala.util.collections.EmptyIterator; +import com.ibm.wala.util.collections.HashMapFactory; + +/** + * An {@link SSAContextInterpreter} specialized to interpret reflective invocations such as Constructor.newInstance and + * Method.invoke on an {@link IMethod} constant. + */ +public class ReflectiveInvocationInterpreter extends AbstractReflectionInterpreter { + + public final static MethodReference CTOR_NEW_INSTANCE = MethodReference.findOrCreate(TypeReference.JavaLangReflectConstructor, + "newInstance", "([Ljava/lang/Object;)Ljava/lang/Object;"); + + public final static MethodReference METHOD_INVOKE = MethodReference.findOrCreate(TypeReference.JavaLangReflectMethod, "invoke", + "(Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object;"); + + /* + * @see com.ibm.wala.ipa.callgraph.propagation.SSAContextInterpreter#getIR(com.ibm.wala.ipa.callgraph.CGNode) + */ + public IR getIR(CGNode node) { + if (node == null) { + throw new IllegalArgumentException("node is null"); + } + assert understands(node); + if (DEBUG) { + System.err.println("generating IR for " + node); + } + ReceiverInstanceContext recv = (ReceiverInstanceContext) node.getContext(); + ConstantKey c = (ConstantKey) recv.getReceiver(); + IMethod m = (IMethod) c.getValue(); + IR result = makeIR(node.getMethod(), m, recv); + return result; + } + + /* + * @see com.ibm.wala.ipa.callgraph.propagation.SSAContextInterpreter#getNumberOfStatements(com.ibm.wala.ipa.callgraph.CGNode) + */ + public int getNumberOfStatements(CGNode node) { + assert understands(node); + return getIR(node).getInstructions().length; + } + + /* + * @see com.ibm.wala.ipa.callgraph.propagation.rta.RTAContextInterpreter#understands(com.ibm.wala.ipa.callgraph.CGNode) + */ + public boolean understands(CGNode node) { + if (node == null) { + throw new IllegalArgumentException("node is null"); + } + if (!(node.getContext() instanceof ReceiverInstanceContext)) { + return false; + } + ReceiverInstanceContext r = (ReceiverInstanceContext) node.getContext(); + if (!(r.getReceiver() instanceof ConstantKey)) { + return false; + } + return node.getMethod().getReference().equals(METHOD_INVOKE) || node.getMethod().getReference().equals(CTOR_NEW_INSTANCE); + } + + /* + * @see com.ibm.wala.ipa.callgraph.propagation.rta.RTAContextInterpreter#iterateNewSites(com.ibm.wala.ipa.callgraph.CGNode) + */ + public Iterator iterateNewSites(CGNode node) { + if (node == null) { + throw new IllegalArgumentException("node is null"); + } + assert understands(node); + return getIR(node).iterateNewSites(); + } + + /* + * @see com.ibm.wala.ipa.callgraph.propagation.rta.RTAContextInterpreter#iterateCallSites(com.ibm.wala.ipa.callgraph.CGNode) + */ + public Iterator iterateCallSites(CGNode node) { + assert understands(node); + return getIR(node).iterateCallSites(); + } + + /** + * TODO: clean this up. Create the IR for the synthetic method (e.g. Method.invoke) + * + * @param method is something like Method.invoke or Construction.newInstance + * @param target is the method being called reflectively + */ + private IR makeIR(IMethod method, IMethod target, ReceiverInstanceContext context) { + SSAInstructionFactory insts = method.getDeclaringClass().getClassLoader().getInstructionFactory(); + + SpecializedMethod m = new SpecializedMethod(method, method.getDeclaringClass(), method.isStatic(), false); + Map constants = HashMapFactory.make(); + + int nextLocal = method.getNumberOfParameters() + 1; // nextLocal = first free value number + + int nargs = target.getNumberOfParameters(); // nargs := number of parameters to target, including "this" pointer + int args[] = new int[nargs]; + int pc = 0; + int parametersVn = -1; // parametersVn will hold the value number of parameters array + + if (method.getReference().equals(CTOR_NEW_INSTANCE)) { + // allocate the new object constructed + TypeReference allocatedType = target.getDeclaringClass().getReference(); + m + .addInstruction(allocatedType, insts.NewInstruction(args[0] = nextLocal++, NewSiteReference.make(pc++, allocatedType)), + true); + parametersVn = 2; + } else { + // for Method.invoke, v3 is the parameter to the method being called + parametersVn = 3; + if (target.isStatic()) { + // do nothing + } else { + // set up args[0] == the receiver for method.invoke, held in v2. + // insert a cast for v2 to filter out bogus types + args[0] = nextLocal++; + TypeReference type = target.getParameterType(0); + SSACheckCastInstruction cast = insts.CheckCastInstruction(args[0], 2, type, true); + m.addInstruction(null, cast, false); + } + } + int nextArg = target.isStatic() ? 0 : 1; // nextArg := next index in args[] array that needs to be initialized + int nextParameter = 0; // nextParameter := next index in the parameters[] array that needs to be copied into the args[] array. + + // load each of the parameters into a local variable, args[something] + for (int j = nextArg; j < nargs; j++) { + // load the next parameter into v_temp. + int indexConst = nextLocal++; + constants.put(new Integer(indexConst), new ConstantValue(nextParameter++)); + int temp = nextLocal++; + m.addInstruction(null, insts.ArrayLoadInstruction(temp, parametersVn, indexConst, TypeReference.JavaLangObject), false); + pc++; + + // cast v_temp to the appropriate type and store it in args[j] + args[j] = nextLocal++; + TypeReference type = target.getParameterType(j); + // we insert a cast to filter out bogus types + SSACheckCastInstruction cast = insts.CheckCastInstruction(args[j], temp, type, true); + m.addInstruction(null, cast, false); + pc++; + } + + int exceptions = nextLocal++; + int result = -1; + + // emit the dispatch and return instructions + if (method.getReference().equals(CTOR_NEW_INSTANCE)) { + m.addInstruction(null, insts.InvokeInstruction(args, exceptions, CallSiteReference.make(pc++, target.getReference(), + IInvokeInstruction.Dispatch.SPECIAL)), false); + m.addInstruction(null, insts.ReturnInstruction(args[0], false), false); + } else { + Dispatch d = target.isStatic() ? Dispatch.STATIC : Dispatch.VIRTUAL; + if (target.getReturnType().equals(TypeReference.Void)) { + m.addInstruction(null, insts.InvokeInstruction(args, exceptions, CallSiteReference.make(pc++, target.getReference(), d)), + false); + } else { + result = nextLocal++; + m.addInstruction(null, insts.InvokeInstruction(result, args, exceptions, CallSiteReference.make(pc++, + target.getReference(), d)), false); + m.addInstruction(null, insts.ReturnInstruction(result, false), false); + } + } + + SSAInstruction[] instrs = new SSAInstruction[m.allInstructions.size()]; + m.allInstructions. toArray(instrs); + + return new SyntheticIR(method, context, new InducedCFG(instrs, method, context), instrs, SSAOptions.defaultOptions(), constants); + } + + public boolean recordFactoryType(CGNode node, IClass klass) { + return false; + } + + public Iterator iterateFieldsRead(CGNode node) { + return EmptyIterator.instance(); + } + + public Iterator iterateFieldsWritten(CGNode node) { + return EmptyIterator.instance(); + } + + public ControlFlowGraph getCFG(CGNode N) { + return getIR(N).getControlFlowGraph(); + } + + public DefUse getDU(CGNode node) { + return new DefUse(getIR(node)); + } +} diff --git a/com.ibm.wala.core/src/com/ibm/wala/analysis/reflection/ReflectiveInvocationSelector.java b/com.ibm.wala.core/src/com/ibm/wala/analysis/reflection/ReflectiveInvocationSelector.java index 034d4e1ab..dc3426cee 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/analysis/reflection/ReflectiveInvocationSelector.java +++ b/com.ibm.wala.core/src/com/ibm/wala/analysis/reflection/ReflectiveInvocationSelector.java @@ -1,136 +1,136 @@ -/******************************************************************************* - * Copyright (c) 2008 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.IMethod; -import com.ibm.wala.ipa.callgraph.CGNode; -import com.ibm.wala.ipa.callgraph.Context; -import com.ibm.wala.ipa.callgraph.ContextSelector; -import com.ibm.wala.ipa.callgraph.propagation.ConstantKey; -import com.ibm.wala.ipa.callgraph.propagation.InstanceKey; -import com.ibm.wala.ipa.callgraph.propagation.ReceiverInstanceContext; -import com.ibm.wala.ssa.IR; -import com.ibm.wala.ssa.SSAAbstractInvokeInstruction; -import com.ibm.wala.ssa.SSAInstruction; -import com.ibm.wala.ssa.SSANewInstruction; -import com.ibm.wala.ssa.SymbolTable; -import com.ibm.wala.types.TypeReference; -import com.ibm.wala.util.intset.EmptyIntSet; -import com.ibm.wala.util.intset.IntSet; -import com.ibm.wala.util.intset.IntSetUtil; - -/** - * A {@link ContextSelector} to intercept calls to reflective method invocations such as Constructor.newInstance and Method.invoke - */ -class ReflectiveInvocationSelector implements ContextSelector { - - public ReflectiveInvocationSelector() { - } - - /** - * Creates a callee target based on the following criteria: - *
          - *
        1. If the method being invoked through reflection is definitely static, then do not create a callee target for any - * callee method that is not static. In this case, return null. - *
        2. If the method being invoked through reflection takes a constant number of parameters, n, then do not create a - * callee target for any callee method that takes a number of parameters different from n. In this case, - * return null. - *
        3. Otherwise, return a new {@link ReceiverInstanceContext} for receiver. - *
        - */ - public Context getCalleeTarget(CGNode caller, CallSiteReference site, IMethod callee, InstanceKey[] receiver) { - if (receiver == null || receiver.length == 0 || !mayUnderstand(caller, site, callee, receiver[0])) { - return null; - } - IR ir = caller.getIR(); - SSAAbstractInvokeInstruction[] invokeInstructions = ir.getCalls(site); - if (invokeInstructions.length != 1) { - return new ReceiverInstanceContext(receiver[0]); - } - SymbolTable st = ir.getSymbolTable(); - ConstantKey receiverConstantKey = (ConstantKey) receiver[0]; - IMethod m = (IMethod) receiverConstantKey.getValue(); - boolean isStatic = m.isStatic(); - boolean isConstructor = isConstructorConstant(receiver[0]); - - // If the method being invoked through reflection is not a constructor and is definitely static, then - // we should not create a callee target for any method that is not static - if (!isConstructor) { - int recvUse = invokeInstructions[0].getUse(1); - if (st.isNullConstant(recvUse) && !isStatic) { - return null; - } - } - - // If the method being invoked through reflection is being passed n parameters, - // then we should not create a callee target for any method that takes a number - // of parameters different from n - int numberOfParams = isStatic ? m.getNumberOfParameters() : m.getNumberOfParameters() - 1; - // instruction[0] is a call to Method.invoke(), where the receiver is a specific method, - // the first parameter is the receiver of the method invocation, and the second parameter - // is an array of objects corresponding to the parameters passed to the method. - int paramIndex = isConstructor ? 1 : 2; - int paramUse = invokeInstructions[0].getUse(paramIndex); - SSAInstruction instr = caller.getDU().getDef(paramUse); - if (!(instr instanceof SSANewInstruction)) { - return new ReceiverInstanceContext(receiver[0]); - } - SSANewInstruction newInstr = (SSANewInstruction) instr; - if (!newInstr.getConcreteType().isArrayType()) { - return null; - } - int vn = newInstr.getUse(0); - try { - int arrayLength = st.getIntValue(vn); - if (arrayLength == numberOfParams) { - return new ReceiverInstanceContext(receiver[0]); - } else { - return new IllegalArgumentExceptionContext(); - } - } catch (IllegalArgumentException e) { - return new ReceiverInstanceContext(receiver[0]); - } - } - - /** - * This object may understand a dispatch to Constructor.newInstance(). - */ - private boolean mayUnderstand(CGNode caller, CallSiteReference site, IMethod targetMethod, InstanceKey instance) { - if (instance instanceof ConstantKey) { - if (targetMethod.getReference().equals(ReflectiveInvocationInterpreter.METHOD_INVOKE) || isConstructorConstant(instance) - && targetMethod.getReference().equals(ReflectiveInvocationInterpreter.CTOR_NEW_INSTANCE)) { - return true; - } - } - return false; - } - - private boolean isConstructorConstant(InstanceKey instance) { - if (instance instanceof ConstantKey) { - ConstantKey c = (ConstantKey) instance; - if (c.getConcreteType().getReference().equals(TypeReference.JavaLangReflectConstructor)) { - return true; - } - } - return false; - } - - private static final IntSet thisParameter = IntSetUtil.make(new int[]{0}); - - public IntSet getRelevantParameters(CGNode caller, CallSiteReference site) { - if (site.isDispatch() || site.getDeclaredTarget().getNumberOfParameters() > 0) { - return thisParameter; - } else { - return EmptyIntSet.instance; - } - } +/******************************************************************************* + * Copyright (c) 2008 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.IMethod; +import com.ibm.wala.ipa.callgraph.CGNode; +import com.ibm.wala.ipa.callgraph.Context; +import com.ibm.wala.ipa.callgraph.ContextSelector; +import com.ibm.wala.ipa.callgraph.propagation.ConstantKey; +import com.ibm.wala.ipa.callgraph.propagation.InstanceKey; +import com.ibm.wala.ipa.callgraph.propagation.ReceiverInstanceContext; +import com.ibm.wala.ssa.IR; +import com.ibm.wala.ssa.SSAAbstractInvokeInstruction; +import com.ibm.wala.ssa.SSAInstruction; +import com.ibm.wala.ssa.SSANewInstruction; +import com.ibm.wala.ssa.SymbolTable; +import com.ibm.wala.types.TypeReference; +import com.ibm.wala.util.intset.EmptyIntSet; +import com.ibm.wala.util.intset.IntSet; +import com.ibm.wala.util.intset.IntSetUtil; + +/** + * A {@link ContextSelector} to intercept calls to reflective method invocations such as Constructor.newInstance and Method.invoke + */ +class ReflectiveInvocationSelector implements ContextSelector { + + public ReflectiveInvocationSelector() { + } + + /** + * Creates a callee target based on the following criteria: + *
          + *
        1. If the method being invoked through reflection is definitely static, then do not create a callee target for any + * callee method that is not static. In this case, return null. + *
        2. If the method being invoked through reflection takes a constant number of parameters, n, then do not create a + * callee target for any callee method that takes a number of parameters different from n. In this case, + * return null. + *
        3. Otherwise, return a new {@link ReceiverInstanceContext} for receiver. + *
        + */ + public Context getCalleeTarget(CGNode caller, CallSiteReference site, IMethod callee, InstanceKey[] receiver) { + if (receiver == null || receiver.length == 0 || !mayUnderstand(caller, site, callee, receiver[0])) { + return null; + } + IR ir = caller.getIR(); + SSAAbstractInvokeInstruction[] invokeInstructions = ir.getCalls(site); + if (invokeInstructions.length != 1) { + return new ReceiverInstanceContext(receiver[0]); + } + SymbolTable st = ir.getSymbolTable(); + ConstantKey receiverConstantKey = (ConstantKey) receiver[0]; + IMethod m = (IMethod) receiverConstantKey.getValue(); + boolean isStatic = m.isStatic(); + boolean isConstructor = isConstructorConstant(receiver[0]); + + // If the method being invoked through reflection is not a constructor and is definitely static, then + // we should not create a callee target for any method that is not static + if (!isConstructor) { + int recvUse = invokeInstructions[0].getUse(1); + if (st.isNullConstant(recvUse) && !isStatic) { + return null; + } + } + + // If the method being invoked through reflection is being passed n parameters, + // then we should not create a callee target for any method that takes a number + // of parameters different from n + int numberOfParams = isStatic ? m.getNumberOfParameters() : m.getNumberOfParameters() - 1; + // instruction[0] is a call to Method.invoke(), where the receiver is a specific method, + // the first parameter is the receiver of the method invocation, and the second parameter + // is an array of objects corresponding to the parameters passed to the method. + int paramIndex = isConstructor ? 1 : 2; + int paramUse = invokeInstructions[0].getUse(paramIndex); + SSAInstruction instr = caller.getDU().getDef(paramUse); + if (!(instr instanceof SSANewInstruction)) { + return new ReceiverInstanceContext(receiver[0]); + } + SSANewInstruction newInstr = (SSANewInstruction) instr; + if (!newInstr.getConcreteType().isArrayType()) { + return null; + } + int vn = newInstr.getUse(0); + try { + int arrayLength = st.getIntValue(vn); + if (arrayLength == numberOfParams) { + return new ReceiverInstanceContext(receiver[0]); + } else { + return new IllegalArgumentExceptionContext(); + } + } catch (IllegalArgumentException e) { + return new ReceiverInstanceContext(receiver[0]); + } + } + + /** + * This object may understand a dispatch to Constructor.newInstance(). + */ + private boolean mayUnderstand(CGNode caller, CallSiteReference site, IMethod targetMethod, InstanceKey instance) { + if (instance instanceof ConstantKey) { + if (targetMethod.getReference().equals(ReflectiveInvocationInterpreter.METHOD_INVOKE) || isConstructorConstant(instance) + && targetMethod.getReference().equals(ReflectiveInvocationInterpreter.CTOR_NEW_INSTANCE)) { + return true; + } + } + return false; + } + + private boolean isConstructorConstant(InstanceKey instance) { + if (instance instanceof ConstantKey) { + ConstantKey c = (ConstantKey) instance; + if (c.getConcreteType().getReference().equals(TypeReference.JavaLangReflectConstructor)) { + return true; + } + } + return false; + } + + private static final IntSet thisParameter = IntSetUtil.make(new int[]{0}); + + public IntSet getRelevantParameters(CGNode caller, CallSiteReference site) { + if (site.isDispatch() || site.getDeclaredTarget().getNumberOfParameters() > 0) { + return thisParameter; + } else { + return EmptyIntSet.instance; + } + } } \ No newline at end of file diff --git a/com.ibm.wala.core/src/com/ibm/wala/analysis/stackMachine/AbstractIntStackMachine.java b/com.ibm.wala.core/src/com/ibm/wala/analysis/stackMachine/AbstractIntStackMachine.java index 913dc41e5..316ac6cc1 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/analysis/stackMachine/AbstractIntStackMachine.java +++ b/com.ibm.wala.core/src/com/ibm/wala/analysis/stackMachine/AbstractIntStackMachine.java @@ -1,1145 +1,1145 @@ -/******************************************************************************* - * 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.stackMachine; - -import java.util.Iterator; - -import com.ibm.wala.cfg.ShrikeCFG; -import com.ibm.wala.cfg.ShrikeCFG.BasicBlock; -import com.ibm.wala.dataflow.graph.AbstractMeetOperator; -import com.ibm.wala.dataflow.graph.BasicFramework; -import com.ibm.wala.dataflow.graph.DataflowSolver; -import com.ibm.wala.dataflow.graph.IKilldallFramework; -import com.ibm.wala.dataflow.graph.ITransferFunctionProvider; -import com.ibm.wala.fixpoint.AbstractStatement; -import com.ibm.wala.fixpoint.AbstractVariable; -import com.ibm.wala.fixpoint.FixedPointConstants; -import com.ibm.wala.fixpoint.IVariable; -import com.ibm.wala.fixpoint.UnaryOperator; -import com.ibm.wala.shrikeBT.ArrayLengthInstruction; -import com.ibm.wala.shrikeBT.ConstantInstruction; -import com.ibm.wala.shrikeBT.Constants; -import com.ibm.wala.shrikeBT.DupInstruction; -import com.ibm.wala.shrikeBT.IArrayLoadInstruction; -import com.ibm.wala.shrikeBT.IArrayStoreInstruction; -import com.ibm.wala.shrikeBT.IBinaryOpInstruction; -import com.ibm.wala.shrikeBT.IComparisonInstruction; -import com.ibm.wala.shrikeBT.IConditionalBranchInstruction; -import com.ibm.wala.shrikeBT.IConversionInstruction; -import com.ibm.wala.shrikeBT.IGetInstruction; -import com.ibm.wala.shrikeBT.IInstanceofInstruction; -import com.ibm.wala.shrikeBT.IInstruction; -import com.ibm.wala.shrikeBT.IInvokeInstruction; -import com.ibm.wala.shrikeBT.ILoadInstruction; -import com.ibm.wala.shrikeBT.IPutInstruction; -import com.ibm.wala.shrikeBT.IShiftInstruction; -import com.ibm.wala.shrikeBT.IStoreInstruction; -import com.ibm.wala.shrikeBT.IUnaryOpInstruction; -import com.ibm.wala.shrikeBT.MonitorInstruction; -import com.ibm.wala.shrikeBT.NewInstruction; -import com.ibm.wala.shrikeBT.PopInstruction; -import com.ibm.wala.shrikeBT.SwapInstruction; -import com.ibm.wala.shrikeBT.SwitchInstruction; -import com.ibm.wala.shrikeBT.ThrowInstruction; -import com.ibm.wala.shrikeBT.Util; -import com.ibm.wala.types.ClassLoaderReference; -import com.ibm.wala.types.TypeReference; -import com.ibm.wala.util.CancelException; -import com.ibm.wala.util.CancelRuntimeException; -import com.ibm.wala.util.shrike.ShrikeUtil; - -/** - * Skeleton of functionality to propagate information through the Java bytecode stack machine using ShrikeBT. - *

        - * This class computes properties the Java operand stack and of the local variables at the beginning of each basic block. - *

        - * In this implementation, each dataflow variable value is an integer, and the "meeter" object provides the meets - */ -public abstract class AbstractIntStackMachine implements FixedPointConstants { - - private static final boolean DEBUG = false; - - public static final int TOP = -1; - - public static final int BOTTOM = -2; - - public static final int UNANALYZED = -3; - - public static final int IGNORE = -4; - - /** - * The solver - */ - private DataflowSolver solver; - - /** - * The control flow graph to analyze - */ - final private ShrikeCFG cfg; - - /** - * Should uninitialized variables be considered TOP (optimistic) or BOTTOM (pessimistic); - */ - final public static boolean OPTIMISTIC = true; - - protected AbstractIntStackMachine(final ShrikeCFG G) { - if (G == null) { - throw new IllegalArgumentException("G is null"); - } - this.cfg = G; - } - - protected void init(Meeter meeter, final FlowProvider flow) { - final MeetOperator meet = new MeetOperator(meeter); - ITransferFunctionProvider xferFunctions = new ITransferFunctionProvider() { - public boolean hasNodeTransferFunctions() { - return flow.needsNodeFlow(); - } - - public boolean hasEdgeTransferFunctions() { - return flow.needsEdgeFlow(); - } - - public UnaryOperator getNodeTransferFunction(final BasicBlock node) { - return new UnaryOperator() { - @Override - public byte evaluate(MachineState lhs, MachineState rhs) { - - MachineState exit = lhs; - MachineState entry = rhs; - - MachineState newExit = flow.flow(entry, node); - if (newExit.stateEquals(exit)) { - return NOT_CHANGED; - } else { - exit.copyState(newExit); - return CHANGED; - } - } - - @Override - public String toString() { - return "NODE-FLOW"; - } - - @Override - public int hashCode() { - return 9973 * node.hashCode(); - } - - @Override - public boolean equals(Object o) { - return this == o; - } - }; - } - - public UnaryOperator getEdgeTransferFunction(final BasicBlock from, final BasicBlock to) { - return new UnaryOperator() { - @Override - public byte evaluate(MachineState lhs, MachineState rhs) { - - MachineState exit = lhs; - MachineState entry = rhs; - - MachineState newExit = flow.flow(entry, from, to); - if (newExit.stateEquals(exit)) { - return NOT_CHANGED; - } else { - exit.copyState(newExit); - return CHANGED; - } - } - - @Override - public String toString() { - return "EDGE-FLOW"; - } - - @Override - public int hashCode() { - return 9973 * (from.hashCode() ^ to.hashCode()); - } - - @Override - public boolean equals(Object o) { - return this == o; - } - }; - } - - public AbstractMeetOperator getMeetOperator() { - return meet; - } - }; - - IKilldallFramework problem = new BasicFramework(cfg, xferFunctions); - solver = new DataflowSolver(problem) { - private MachineState entry; - - @Override - protected MachineState makeNodeVariable(BasicBlock n, boolean IN) { - assert n != null; - MachineState result = new MachineState(n); - if (IN && n.equals(cfg.entry())) { - entry = result; - } - return result; - } - - @Override - protected MachineState makeEdgeVariable(BasicBlock from, BasicBlock to) { - assert from != null; - assert to != null; - MachineState result = new MachineState(from); - - return result; - } - - @Override - protected void initializeWorkList() { - super.buildEquations(false, false); - /* - * Add only the entry variable to the work list. - */ - for (Iterator it = getFixedPointSystem().getStatementsThatUse(entry); it.hasNext();) { - AbstractStatement s = (AbstractStatement) it.next(); - addToWorkList(s); - } - } - - @Override - protected void initializeVariables() { - super.initializeVariables(); - AbstractIntStackMachine.this.initializeVariables(); - } - - @Override - protected MachineState[] makeStmtRHS(int size) { - return new MachineState[size]; - } - }; - - } - - public boolean solve() { - try { - return solver.solve(null); - } catch (CancelException e) { - throw new CancelRuntimeException(e); - } - } - - /** - * Convenience method ... a little ugly .. perhaps delete later. - */ - protected void initializeVariables() { - } - - public MachineState getEntryState() { - return solver.getIn(cfg.entry()); - } - - /** - * @return the state at the entry to a given block - */ - public MachineState getIn(ShrikeCFG.BasicBlock bb) { - return solver.getIn(bb); - } - - private class MeetOperator extends AbstractMeetOperator { - - private final Meeter meeter; - - MeetOperator(Meeter meeter) { - this.meeter = meeter; - } - - @Override - public boolean isUnaryNoOp() { - return false; - } - - @Override - public byte evaluate(MachineState lhs, MachineState[] rhs) { - BasicBlock bb = lhs.getBasicBlock(); - if (!bb.isCatchBlock()) { - return meet(lhs, rhs, bb, meeter) ? CHANGED : NOT_CHANGED; - } else { - return meetForCatchBlock(lhs, rhs, bb, meeter) ? CHANGED : NOT_CHANGED; - } - } - - @Override - public int hashCode() { - return 72223 * meeter.hashCode(); - } - - @Override - public boolean equals(Object o) { - if (o instanceof MeetOperator) { - MeetOperator other = (MeetOperator) o; - return meeter.equals(other.meeter); - } else { - return false; - } - } - - @Override - public String toString() { - return "MEETER"; - } - } - - /** - * A Meeter object provides the dataflow logic needed to meet the abstract machine state for a dataflow meet. - */ - protected interface Meeter { - - /** - * Return the integer that represents the meet of a particular stack slot at the entry to a basic block. - * - * @param slot The stack slot to meet - * @param rhs The values to meet - * @param bb The basic block at whose entry this meet occurs - * @return The value result of the meet - */ - int meetStack(int slot, int[] rhs, BasicBlock bb); - - /** - * Return the integer that represents stack slot 0 after a meet at the entry to a catch block. - * - * @param bb The basic block at whose entry this meet occurs - * @return The value of stack slot 0 after the meet - */ - int meetStackAtCatchBlock(BasicBlock bb); - - /** - * Return the integer that represents the meet of a particular local at the entry to a basic block. - * - * @param n The number of the local - * @param rhs The values to meet - * @param bb The basic block at whose entry this meet occurs - * @return The value of local n after the meet. - */ - int meetLocal(int n, int[] rhs, BasicBlock bb); - } - - /** - * Evaluate a meet of machine states. - * - * TODO: add some efficiency shortcuts. TODO: clean up and refactor. - * - * @param bb the basic block at whose entry the meet occurs - * @return true if the lhs value changes. false otherwise. - */ - private boolean meet(IVariable lhs, IVariable[] rhs, BasicBlock bb, Meeter meeter) { - - boolean changed = meetStacks(lhs, rhs, bb, meeter); - - changed |= meetLocals(lhs, rhs, bb, meeter); - return changed; - } - - /** - * Evaluate a meet of machine states at a catch block. - * - * TODO: add some efficiency shortcuts. TODO: clean up and refactor. - * - * @param bb the basic block at whose entry the meet occurs - * @return true if the lhs value changes. false otherwise. - */ - private boolean meetForCatchBlock(IVariable lhs, IVariable[] rhs, BasicBlock bb, Meeter meeter) { - - boolean changed = meetStacksAtCatchBlock(lhs, bb, meeter); - changed |= meetLocals(lhs, rhs, bb, meeter); - return changed; - } - - /** - * Evaluate a meet of the stacks of machine states at the entry of a catch block. - * - * TODO: add some efficiency shortcuts. TODO: clean up and refactor. - * - * @param bb the basic block at whose entry the meet occurs - * @return true if the lhs value changes. false otherwise. - */ - private boolean meetStacksAtCatchBlock(IVariable lhs, BasicBlock bb, Meeter meeter) { - boolean changed = false; - MachineState L = (MachineState) lhs; - - // evaluate the meet of the stack of height 1, which holds the exception - // object. - - // allocate lhs.stack if it's - // not already allocated. - if (L.stack == null) { - L.allocateStack(1); - L.stackHeight = 1; - } - - int meet = meeter.meetStackAtCatchBlock(bb); - if (L.stack[0] == TOP) { - if (meet != TOP) { - changed = true; - L.stack[0] = meet; - } - } else if (meet != L.stack[0]) { - changed = true; - L.stack[0] = meet; - } - return changed; - } - - /** - * Evaluate a meet of the stacks of machine states at the entry of a basic block. - * - * TODO: add some efficiency shortcuts. TODO: clean up and refactor. - * - * @param bb the basic block at whose entry the meet occurs - * @return true if the lhs value changes. false otherwise. - */ - private boolean meetStacks(IVariable lhs, IVariable[] rhs, BasicBlock bb, Meeter meeter) { - boolean changed = false; - MachineState L = (MachineState) lhs; - - // evaluate the element-wise meet over the stacks - - // first ... how high are the stacks? - int height = computeMeetStackHeight(rhs); - - // if there's any stack height to meet, allocate lhs.stack if it's - // not already allocated. - if (height > -1 && (L.stack == null || L.stack.length < height)) { - L.allocateStack(height); - L.stackHeight = height; - changed = true; - } - - // now do the element-wise meet. - for (int i = 0; i < height; i++) { - int[] R = new int[rhs.length]; - for (int j = 0; j < R.length; j++) { - MachineState m = (MachineState) rhs[j]; - if (m.stack == null || m.stack.length < i+1) { - R[j] = TOP; - } else { - R[j] = m.stack[i]; - if (R[j] == 0) { - R[j] = TOP; - } - } - } - int meet = meeter.meetStack(i, R, bb); - if (L.stack[i] == TOP) { - if (meet != TOP) { - changed = true; - L.stack[i] = meet; - } - } else if (meet != L.stack[i]) { - changed = true; - L.stack[i] = meet; - } - } - return changed; - } - - /** - * Evaluate a meet of locals of machine states at the entry to a basic block. - * - * TODO: add some efficiency shortcuts. TODO: clean up and refactor. - * - * @param bb the basic block at whose entry the meet occurs - * @return true if the lhs value changes. false otherwise. - */ - private boolean meetLocals(IVariable lhs, IVariable[] rhs, BasicBlock bb, Meeter meeter) { - - boolean changed = false; - MachineState L = (MachineState) lhs; - // need we allocate lhs.locals? - int nLocals = computeMeetNLocals(rhs); - if (nLocals > -1 && (L.locals == null || L.locals.length < nLocals)) { - L.allocateLocals(nLocals); - } - - // evaluate the element-wise meet over the locals. - for (int i = 0; i < nLocals; i++) { - int[] R = new int[rhs.length]; - for (int j = 0; j < rhs.length; j++) { - R[j] = ((MachineState) rhs[j]).getLocal(i); - } - int meet = meeter.meetLocal(i, R, bb); - if (L.locals[i] == TOP) { - if (meet != TOP) { - changed = true; - L.locals[i] = meet; - } - } else if (meet != L.locals[i]) { - changed = true; - L.locals[i] = meet; - } - } - return changed; - } - - /** - * @return the number of locals to meet. Return -1 if there is no local meet necessary. - * @param operands The operands for this operator. operands[0] is the left-hand side. - */ - private static int computeMeetNLocals(IVariable[] operands) { - MachineState lhs = (MachineState) operands[0]; - int nLocals = -1; - if (lhs.locals != null) { - nLocals = lhs.locals.length; - } else { - for (int i = 1; i < operands.length; i++) { - MachineState rhs = (MachineState) operands[i]; - if (rhs.locals != null) { - nLocals = rhs.locals.length; - break; - } - } - } - return nLocals; - } - - /** - * @return the height of stacks that are being meeted. Return -1 if there is no stack meet necessary. - * @param operands The operands for this operator. operands[0] is the left-hand side. - */ - private static int computeMeetStackHeight(IVariable[] operands) { - MachineState lhs = (MachineState) operands[0]; - int height = -1; - if (lhs.stack != null) { - height = lhs.stackHeight; - } else { - for (int i = 1; i < operands.length; i++) { - MachineState rhs = (MachineState) operands[i]; - if (rhs.stack != null) { - height = rhs.stackHeight; - break; - } - } - } - return height; - } - - /** - * Representation of the state of the JVM stack machine at some program point. - */ - public class MachineState extends AbstractVariable { - private int[] stack; - - private int[] locals; - - // NOTE: stackHeight == -1 is a special code meaning "this variable is TOP" - private int stackHeight; - - private final BasicBlock bb; - - /** - * I'm not using clone because I don't want to necessarily inherit the AbstractVariable state from the superclass - */ - public MachineState duplicate() { - MachineState result = new MachineState(bb); - result.copyState(this); - return result; - } - - public MachineState(BasicBlock bb) { - setTOP(); - this.bb = bb; - } - - public BasicBlock getBasicBlock() { - return bb; - } - - void setTOP() { - stackHeight = -1; - stack = null; - } - - boolean isTOP() { - return stackHeight == -1; - } - - public void push(int i) { - if (stack == null || stackHeight >= stack.length) - allocateStack(stackHeight+1); - stack[stackHeight++] = i; - } - - public int pop() { - if (stackHeight <= 0) { - assert stackHeight > 0 : "can't pop stack of height " + stackHeight; - } - stackHeight -= 1; - return stack[stackHeight]; - } - - public int peek() { - return stack[stackHeight - 1]; - } - - public void swap() { - int temp = stack[stackHeight - 1]; - stack[stackHeight - 1] = stack[stackHeight - 2]; - stack[stackHeight - 2] = temp; - } - - private void allocateStack(int stackHeight) { - if (stack == null) { - stack = new int[stackHeight + 1 ]; - this.stackHeight = 0; - } else { - int[] newStack = new int[ Math.max(stack.length, stackHeight) * 2 + 1 ]; - System.arraycopy(stack, 0, newStack, 0, stack.length); - stack = newStack; - } - } - - private void allocateLocals(int maxLocals) { - int[] result = new int[maxLocals]; - int start = 0; - if (locals != null) { - System.arraycopy(locals, 0, result, 0, locals.length); - start = locals.length; - } - - for (int i = start; i < maxLocals; i++) { - result[i] = OPTIMISTIC ? TOP : BOTTOM; - } - - locals = result; - } - - public void clearStack() { - stackHeight = 0; - } - - /** - * set the value of local i to symbol j - * - * @param i - * @param j - */ - public void setLocal(int i, int j) { - if (locals == null || locals.length < i+1) { - if (OPTIMISTIC && (j == TOP)) { - return; - } else { - allocateLocals(i+1); - } - } - locals[i] = j; - } - - /** - * @param i - * @return the number of the symbol corresponding to local i - */ - public int getLocal(int i) { - if (locals == null || locals.length < i+1) { - if (OPTIMISTIC) { - return TOP; - } else { - return BOTTOM; - } - } else { - return locals[i]; - } - } - - public void replaceValue(int from, int to) { - if (stack != null) - for (int i = 0; i < stackHeight; i++) - if (stack[i] == from) - stack[i] = to; - - if (locals != null) - for (int i = 0; i < locals.length; i++) - if (locals[i] == from) - locals[i] = to; - } - - public boolean hasValue(int val) { - if (stack != null) - for (int i = 0; i < stackHeight; i++) - if (stack[i] == val) - return true; - - if (locals != null) - for (int i = 0; i < locals.length; i++) - if (locals[i] == val) - return true; - - return false; - } - - @Override - public String toString() { - if (isTOP()) { - return "@" + System.identityHashCode(this); - } - StringBuffer result = new StringBuffer("<"); - result.append("S"); - if (stackHeight == 0) { - result.append("[empty]"); - } else { - result.append(array2StringBuffer(stack, stackHeight)); - } - result.append("L"); - result.append(array2StringBuffer(locals, locals.length)); - result.append(">"); - return result.toString(); - } - - private StringBuffer array2StringBuffer(int[] array, int n) { - StringBuffer result = new StringBuffer("["); - if (array == null) { - result.append(OPTIMISTIC ? "TOP" : "BOTTOM"); - } else { - for (int i = 0; i < n - 1; i++) { - result.append(array[i]).append(","); - } - result.append(array[n - 1]); - } - result.append("]"); - return result; - } - - public void copyState(MachineState other) { - if (other.stack == null) { - stack = null; - } else { - stack = new int[other.stack.length]; - System.arraycopy(other.stack, 0, stack, 0, other.stack.length); - } - if (other.locals == null) { - locals = null; - } else { - locals = new int[other.locals.length]; - System.arraycopy(other.locals, 0, locals, 0, other.locals.length); - } - stackHeight = other.stackHeight; - } - - boolean stateEquals(MachineState exit) { - if (stackHeight != exit.stackHeight) - return false; - if (locals == null) { - if (exit.locals != null) - return false; - } else { - if (exit.locals == null) - return false; - else if (locals.length != exit.locals.length) - return false; - } - - for (int i = 0; i < stackHeight; i++) { - if (stack[i] != exit.stack[i]) - return false; - } - if (locals != null) { - for (int i = 0; i < locals.length; i++) { - if (locals[i] == TOP) { - if (exit.locals[i] != TOP) - return false; - } - if (locals[i] != exit.locals[i]) - return false; - } - } - return true; - } - - /** - * Returns the stackHeight. - * - * @return int - */ - public int getStackHeight() { - return stackHeight; - } - - /** - * Use with care. - */ - public int[] getLocals() { - return locals; - } - - } - - /** - * Interface which defines a flow function for a basic block - */ - public interface FlowProvider { - - public boolean needsNodeFlow(); - - public boolean needsEdgeFlow(); - - /** - * Compute the MachineState at the exit of a basic block, given a MachineState at the block's entry. - */ - public MachineState flow(MachineState entry, BasicBlock basicBlock); - - /** - * Compute the MachineState at the end of an edge, given a MachineState at the edges's entry. - */ - public MachineState flow(MachineState entry, BasicBlock from, BasicBlock to); - } - - /** - * This gives some basic facilities for shoving things around on the stack. Client analyses should subclass this as needed. - */ - protected static abstract class BasicStackFlowProvider implements FlowProvider, Constants { - private final ShrikeCFG cfg; - - protected MachineState workingState; - - private BasicStackMachineVisitor visitor; - - private com.ibm.wala.shrikeBT.IInstruction.Visitor edgeVisitor; - - private int currentInstructionIndex = 0; - - private BasicBlock currentBlock; - - private BasicBlock currentSuccessorBlock; - - /** - * Only subclasses can instantiate - */ - protected BasicStackFlowProvider(ShrikeCFG cfg) { - this.cfg = cfg; - } - - /** - * Initialize the visitors used to perform the flow functions - */ - protected void init(BasicStackMachineVisitor v, com.ibm.wala.shrikeBT.IInstruction.Visitor ev) { - this.visitor = v; - this.edgeVisitor = ev; - } - - public boolean needsNodeFlow() { - return true; - } - - public boolean needsEdgeFlow() { - return false; - } - - public MachineState flow(MachineState entry, BasicBlock basicBlock) { - workingState = entry.duplicate(); - currentBlock = basicBlock; - currentSuccessorBlock = null; - IInstruction[] instructions = getInstructions(); - if (DEBUG) { - System.err.println(("Entry to BB" + cfg.getNumber(basicBlock) + " " + workingState)); - } - for (int i = basicBlock.getFirstInstructionIndex(); i <= basicBlock.getLastInstructionIndex(); i++) { - currentInstructionIndex = i; - instructions[i].visit(visitor); - - if (DEBUG) { - System.err.println(("After " + instructions[i] + " " + workingState)); - } - } - return workingState; - } - - public MachineState flow(MachineState entry, BasicBlock from, BasicBlock to) { - workingState = entry.duplicate(); - currentBlock = from; - currentSuccessorBlock = to; - IInstruction[] instructions = getInstructions(); - if (DEBUG) { - System.err.println(("Entry to BB" + cfg.getNumber(from) + " " + workingState)); - } - for (int i = from.getFirstInstructionIndex(); i <= from.getLastInstructionIndex(); i++) { - currentInstructionIndex = i; - instructions[i].visit(edgeVisitor); - if (DEBUG) { - System.err.println(("After " + instructions[i] + " " + workingState)); - } - } - return workingState; - } - - protected int getCurrentInstructionIndex() { - return currentInstructionIndex; - } - - protected int getCurrentProgramCounter() { - return cfg.getProgramCounter(currentInstructionIndex); - } - - protected BasicBlock getCurrentBlock() { - return currentBlock; - } - - protected BasicBlock getCurrentSuccessor() { - return currentSuccessorBlock; - } - - public abstract IInstruction[] getInstructions(); - - /** - * Update the machine state to account for an instruction - */ - protected class BasicStackMachineVisitor extends IInstruction.Visitor { - - /** - * @see com.ibm.wala.shrikeBT.Instruction.Visitor#visitArrayLength(ArrayLengthInstruction) - */ - @Override - public void visitArrayLength(ArrayLengthInstruction instruction) { - - workingState.pop(); - workingState.push(UNANALYZED); - } - - /** - * @see com.ibm.wala.shrikeBT.Instruction.Visitor#visitArrayLoad(IArrayLoadInstruction) - */ - @Override - public void visitArrayLoad(IArrayLoadInstruction instruction) { - workingState.pop(); - workingState.pop(); - workingState.push(UNANALYZED); - } - - /** - * @see com.ibm.wala.shrikeBT.Instruction.Visitor#visitArrayStore(IArrayStoreInstruction) - */ - @Override - public void visitArrayStore(IArrayStoreInstruction instruction) { - workingState.pop(); - workingState.pop(); - workingState.pop(); - } - - /** - * @see com.ibm.wala.shrikeBT.Instruction.Visitor#visitBinaryOp(IBinaryOpInstruction) - */ - @Override - public void visitBinaryOp(IBinaryOpInstruction instruction) { - workingState.pop(); - } - - /** - * @see com.ibm.wala.shrikeBT.Instruction.Visitor#visitComparison(IComparisonInstruction) - */ - @Override - public void visitComparison(IComparisonInstruction instruction) { - workingState.pop(); - workingState.pop(); - workingState.push(UNANALYZED); - } - - /** - * @see com.ibm.wala.shrikeBT.Instruction.Visitor#visitConditionalBranch(IConditionalBranchInstruction) - */ - @Override - public void visitConditionalBranch(IConditionalBranchInstruction instruction) { - workingState.pop(); - workingState.pop(); - } - - /** - * @see com.ibm.wala.shrikeBT.Instruction.Visitor#visitConstant(ConstantInstruction) - */ - @Override - public void visitConstant(ConstantInstruction instruction) { - workingState.push(UNANALYZED); - } - - /** - * @see com.ibm.wala.shrikeBT.Instruction.Visitor#visitConversion(IConversionInstruction) - */ - @Override - public void visitConversion(IConversionInstruction instruction) { - workingState.pop(); - workingState.push(UNANALYZED); - } - - /** - * @see com.ibm.wala.shrikeBT.Instruction.Visitor#visitDup(DupInstruction) - */ - @Override - public void visitDup(DupInstruction instruction) { - - int size = instruction.getSize(); - int delta = instruction.getDelta(); - assert size == 1 || size == 2; - assert delta == 0 || delta == 1 || delta == 2; - int toPop = size + delta; - int v1 = workingState.pop(); - int v2 = (toPop > 1) ? workingState.pop() : IGNORE; - int v3 = (toPop > 2) ? workingState.pop() : IGNORE; - int v4 = (toPop > 3) ? workingState.pop() : IGNORE; - - if (size > 1) { - workingState.push(v2); - } - workingState.push(v1); - if (v4 != IGNORE) { - workingState.push(v4); - } - if (v3 != IGNORE) { - workingState.push(v3); - } - if (v2 != IGNORE) { - workingState.push(v2); - } - workingState.push(v1); - - } - - /** - * @see com.ibm.wala.shrikeBT.Instruction.Visitor#visitGet(IGetInstruction) - */ - @Override - public void visitGet(IGetInstruction instruction) { - popN(instruction); - workingState.push(UNANALYZED); - } - - protected void popN(IInstruction instruction) { - for (int i = 0; i < instruction.getPoppedCount(); i++) { - workingState.pop(); - } - } - - /** - * @see com.ibm.wala.shrikeBT.Instruction.Visitor#visitInstanceof(IInstanceofInstruction) - */ - @Override - public void visitInstanceof(IInstanceofInstruction instruction) { - workingState.pop(); - workingState.push(UNANALYZED); - } - - /** - * @see com.ibm.wala.shrikeBT.Instruction.Visitor#visitInvoke(IInvokeInstruction) - */ - @Override - public void visitInvoke(IInvokeInstruction instruction) { - popN(instruction); - ClassLoaderReference loader = cfg.getMethod().getDeclaringClass().getClassLoader().getReference(); - TypeReference returnType = ShrikeUtil.makeTypeReference(loader, Util.getReturnType(instruction.getMethodSignature())); - if (!returnType.equals(TypeReference.Void)) { - workingState.push(UNANALYZED); - } - } - - /** - * @see com.ibm.wala.shrikeBT.Instruction.Visitor#visitMonitor(MonitorInstruction) - */ - @Override - public void visitMonitor(MonitorInstruction instruction) { - workingState.pop(); - } - - /** - * @see com.ibm.wala.shrikeBT.Instruction.Visitor#visitLocalLoad(ILoadInstruction) - */ - @Override - public void visitLocalLoad(ILoadInstruction instruction) { - int t = workingState.getLocal(instruction.getVarIndex()); - workingState.push(t); - } - - /** - * @see com.ibm.wala.shrikeBT.Instruction.Visitor#visitLocalStore(IStoreInstruction) - */ - @Override - public void visitLocalStore(IStoreInstruction instruction) { - int index = instruction.getVarIndex(); - workingState.setLocal(index, workingState.pop()); - } - - /** - * @see com.ibm.wala.shrikeBT.Instruction.Visitor#visitNew(NewInstruction) - */ - @Override - public void visitNew(NewInstruction instruction) { - popN(instruction); - workingState.push(UNANALYZED); - } - - /** - * @see com.ibm.wala.shrikeBT.Instruction.Visitor#visitPop(PopInstruction) - */ - @Override - public void visitPop(PopInstruction instruction) { - if (instruction.getPoppedCount() > 0) { - workingState.pop(); - } - } - - /** - * @see com.ibm.wala.shrikeBT.Instruction.Visitor#visitPut(IPutInstruction) - */ - @Override - public void visitPut(IPutInstruction instruction) { - popN(instruction); - } - - /** - * @see com.ibm.wala.shrikeBT.Instruction.Visitor#visitShift(IShiftInstruction) - */ - @Override - public void visitShift(IShiftInstruction instruction) { - workingState.pop(); - } - - /** - * @see com.ibm.wala.shrikeBT.Instruction.Visitor#visitSwap(SwapInstruction) - */ - @Override - public void visitSwap(SwapInstruction instruction) { - workingState.swap(); - } - - /** - * @see com.ibm.wala.shrikeBT.Instruction.Visitor#visitSwitch(SwitchInstruction) - */ - @Override - public void visitSwitch(SwitchInstruction instruction) { - workingState.pop(); - } - - /** - * @see com.ibm.wala.shrikeBT.Instruction.Visitor#visitThrow(ThrowInstruction) - */ - @Override - public void visitThrow(ThrowInstruction instruction) { - int exceptionType = workingState.pop(); - workingState.clearStack(); - workingState.push(exceptionType); - } - - /** - * @see com.ibm.wala.shrikeBT.Instruction.Visitor#visitUnaryOp(IUnaryOpInstruction) - */ - @Override - public void visitUnaryOp(IUnaryOpInstruction instruction) { - // treated as a no-op in basic scheme - } - } - } +/******************************************************************************* + * 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.stackMachine; + +import java.util.Iterator; + +import com.ibm.wala.cfg.ShrikeCFG; +import com.ibm.wala.cfg.ShrikeCFG.BasicBlock; +import com.ibm.wala.dataflow.graph.AbstractMeetOperator; +import com.ibm.wala.dataflow.graph.BasicFramework; +import com.ibm.wala.dataflow.graph.DataflowSolver; +import com.ibm.wala.dataflow.graph.IKilldallFramework; +import com.ibm.wala.dataflow.graph.ITransferFunctionProvider; +import com.ibm.wala.fixpoint.AbstractStatement; +import com.ibm.wala.fixpoint.AbstractVariable; +import com.ibm.wala.fixpoint.FixedPointConstants; +import com.ibm.wala.fixpoint.IVariable; +import com.ibm.wala.fixpoint.UnaryOperator; +import com.ibm.wala.shrikeBT.ArrayLengthInstruction; +import com.ibm.wala.shrikeBT.ConstantInstruction; +import com.ibm.wala.shrikeBT.Constants; +import com.ibm.wala.shrikeBT.DupInstruction; +import com.ibm.wala.shrikeBT.IArrayLoadInstruction; +import com.ibm.wala.shrikeBT.IArrayStoreInstruction; +import com.ibm.wala.shrikeBT.IBinaryOpInstruction; +import com.ibm.wala.shrikeBT.IComparisonInstruction; +import com.ibm.wala.shrikeBT.IConditionalBranchInstruction; +import com.ibm.wala.shrikeBT.IConversionInstruction; +import com.ibm.wala.shrikeBT.IGetInstruction; +import com.ibm.wala.shrikeBT.IInstanceofInstruction; +import com.ibm.wala.shrikeBT.IInstruction; +import com.ibm.wala.shrikeBT.IInvokeInstruction; +import com.ibm.wala.shrikeBT.ILoadInstruction; +import com.ibm.wala.shrikeBT.IPutInstruction; +import com.ibm.wala.shrikeBT.IShiftInstruction; +import com.ibm.wala.shrikeBT.IStoreInstruction; +import com.ibm.wala.shrikeBT.IUnaryOpInstruction; +import com.ibm.wala.shrikeBT.MonitorInstruction; +import com.ibm.wala.shrikeBT.NewInstruction; +import com.ibm.wala.shrikeBT.PopInstruction; +import com.ibm.wala.shrikeBT.SwapInstruction; +import com.ibm.wala.shrikeBT.SwitchInstruction; +import com.ibm.wala.shrikeBT.ThrowInstruction; +import com.ibm.wala.shrikeBT.Util; +import com.ibm.wala.types.ClassLoaderReference; +import com.ibm.wala.types.TypeReference; +import com.ibm.wala.util.CancelException; +import com.ibm.wala.util.CancelRuntimeException; +import com.ibm.wala.util.shrike.ShrikeUtil; + +/** + * Skeleton of functionality to propagate information through the Java bytecode stack machine using ShrikeBT. + *

        + * This class computes properties the Java operand stack and of the local variables at the beginning of each basic block. + *

        + * In this implementation, each dataflow variable value is an integer, and the "meeter" object provides the meets + */ +public abstract class AbstractIntStackMachine implements FixedPointConstants { + + private static final boolean DEBUG = false; + + public static final int TOP = -1; + + public static final int BOTTOM = -2; + + public static final int UNANALYZED = -3; + + public static final int IGNORE = -4; + + /** + * The solver + */ + private DataflowSolver solver; + + /** + * The control flow graph to analyze + */ + final private ShrikeCFG cfg; + + /** + * Should uninitialized variables be considered TOP (optimistic) or BOTTOM (pessimistic); + */ + final public static boolean OPTIMISTIC = true; + + protected AbstractIntStackMachine(final ShrikeCFG G) { + if (G == null) { + throw new IllegalArgumentException("G is null"); + } + this.cfg = G; + } + + protected void init(Meeter meeter, final FlowProvider flow) { + final MeetOperator meet = new MeetOperator(meeter); + ITransferFunctionProvider xferFunctions = new ITransferFunctionProvider() { + public boolean hasNodeTransferFunctions() { + return flow.needsNodeFlow(); + } + + public boolean hasEdgeTransferFunctions() { + return flow.needsEdgeFlow(); + } + + public UnaryOperator getNodeTransferFunction(final BasicBlock node) { + return new UnaryOperator() { + @Override + public byte evaluate(MachineState lhs, MachineState rhs) { + + MachineState exit = lhs; + MachineState entry = rhs; + + MachineState newExit = flow.flow(entry, node); + if (newExit.stateEquals(exit)) { + return NOT_CHANGED; + } else { + exit.copyState(newExit); + return CHANGED; + } + } + + @Override + public String toString() { + return "NODE-FLOW"; + } + + @Override + public int hashCode() { + return 9973 * node.hashCode(); + } + + @Override + public boolean equals(Object o) { + return this == o; + } + }; + } + + public UnaryOperator getEdgeTransferFunction(final BasicBlock from, final BasicBlock to) { + return new UnaryOperator() { + @Override + public byte evaluate(MachineState lhs, MachineState rhs) { + + MachineState exit = lhs; + MachineState entry = rhs; + + MachineState newExit = flow.flow(entry, from, to); + if (newExit.stateEquals(exit)) { + return NOT_CHANGED; + } else { + exit.copyState(newExit); + return CHANGED; + } + } + + @Override + public String toString() { + return "EDGE-FLOW"; + } + + @Override + public int hashCode() { + return 9973 * (from.hashCode() ^ to.hashCode()); + } + + @Override + public boolean equals(Object o) { + return this == o; + } + }; + } + + public AbstractMeetOperator getMeetOperator() { + return meet; + } + }; + + IKilldallFramework problem = new BasicFramework(cfg, xferFunctions); + solver = new DataflowSolver(problem) { + private MachineState entry; + + @Override + protected MachineState makeNodeVariable(BasicBlock n, boolean IN) { + assert n != null; + MachineState result = new MachineState(n); + if (IN && n.equals(cfg.entry())) { + entry = result; + } + return result; + } + + @Override + protected MachineState makeEdgeVariable(BasicBlock from, BasicBlock to) { + assert from != null; + assert to != null; + MachineState result = new MachineState(from); + + return result; + } + + @Override + protected void initializeWorkList() { + super.buildEquations(false, false); + /* + * Add only the entry variable to the work list. + */ + for (Iterator it = getFixedPointSystem().getStatementsThatUse(entry); it.hasNext();) { + AbstractStatement s = (AbstractStatement) it.next(); + addToWorkList(s); + } + } + + @Override + protected void initializeVariables() { + super.initializeVariables(); + AbstractIntStackMachine.this.initializeVariables(); + } + + @Override + protected MachineState[] makeStmtRHS(int size) { + return new MachineState[size]; + } + }; + + } + + public boolean solve() { + try { + return solver.solve(null); + } catch (CancelException e) { + throw new CancelRuntimeException(e); + } + } + + /** + * Convenience method ... a little ugly .. perhaps delete later. + */ + protected void initializeVariables() { + } + + public MachineState getEntryState() { + return solver.getIn(cfg.entry()); + } + + /** + * @return the state at the entry to a given block + */ + public MachineState getIn(ShrikeCFG.BasicBlock bb) { + return solver.getIn(bb); + } + + private class MeetOperator extends AbstractMeetOperator { + + private final Meeter meeter; + + MeetOperator(Meeter meeter) { + this.meeter = meeter; + } + + @Override + public boolean isUnaryNoOp() { + return false; + } + + @Override + public byte evaluate(MachineState lhs, MachineState[] rhs) { + BasicBlock bb = lhs.getBasicBlock(); + if (!bb.isCatchBlock()) { + return meet(lhs, rhs, bb, meeter) ? CHANGED : NOT_CHANGED; + } else { + return meetForCatchBlock(lhs, rhs, bb, meeter) ? CHANGED : NOT_CHANGED; + } + } + + @Override + public int hashCode() { + return 72223 * meeter.hashCode(); + } + + @Override + public boolean equals(Object o) { + if (o instanceof MeetOperator) { + MeetOperator other = (MeetOperator) o; + return meeter.equals(other.meeter); + } else { + return false; + } + } + + @Override + public String toString() { + return "MEETER"; + } + } + + /** + * A Meeter object provides the dataflow logic needed to meet the abstract machine state for a dataflow meet. + */ + protected interface Meeter { + + /** + * Return the integer that represents the meet of a particular stack slot at the entry to a basic block. + * + * @param slot The stack slot to meet + * @param rhs The values to meet + * @param bb The basic block at whose entry this meet occurs + * @return The value result of the meet + */ + int meetStack(int slot, int[] rhs, BasicBlock bb); + + /** + * Return the integer that represents stack slot 0 after a meet at the entry to a catch block. + * + * @param bb The basic block at whose entry this meet occurs + * @return The value of stack slot 0 after the meet + */ + int meetStackAtCatchBlock(BasicBlock bb); + + /** + * Return the integer that represents the meet of a particular local at the entry to a basic block. + * + * @param n The number of the local + * @param rhs The values to meet + * @param bb The basic block at whose entry this meet occurs + * @return The value of local n after the meet. + */ + int meetLocal(int n, int[] rhs, BasicBlock bb); + } + + /** + * Evaluate a meet of machine states. + * + * TODO: add some efficiency shortcuts. TODO: clean up and refactor. + * + * @param bb the basic block at whose entry the meet occurs + * @return true if the lhs value changes. false otherwise. + */ + private boolean meet(IVariable lhs, IVariable[] rhs, BasicBlock bb, Meeter meeter) { + + boolean changed = meetStacks(lhs, rhs, bb, meeter); + + changed |= meetLocals(lhs, rhs, bb, meeter); + return changed; + } + + /** + * Evaluate a meet of machine states at a catch block. + * + * TODO: add some efficiency shortcuts. TODO: clean up and refactor. + * + * @param bb the basic block at whose entry the meet occurs + * @return true if the lhs value changes. false otherwise. + */ + private boolean meetForCatchBlock(IVariable lhs, IVariable[] rhs, BasicBlock bb, Meeter meeter) { + + boolean changed = meetStacksAtCatchBlock(lhs, bb, meeter); + changed |= meetLocals(lhs, rhs, bb, meeter); + return changed; + } + + /** + * Evaluate a meet of the stacks of machine states at the entry of a catch block. + * + * TODO: add some efficiency shortcuts. TODO: clean up and refactor. + * + * @param bb the basic block at whose entry the meet occurs + * @return true if the lhs value changes. false otherwise. + */ + private boolean meetStacksAtCatchBlock(IVariable lhs, BasicBlock bb, Meeter meeter) { + boolean changed = false; + MachineState L = (MachineState) lhs; + + // evaluate the meet of the stack of height 1, which holds the exception + // object. + + // allocate lhs.stack if it's + // not already allocated. + if (L.stack == null) { + L.allocateStack(1); + L.stackHeight = 1; + } + + int meet = meeter.meetStackAtCatchBlock(bb); + if (L.stack[0] == TOP) { + if (meet != TOP) { + changed = true; + L.stack[0] = meet; + } + } else if (meet != L.stack[0]) { + changed = true; + L.stack[0] = meet; + } + return changed; + } + + /** + * Evaluate a meet of the stacks of machine states at the entry of a basic block. + * + * TODO: add some efficiency shortcuts. TODO: clean up and refactor. + * + * @param bb the basic block at whose entry the meet occurs + * @return true if the lhs value changes. false otherwise. + */ + private boolean meetStacks(IVariable lhs, IVariable[] rhs, BasicBlock bb, Meeter meeter) { + boolean changed = false; + MachineState L = (MachineState) lhs; + + // evaluate the element-wise meet over the stacks + + // first ... how high are the stacks? + int height = computeMeetStackHeight(rhs); + + // if there's any stack height to meet, allocate lhs.stack if it's + // not already allocated. + if (height > -1 && (L.stack == null || L.stack.length < height)) { + L.allocateStack(height); + L.stackHeight = height; + changed = true; + } + + // now do the element-wise meet. + for (int i = 0; i < height; i++) { + int[] R = new int[rhs.length]; + for (int j = 0; j < R.length; j++) { + MachineState m = (MachineState) rhs[j]; + if (m.stack == null || m.stack.length < i+1) { + R[j] = TOP; + } else { + R[j] = m.stack[i]; + if (R[j] == 0) { + R[j] = TOP; + } + } + } + int meet = meeter.meetStack(i, R, bb); + if (L.stack[i] == TOP) { + if (meet != TOP) { + changed = true; + L.stack[i] = meet; + } + } else if (meet != L.stack[i]) { + changed = true; + L.stack[i] = meet; + } + } + return changed; + } + + /** + * Evaluate a meet of locals of machine states at the entry to a basic block. + * + * TODO: add some efficiency shortcuts. TODO: clean up and refactor. + * + * @param bb the basic block at whose entry the meet occurs + * @return true if the lhs value changes. false otherwise. + */ + private boolean meetLocals(IVariable lhs, IVariable[] rhs, BasicBlock bb, Meeter meeter) { + + boolean changed = false; + MachineState L = (MachineState) lhs; + // need we allocate lhs.locals? + int nLocals = computeMeetNLocals(rhs); + if (nLocals > -1 && (L.locals == null || L.locals.length < nLocals)) { + L.allocateLocals(nLocals); + } + + // evaluate the element-wise meet over the locals. + for (int i = 0; i < nLocals; i++) { + int[] R = new int[rhs.length]; + for (int j = 0; j < rhs.length; j++) { + R[j] = ((MachineState) rhs[j]).getLocal(i); + } + int meet = meeter.meetLocal(i, R, bb); + if (L.locals[i] == TOP) { + if (meet != TOP) { + changed = true; + L.locals[i] = meet; + } + } else if (meet != L.locals[i]) { + changed = true; + L.locals[i] = meet; + } + } + return changed; + } + + /** + * @return the number of locals to meet. Return -1 if there is no local meet necessary. + * @param operands The operands for this operator. operands[0] is the left-hand side. + */ + private static int computeMeetNLocals(IVariable[] operands) { + MachineState lhs = (MachineState) operands[0]; + int nLocals = -1; + if (lhs.locals != null) { + nLocals = lhs.locals.length; + } else { + for (int i = 1; i < operands.length; i++) { + MachineState rhs = (MachineState) operands[i]; + if (rhs.locals != null) { + nLocals = rhs.locals.length; + break; + } + } + } + return nLocals; + } + + /** + * @return the height of stacks that are being meeted. Return -1 if there is no stack meet necessary. + * @param operands The operands for this operator. operands[0] is the left-hand side. + */ + private static int computeMeetStackHeight(IVariable[] operands) { + MachineState lhs = (MachineState) operands[0]; + int height = -1; + if (lhs.stack != null) { + height = lhs.stackHeight; + } else { + for (int i = 1; i < operands.length; i++) { + MachineState rhs = (MachineState) operands[i]; + if (rhs.stack != null) { + height = rhs.stackHeight; + break; + } + } + } + return height; + } + + /** + * Representation of the state of the JVM stack machine at some program point. + */ + public class MachineState extends AbstractVariable { + private int[] stack; + + private int[] locals; + + // NOTE: stackHeight == -1 is a special code meaning "this variable is TOP" + private int stackHeight; + + private final BasicBlock bb; + + /** + * I'm not using clone because I don't want to necessarily inherit the AbstractVariable state from the superclass + */ + public MachineState duplicate() { + MachineState result = new MachineState(bb); + result.copyState(this); + return result; + } + + public MachineState(BasicBlock bb) { + setTOP(); + this.bb = bb; + } + + public BasicBlock getBasicBlock() { + return bb; + } + + void setTOP() { + stackHeight = -1; + stack = null; + } + + boolean isTOP() { + return stackHeight == -1; + } + + public void push(int i) { + if (stack == null || stackHeight >= stack.length) + allocateStack(stackHeight+1); + stack[stackHeight++] = i; + } + + public int pop() { + if (stackHeight <= 0) { + assert stackHeight > 0 : "can't pop stack of height " + stackHeight; + } + stackHeight -= 1; + return stack[stackHeight]; + } + + public int peek() { + return stack[stackHeight - 1]; + } + + public void swap() { + int temp = stack[stackHeight - 1]; + stack[stackHeight - 1] = stack[stackHeight - 2]; + stack[stackHeight - 2] = temp; + } + + private void allocateStack(int stackHeight) { + if (stack == null) { + stack = new int[stackHeight + 1 ]; + this.stackHeight = 0; + } else { + int[] newStack = new int[ Math.max(stack.length, stackHeight) * 2 + 1 ]; + System.arraycopy(stack, 0, newStack, 0, stack.length); + stack = newStack; + } + } + + private void allocateLocals(int maxLocals) { + int[] result = new int[maxLocals]; + int start = 0; + if (locals != null) { + System.arraycopy(locals, 0, result, 0, locals.length); + start = locals.length; + } + + for (int i = start; i < maxLocals; i++) { + result[i] = OPTIMISTIC ? TOP : BOTTOM; + } + + locals = result; + } + + public void clearStack() { + stackHeight = 0; + } + + /** + * set the value of local i to symbol j + * + * @param i + * @param j + */ + public void setLocal(int i, int j) { + if (locals == null || locals.length < i+1) { + if (OPTIMISTIC && (j == TOP)) { + return; + } else { + allocateLocals(i+1); + } + } + locals[i] = j; + } + + /** + * @param i + * @return the number of the symbol corresponding to local i + */ + public int getLocal(int i) { + if (locals == null || locals.length < i+1) { + if (OPTIMISTIC) { + return TOP; + } else { + return BOTTOM; + } + } else { + return locals[i]; + } + } + + public void replaceValue(int from, int to) { + if (stack != null) + for (int i = 0; i < stackHeight; i++) + if (stack[i] == from) + stack[i] = to; + + if (locals != null) + for (int i = 0; i < locals.length; i++) + if (locals[i] == from) + locals[i] = to; + } + + public boolean hasValue(int val) { + if (stack != null) + for (int i = 0; i < stackHeight; i++) + if (stack[i] == val) + return true; + + if (locals != null) + for (int i = 0; i < locals.length; i++) + if (locals[i] == val) + return true; + + return false; + } + + @Override + public String toString() { + if (isTOP()) { + return "@" + System.identityHashCode(this); + } + StringBuffer result = new StringBuffer("<"); + result.append("S"); + if (stackHeight == 0) { + result.append("[empty]"); + } else { + result.append(array2StringBuffer(stack, stackHeight)); + } + result.append("L"); + result.append(array2StringBuffer(locals, locals.length)); + result.append(">"); + return result.toString(); + } + + private StringBuffer array2StringBuffer(int[] array, int n) { + StringBuffer result = new StringBuffer("["); + if (array == null) { + result.append(OPTIMISTIC ? "TOP" : "BOTTOM"); + } else { + for (int i = 0; i < n - 1; i++) { + result.append(array[i]).append(","); + } + result.append(array[n - 1]); + } + result.append("]"); + return result; + } + + public void copyState(MachineState other) { + if (other.stack == null) { + stack = null; + } else { + stack = new int[other.stack.length]; + System.arraycopy(other.stack, 0, stack, 0, other.stack.length); + } + if (other.locals == null) { + locals = null; + } else { + locals = new int[other.locals.length]; + System.arraycopy(other.locals, 0, locals, 0, other.locals.length); + } + stackHeight = other.stackHeight; + } + + boolean stateEquals(MachineState exit) { + if (stackHeight != exit.stackHeight) + return false; + if (locals == null) { + if (exit.locals != null) + return false; + } else { + if (exit.locals == null) + return false; + else if (locals.length != exit.locals.length) + return false; + } + + for (int i = 0; i < stackHeight; i++) { + if (stack[i] != exit.stack[i]) + return false; + } + if (locals != null) { + for (int i = 0; i < locals.length; i++) { + if (locals[i] == TOP) { + if (exit.locals[i] != TOP) + return false; + } + if (locals[i] != exit.locals[i]) + return false; + } + } + return true; + } + + /** + * Returns the stackHeight. + * + * @return int + */ + public int getStackHeight() { + return stackHeight; + } + + /** + * Use with care. + */ + public int[] getLocals() { + return locals; + } + + } + + /** + * Interface which defines a flow function for a basic block + */ + public interface FlowProvider { + + public boolean needsNodeFlow(); + + public boolean needsEdgeFlow(); + + /** + * Compute the MachineState at the exit of a basic block, given a MachineState at the block's entry. + */ + public MachineState flow(MachineState entry, BasicBlock basicBlock); + + /** + * Compute the MachineState at the end of an edge, given a MachineState at the edges's entry. + */ + public MachineState flow(MachineState entry, BasicBlock from, BasicBlock to); + } + + /** + * This gives some basic facilities for shoving things around on the stack. Client analyses should subclass this as needed. + */ + protected static abstract class BasicStackFlowProvider implements FlowProvider, Constants { + private final ShrikeCFG cfg; + + protected MachineState workingState; + + private BasicStackMachineVisitor visitor; + + private com.ibm.wala.shrikeBT.IInstruction.Visitor edgeVisitor; + + private int currentInstructionIndex = 0; + + private BasicBlock currentBlock; + + private BasicBlock currentSuccessorBlock; + + /** + * Only subclasses can instantiate + */ + protected BasicStackFlowProvider(ShrikeCFG cfg) { + this.cfg = cfg; + } + + /** + * Initialize the visitors used to perform the flow functions + */ + protected void init(BasicStackMachineVisitor v, com.ibm.wala.shrikeBT.IInstruction.Visitor ev) { + this.visitor = v; + this.edgeVisitor = ev; + } + + public boolean needsNodeFlow() { + return true; + } + + public boolean needsEdgeFlow() { + return false; + } + + public MachineState flow(MachineState entry, BasicBlock basicBlock) { + workingState = entry.duplicate(); + currentBlock = basicBlock; + currentSuccessorBlock = null; + IInstruction[] instructions = getInstructions(); + if (DEBUG) { + System.err.println(("Entry to BB" + cfg.getNumber(basicBlock) + " " + workingState)); + } + for (int i = basicBlock.getFirstInstructionIndex(); i <= basicBlock.getLastInstructionIndex(); i++) { + currentInstructionIndex = i; + instructions[i].visit(visitor); + + if (DEBUG) { + System.err.println(("After " + instructions[i] + " " + workingState)); + } + } + return workingState; + } + + public MachineState flow(MachineState entry, BasicBlock from, BasicBlock to) { + workingState = entry.duplicate(); + currentBlock = from; + currentSuccessorBlock = to; + IInstruction[] instructions = getInstructions(); + if (DEBUG) { + System.err.println(("Entry to BB" + cfg.getNumber(from) + " " + workingState)); + } + for (int i = from.getFirstInstructionIndex(); i <= from.getLastInstructionIndex(); i++) { + currentInstructionIndex = i; + instructions[i].visit(edgeVisitor); + if (DEBUG) { + System.err.println(("After " + instructions[i] + " " + workingState)); + } + } + return workingState; + } + + protected int getCurrentInstructionIndex() { + return currentInstructionIndex; + } + + protected int getCurrentProgramCounter() { + return cfg.getProgramCounter(currentInstructionIndex); + } + + protected BasicBlock getCurrentBlock() { + return currentBlock; + } + + protected BasicBlock getCurrentSuccessor() { + return currentSuccessorBlock; + } + + public abstract IInstruction[] getInstructions(); + + /** + * Update the machine state to account for an instruction + */ + protected class BasicStackMachineVisitor extends IInstruction.Visitor { + + /** + * @see com.ibm.wala.shrikeBT.Instruction.Visitor#visitArrayLength(ArrayLengthInstruction) + */ + @Override + public void visitArrayLength(ArrayLengthInstruction instruction) { + + workingState.pop(); + workingState.push(UNANALYZED); + } + + /** + * @see com.ibm.wala.shrikeBT.Instruction.Visitor#visitArrayLoad(IArrayLoadInstruction) + */ + @Override + public void visitArrayLoad(IArrayLoadInstruction instruction) { + workingState.pop(); + workingState.pop(); + workingState.push(UNANALYZED); + } + + /** + * @see com.ibm.wala.shrikeBT.Instruction.Visitor#visitArrayStore(IArrayStoreInstruction) + */ + @Override + public void visitArrayStore(IArrayStoreInstruction instruction) { + workingState.pop(); + workingState.pop(); + workingState.pop(); + } + + /** + * @see com.ibm.wala.shrikeBT.Instruction.Visitor#visitBinaryOp(IBinaryOpInstruction) + */ + @Override + public void visitBinaryOp(IBinaryOpInstruction instruction) { + workingState.pop(); + } + + /** + * @see com.ibm.wala.shrikeBT.Instruction.Visitor#visitComparison(IComparisonInstruction) + */ + @Override + public void visitComparison(IComparisonInstruction instruction) { + workingState.pop(); + workingState.pop(); + workingState.push(UNANALYZED); + } + + /** + * @see com.ibm.wala.shrikeBT.Instruction.Visitor#visitConditionalBranch(IConditionalBranchInstruction) + */ + @Override + public void visitConditionalBranch(IConditionalBranchInstruction instruction) { + workingState.pop(); + workingState.pop(); + } + + /** + * @see com.ibm.wala.shrikeBT.Instruction.Visitor#visitConstant(ConstantInstruction) + */ + @Override + public void visitConstant(ConstantInstruction instruction) { + workingState.push(UNANALYZED); + } + + /** + * @see com.ibm.wala.shrikeBT.Instruction.Visitor#visitConversion(IConversionInstruction) + */ + @Override + public void visitConversion(IConversionInstruction instruction) { + workingState.pop(); + workingState.push(UNANALYZED); + } + + /** + * @see com.ibm.wala.shrikeBT.Instruction.Visitor#visitDup(DupInstruction) + */ + @Override + public void visitDup(DupInstruction instruction) { + + int size = instruction.getSize(); + int delta = instruction.getDelta(); + assert size == 1 || size == 2; + assert delta == 0 || delta == 1 || delta == 2; + int toPop = size + delta; + int v1 = workingState.pop(); + int v2 = (toPop > 1) ? workingState.pop() : IGNORE; + int v3 = (toPop > 2) ? workingState.pop() : IGNORE; + int v4 = (toPop > 3) ? workingState.pop() : IGNORE; + + if (size > 1) { + workingState.push(v2); + } + workingState.push(v1); + if (v4 != IGNORE) { + workingState.push(v4); + } + if (v3 != IGNORE) { + workingState.push(v3); + } + if (v2 != IGNORE) { + workingState.push(v2); + } + workingState.push(v1); + + } + + /** + * @see com.ibm.wala.shrikeBT.Instruction.Visitor#visitGet(IGetInstruction) + */ + @Override + public void visitGet(IGetInstruction instruction) { + popN(instruction); + workingState.push(UNANALYZED); + } + + protected void popN(IInstruction instruction) { + for (int i = 0; i < instruction.getPoppedCount(); i++) { + workingState.pop(); + } + } + + /** + * @see com.ibm.wala.shrikeBT.Instruction.Visitor#visitInstanceof(IInstanceofInstruction) + */ + @Override + public void visitInstanceof(IInstanceofInstruction instruction) { + workingState.pop(); + workingState.push(UNANALYZED); + } + + /** + * @see com.ibm.wala.shrikeBT.Instruction.Visitor#visitInvoke(IInvokeInstruction) + */ + @Override + public void visitInvoke(IInvokeInstruction instruction) { + popN(instruction); + ClassLoaderReference loader = cfg.getMethod().getDeclaringClass().getClassLoader().getReference(); + TypeReference returnType = ShrikeUtil.makeTypeReference(loader, Util.getReturnType(instruction.getMethodSignature())); + if (!returnType.equals(TypeReference.Void)) { + workingState.push(UNANALYZED); + } + } + + /** + * @see com.ibm.wala.shrikeBT.Instruction.Visitor#visitMonitor(MonitorInstruction) + */ + @Override + public void visitMonitor(MonitorInstruction instruction) { + workingState.pop(); + } + + /** + * @see com.ibm.wala.shrikeBT.Instruction.Visitor#visitLocalLoad(ILoadInstruction) + */ + @Override + public void visitLocalLoad(ILoadInstruction instruction) { + int t = workingState.getLocal(instruction.getVarIndex()); + workingState.push(t); + } + + /** + * @see com.ibm.wala.shrikeBT.Instruction.Visitor#visitLocalStore(IStoreInstruction) + */ + @Override + public void visitLocalStore(IStoreInstruction instruction) { + int index = instruction.getVarIndex(); + workingState.setLocal(index, workingState.pop()); + } + + /** + * @see com.ibm.wala.shrikeBT.Instruction.Visitor#visitNew(NewInstruction) + */ + @Override + public void visitNew(NewInstruction instruction) { + popN(instruction); + workingState.push(UNANALYZED); + } + + /** + * @see com.ibm.wala.shrikeBT.Instruction.Visitor#visitPop(PopInstruction) + */ + @Override + public void visitPop(PopInstruction instruction) { + if (instruction.getPoppedCount() > 0) { + workingState.pop(); + } + } + + /** + * @see com.ibm.wala.shrikeBT.Instruction.Visitor#visitPut(IPutInstruction) + */ + @Override + public void visitPut(IPutInstruction instruction) { + popN(instruction); + } + + /** + * @see com.ibm.wala.shrikeBT.Instruction.Visitor#visitShift(IShiftInstruction) + */ + @Override + public void visitShift(IShiftInstruction instruction) { + workingState.pop(); + } + + /** + * @see com.ibm.wala.shrikeBT.Instruction.Visitor#visitSwap(SwapInstruction) + */ + @Override + public void visitSwap(SwapInstruction instruction) { + workingState.swap(); + } + + /** + * @see com.ibm.wala.shrikeBT.Instruction.Visitor#visitSwitch(SwitchInstruction) + */ + @Override + public void visitSwitch(SwitchInstruction instruction) { + workingState.pop(); + } + + /** + * @see com.ibm.wala.shrikeBT.Instruction.Visitor#visitThrow(ThrowInstruction) + */ + @Override + public void visitThrow(ThrowInstruction instruction) { + int exceptionType = workingState.pop(); + workingState.clearStack(); + workingState.push(exceptionType); + } + + /** + * @see com.ibm.wala.shrikeBT.Instruction.Visitor#visitUnaryOp(IUnaryOpInstruction) + */ + @Override + public void visitUnaryOp(IUnaryOpInstruction instruction) { + // treated as a no-op in basic scheme + } + } + } } \ No newline at end of file diff --git a/com.ibm.wala.core/src/com/ibm/wala/analysis/typeInference/ConeType.java b/com.ibm.wala.core/src/com/ibm/wala/analysis/typeInference/ConeType.java index 1261e93d6..01718c64a 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/analysis/typeInference/ConeType.java +++ b/com.ibm.wala.core/src/com/ibm/wala/analysis/typeInference/ConeType.java @@ -1,116 +1,116 @@ -/******************************************************************************* - * 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.IClassHierarchy; -import com.ibm.wala.types.TypeReference; -import com.ibm.wala.util.debug.Assertions; - -/** - * Represents a type and its subtypes. - */ -public class ConeType extends TypeAbstraction { - - private final IClass type; - - /** - * @throws IllegalArgumentException if type is null - */ - public ConeType(IClass type) { - if (type == null) { - throw new IllegalArgumentException("type is null"); - } - assert type.getReference().isReferenceType() : type; - this.type = type; - } - - @Override - 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(type.getClassHierarchy().getRootClass()); - } else { - return new ConeType(type.getClassHierarchy().getLeastCommonSuperclass(this.type, other.type)); - } - } 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; - } - } - - - @Override - public String toString() { - return "cone:" + type.toString(); - } - - @Override - public IClass getType() { - return type; - } - - @Override - public TypeReference getTypeReference() { - return type.getReference(); - } - - @Override - public boolean equals(Object obj) { - if (!(obj instanceof ConeType)) { - return false; - } - ConeType other = (ConeType) obj; - if (other == TOP) { - return false; - } - if (!type.getClassHierarchy().equals(other.type.getClassHierarchy())) { - Assertions.UNREACHABLE("different chas " + this + " " + other); - } - return type.equals(other.type); - } - - @Override - public int hashCode() { - return 39 * type.hashCode(); - } - - public boolean isArrayType() { - return getType().isArrayClass(); - } - - public boolean isInterface() { - return getType().isInterface(); - } - - /** - * @return an Iterator of IClass that implement this interface - */ - public Iterator iterateImplementors() { - return type.getClassHierarchy().getImplementors(getType().getReference()).iterator(); - } - - public IClassHierarchy getClassHierarchy() { - return type.getClassHierarchy(); - } -} +/******************************************************************************* + * 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.IClassHierarchy; +import com.ibm.wala.types.TypeReference; +import com.ibm.wala.util.debug.Assertions; + +/** + * Represents a type and its subtypes. + */ +public class ConeType extends TypeAbstraction { + + private final IClass type; + + /** + * @throws IllegalArgumentException if type is null + */ + public ConeType(IClass type) { + if (type == null) { + throw new IllegalArgumentException("type is null"); + } + assert type.getReference().isReferenceType() : type; + this.type = type; + } + + @Override + 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(type.getClassHierarchy().getRootClass()); + } else { + return new ConeType(type.getClassHierarchy().getLeastCommonSuperclass(this.type, other.type)); + } + } 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; + } + } + + + @Override + public String toString() { + return "cone:" + type.toString(); + } + + @Override + public IClass getType() { + return type; + } + + @Override + public TypeReference getTypeReference() { + return type.getReference(); + } + + @Override + public boolean equals(Object obj) { + if (!(obj instanceof ConeType)) { + return false; + } + ConeType other = (ConeType) obj; + if (other == TOP) { + return false; + } + if (!type.getClassHierarchy().equals(other.type.getClassHierarchy())) { + Assertions.UNREACHABLE("different chas " + this + " " + other); + } + return type.equals(other.type); + } + + @Override + public int hashCode() { + return 39 * type.hashCode(); + } + + public boolean isArrayType() { + return getType().isArrayClass(); + } + + public boolean isInterface() { + return getType().isInterface(); + } + + /** + * @return an Iterator of IClass that implement this interface + */ + public Iterator iterateImplementors() { + return type.getClassHierarchy().getImplementors(getType().getReference()).iterator(); + } + + public IClassHierarchy getClassHierarchy() { + return type.getClassHierarchy(); + } +} diff --git a/com.ibm.wala.core/src/com/ibm/wala/analysis/typeInference/PointType.java b/com.ibm.wala.core/src/com/ibm/wala/analysis/typeInference/PointType.java index fe36a0125..6888fca9d 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/analysis/typeInference/PointType.java +++ b/com.ibm.wala.core/src/com/ibm/wala/analysis/typeInference/PointType.java @@ -1,114 +1,114 @@ -/******************************************************************************* - * 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.types.TypeReference; -import com.ibm.wala.util.debug.Assertions; - -/** - * Represents a single concrete type. - */ -public class PointType extends TypeAbstraction { - - private final IClass type; - - /** - * @throws IllegalArgumentException if type is null - */ - public PointType(IClass type) { - if (type == null) { - throw new IllegalArgumentException("type is null"); - } - this.type = type; - assert type.getReference().isReferenceType(); - } - - @Override - 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(type.getClassHierarchy().getRootClass()); - } else { - return new ConeType(type.getClassHierarchy().getLeastCommonSuperclass(this.type, other.type)); - } - } 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(type.getClassHierarchy().getRootClass()); - } - IClass typeKlass = type; - if (type.getClassHierarchy().isSubclassOf(typeKlass, other.getType())) { - return other; - } else if (other.isInterface()) { - if (type.getClassHierarchy().implementsInterface(typeKlass, other.getType())) { - 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(this.getType())); - } else { - Assertions.UNREACHABLE("Unexpected type: " + rhs.getClass()); - return null; - } - } - } - - @Override - public String toString() { - return "point: " + type.toString(); - } - - @Override - public IClass getType() { - return type; - } - - @Override - public TypeReference getTypeReference() { - return type.getReference(); - } - - @Override - public boolean equals(Object obj) { - if (!(obj instanceof PointType)) { - return false; - } - PointType other = (PointType) obj; - if (!type.getClassHierarchy().equals(other.type.getClassHierarchy())) { - Assertions.UNREACHABLE("different chas " + this + " " + other); - } - return type.equals(other.type); - } - - @Override - public int hashCode() { - return 37 * type.hashCode(); - } - - public boolean isArrayType() { - return getType().isArrayClass(); - } - - public IClass getIClass() { - return type; - } -} +/******************************************************************************* + * 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.types.TypeReference; +import com.ibm.wala.util.debug.Assertions; + +/** + * Represents a single concrete type. + */ +public class PointType extends TypeAbstraction { + + private final IClass type; + + /** + * @throws IllegalArgumentException if type is null + */ + public PointType(IClass type) { + if (type == null) { + throw new IllegalArgumentException("type is null"); + } + this.type = type; + assert type.getReference().isReferenceType(); + } + + @Override + 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(type.getClassHierarchy().getRootClass()); + } else { + return new ConeType(type.getClassHierarchy().getLeastCommonSuperclass(this.type, other.type)); + } + } 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(type.getClassHierarchy().getRootClass()); + } + IClass typeKlass = type; + if (type.getClassHierarchy().isSubclassOf(typeKlass, other.getType())) { + return other; + } else if (other.isInterface()) { + if (type.getClassHierarchy().implementsInterface(typeKlass, other.getType())) { + 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(this.getType())); + } else { + Assertions.UNREACHABLE("Unexpected type: " + rhs.getClass()); + return null; + } + } + } + + @Override + public String toString() { + return "point: " + type.toString(); + } + + @Override + public IClass getType() { + return type; + } + + @Override + public TypeReference getTypeReference() { + return type.getReference(); + } + + @Override + public boolean equals(Object obj) { + if (!(obj instanceof PointType)) { + return false; + } + PointType other = (PointType) obj; + if (!type.getClassHierarchy().equals(other.type.getClassHierarchy())) { + Assertions.UNREACHABLE("different chas " + this + " " + other); + } + return type.equals(other.type); + } + + @Override + public int hashCode() { + return 37 * type.hashCode(); + } + + public boolean isArrayType() { + return getType().isArrayClass(); + } + + public IClass getIClass() { + return type; + } +} diff --git a/com.ibm.wala.core/src/com/ibm/wala/analysis/typeInference/PrimitiveType.java b/com.ibm.wala.core/src/com/ibm/wala/analysis/typeInference/PrimitiveType.java index 297e41599..83711ce45 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/analysis/typeInference/PrimitiveType.java +++ b/com.ibm.wala.core/src/com/ibm/wala/analysis/typeInference/PrimitiveType.java @@ -1,90 +1,90 @@ -/******************************************************************************* - * 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.classLoader.IClass; -import com.ibm.wala.types.TypeReference; -import com.ibm.wala.util.collections.HashMapFactory; - -/** - * Abstraction of a primitive type. Subclasses will define the primitive type abstractions for a particular language. - * - * @see JavaPrimitiveType - */ -public abstract class PrimitiveType extends TypeAbstraction { - - final protected static Map referenceToType = HashMapFactory.make(); - - public static PrimitiveType getPrimitive(TypeReference reference) { - return referenceToType.get(reference); - } - - protected final TypeReference reference; - - protected final int size; - - protected PrimitiveType(TypeReference reference, int size) { - this.reference = reference; - this.size = size; - referenceToType.put(reference, this); - } - - @Override - public TypeAbstraction meet(TypeAbstraction rhs) { - if (rhs == TOP) { - return this; - } else if (rhs == this) { - return this; - } else if (rhs instanceof PrimitiveType) { - // the meet of two primitives is the smaller of the two types. - // in particular integer meet boolean == boolean - if (size() < ((PrimitiveType) rhs).size()) { - return this; - } else { - return rhs; - } - } else { - return TOP; - } - } - - public int size() { - return size; - } - - @Override - public int hashCode() { - return reference.hashCode(); - } - - @Override - public boolean equals(Object other) { - return this == other; - } - - @Override - public IClass getType() { - return null; - } - - @Override - public TypeReference getTypeReference() { - return reference; - } - - @Override - public String toString() { - return reference.getName().toString(); - } - -} +/******************************************************************************* + * 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.classLoader.IClass; +import com.ibm.wala.types.TypeReference; +import com.ibm.wala.util.collections.HashMapFactory; + +/** + * Abstraction of a primitive type. Subclasses will define the primitive type abstractions for a particular language. + * + * @see JavaPrimitiveType + */ +public abstract class PrimitiveType extends TypeAbstraction { + + final protected static Map referenceToType = HashMapFactory.make(); + + public static PrimitiveType getPrimitive(TypeReference reference) { + return referenceToType.get(reference); + } + + protected final TypeReference reference; + + protected final int size; + + protected PrimitiveType(TypeReference reference, int size) { + this.reference = reference; + this.size = size; + referenceToType.put(reference, this); + } + + @Override + public TypeAbstraction meet(TypeAbstraction rhs) { + if (rhs == TOP) { + return this; + } else if (rhs == this) { + return this; + } else if (rhs instanceof PrimitiveType) { + // the meet of two primitives is the smaller of the two types. + // in particular integer meet boolean == boolean + if (size() < ((PrimitiveType) rhs).size()) { + return this; + } else { + return rhs; + } + } else { + return TOP; + } + } + + public int size() { + return size; + } + + @Override + public int hashCode() { + return reference.hashCode(); + } + + @Override + public boolean equals(Object other) { + return this == other; + } + + @Override + public IClass getType() { + return null; + } + + @Override + public TypeReference getTypeReference() { + return reference; + } + + @Override + public String toString() { + return reference.getName().toString(); + } + +} diff --git a/com.ibm.wala.core/src/com/ibm/wala/analysis/typeInference/SetType.java b/com.ibm.wala.core/src/com/ibm/wala/analysis/typeInference/SetType.java index f24b649b7..0a6a86d5b 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/analysis/typeInference/SetType.java +++ b/com.ibm.wala.core/src/com/ibm/wala/analysis/typeInference/SetType.java @@ -1,101 +1,101 @@ -/******************************************************************************* - * 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; -import com.ibm.wala.util.debug.UnimplementedError; - -/** - * Abstraction of a set of {@link PointType}. These are immutable. TODO: fix for efficiency if needed. - */ -public class SetType extends TypeAbstraction { - - private final HashSet types; - - private final int hashCode; - - public SetType(PointType[] points) { - if (points == null) { - throw new IllegalArgumentException("points is null"); - } - if (points.length == 0) { - throw new IllegalArgumentException("points.length == 0"); - } - types = HashSetFactory.make(points.length); - int h = 0; - for (int i = 0; i < points.length; i++) { - if (points[i] == null) { - throw new IllegalArgumentException("points[" + i + "] is null"); - } - TypeReference T = points[i].getType().getReference(); - h ^= T.hashCode(); - types.add(T); - } - hashCode = h; - } - - @Override - public TypeReference getTypeReference() { - Iterator ti = types.iterator(); - TypeAbstraction T = (TypeAbstraction) ti.next(); - while (ti.hasNext()) { - T = T.meet((TypeAbstraction) ti.next()); - } - return T.getTypeReference(); - } - - /* - * @see com.ibm.wala.analysis.typeInference.TypeAbstraction#meet(com.ibm.wala.analysis.typeInference.TypeAbstrac ) - */ - @Override - public TypeAbstraction meet(TypeAbstraction rhs) throws UnimplementedError { - Assertions.UNREACHABLE(); - return null; - } - - @Override - 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; - } - } - - @Override - public int hashCode() { - return hashCode; - } - - /** - * @return Iterator of the TypeReferences which compose this Set. - */ - public Iterator iteratePoints() { - return types.iterator(); - } -} +/******************************************************************************* + * 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; +import com.ibm.wala.util.debug.UnimplementedError; + +/** + * Abstraction of a set of {@link PointType}. These are immutable. TODO: fix for efficiency if needed. + */ +public class SetType extends TypeAbstraction { + + private final HashSet types; + + private final int hashCode; + + public SetType(PointType[] points) { + if (points == null) { + throw new IllegalArgumentException("points is null"); + } + if (points.length == 0) { + throw new IllegalArgumentException("points.length == 0"); + } + types = HashSetFactory.make(points.length); + int h = 0; + for (int i = 0; i < points.length; i++) { + if (points[i] == null) { + throw new IllegalArgumentException("points[" + i + "] is null"); + } + TypeReference T = points[i].getType().getReference(); + h ^= T.hashCode(); + types.add(T); + } + hashCode = h; + } + + @Override + public TypeReference getTypeReference() { + Iterator ti = types.iterator(); + TypeAbstraction T = (TypeAbstraction) ti.next(); + while (ti.hasNext()) { + T = T.meet((TypeAbstraction) ti.next()); + } + return T.getTypeReference(); + } + + /* + * @see com.ibm.wala.analysis.typeInference.TypeAbstraction#meet(com.ibm.wala.analysis.typeInference.TypeAbstrac ) + */ + @Override + public TypeAbstraction meet(TypeAbstraction rhs) throws UnimplementedError { + Assertions.UNREACHABLE(); + return null; + } + + @Override + 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; + } + } + + @Override + public int hashCode() { + return hashCode; + } + + /** + * @return Iterator of the TypeReferences which compose this Set. + */ + public Iterator iteratePoints() { + return types.iterator(); + } +} diff --git a/com.ibm.wala.core/src/com/ibm/wala/analysis/typeInference/TypeAbstraction.java b/com.ibm.wala.core/src/com/ibm/wala/analysis/typeInference/TypeAbstraction.java index 7dcefe377..a4b36c39d 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/analysis/typeInference/TypeAbstraction.java +++ b/com.ibm.wala.core/src/com/ibm/wala/analysis/typeInference/TypeAbstraction.java @@ -1,82 +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.analysis.typeInference; - -import com.ibm.wala.classLoader.IClass; -import com.ibm.wala.ipa.callgraph.ContextItem; -import com.ibm.wala.types.TypeReference; - -/** - * Abstraction of a Java type. These are immutable. - * - * @see TypeInference - */ -public abstract class TypeAbstraction implements ContextItem { - - /** - * Canonical element representing TOP for a dataflow lattice - */ - public final static TypeAbstraction TOP = new TypeAbstraction() { - @Override - public TypeAbstraction meet(TypeAbstraction rhs) { - return rhs; - } - - @Override - public String toString() { - return "WalaTypeAbstraction.TOP"; - } - - @Override - public int hashCode() { - return 17; - } - - @Override - public boolean equals(Object other) { - return this == other; - } - - @Override - public IClass getType() { - return null; - } - - @Override - public TypeReference getTypeReference() { - return null; - } - }; - - public abstract TypeAbstraction meet(TypeAbstraction rhs); - - @Override - public abstract boolean equals(Object obj); - - @Override - public abstract int hashCode(); - - /** - * A TypeReference representing the types of this abstraction - */ - public abstract TypeReference getTypeReference(); - - /** - * This is here for convenience; it makes sense for Point and Cone Dispatch. - * TODO: probably should get rid of it. - * @throws UnsupportedOperationException unconditionally - */ - public IClass getType() throws UnsupportedOperationException { - throw new UnsupportedOperationException("getType not implemented for " + getClass()); - } - -} +/******************************************************************************* + * 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.types.TypeReference; + +/** + * Abstraction of a Java type. These are immutable. + * + * @see TypeInference + */ +public abstract class TypeAbstraction implements ContextItem { + + /** + * Canonical element representing TOP for a dataflow lattice + */ + public final static TypeAbstraction TOP = new TypeAbstraction() { + @Override + public TypeAbstraction meet(TypeAbstraction rhs) { + return rhs; + } + + @Override + public String toString() { + return "WalaTypeAbstraction.TOP"; + } + + @Override + public int hashCode() { + return 17; + } + + @Override + public boolean equals(Object other) { + return this == other; + } + + @Override + public IClass getType() { + return null; + } + + @Override + public TypeReference getTypeReference() { + return null; + } + }; + + public abstract TypeAbstraction meet(TypeAbstraction rhs); + + @Override + public abstract boolean equals(Object obj); + + @Override + public abstract int hashCode(); + + /** + * A TypeReference representing the types of this abstraction + */ + public abstract TypeReference getTypeReference(); + + /** + * This is here for convenience; it makes sense for Point and Cone Dispatch. + * TODO: probably should get rid of it. + * @throws UnsupportedOperationException unconditionally + */ + public IClass getType() throws UnsupportedOperationException { + throw new UnsupportedOperationException("getType not implemented for " + getClass()); + } + +} diff --git a/com.ibm.wala.core/src/com/ibm/wala/analysis/typeInference/TypeInference.java b/com.ibm.wala.core/src/com/ibm/wala/analysis/typeInference/TypeInference.java index 8a76ce6b9..513e67c75 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/analysis/typeInference/TypeInference.java +++ b/com.ibm.wala.core/src/com/ibm/wala/analysis/typeInference/TypeInference.java @@ -1,804 +1,804 @@ -/******************************************************************************* - * 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.classLoader.Language; -import com.ibm.wala.dataflow.ssa.SSAInference; -import com.ibm.wala.fixedpoint.impl.NullaryOperator; -import com.ibm.wala.fixpoint.AbstractOperator; -import com.ibm.wala.fixpoint.FixedPointConstants; -import com.ibm.wala.fixpoint.IVariable; -import com.ibm.wala.ipa.cha.IClassHierarchy; -import com.ibm.wala.shrikeCT.InvalidClassFileException; -import com.ibm.wala.ssa.IR; -import com.ibm.wala.ssa.IVisitorWithAddresses; -import com.ibm.wala.ssa.SSAAbstractInvokeInstruction; -import com.ibm.wala.ssa.SSAAddressOfInstruction; -import com.ibm.wala.ssa.SSAArrayLengthInstruction; -import com.ibm.wala.ssa.SSAArrayLoadInstruction; -import com.ibm.wala.ssa.SSABinaryOpInstruction; -import com.ibm.wala.ssa.SSACFG.ExceptionHandlerBasicBlock; -import com.ibm.wala.ssa.SSACheckCastInstruction; -import com.ibm.wala.ssa.SSAComparisonInstruction; -import com.ibm.wala.ssa.SSAConversionInstruction; -import com.ibm.wala.ssa.SSAGetCaughtExceptionInstruction; -import com.ibm.wala.ssa.SSAGetInstruction; -import com.ibm.wala.ssa.SSAInstanceofInstruction; -import com.ibm.wala.ssa.SSAInstruction; -import com.ibm.wala.ssa.SSAInvokeInstruction; -import com.ibm.wala.ssa.SSALoadIndirectInstruction; -import com.ibm.wala.ssa.SSALoadMetadataInstruction; -import com.ibm.wala.ssa.SSANewInstruction; -import com.ibm.wala.ssa.SSAPhiInstruction; -import com.ibm.wala.ssa.SSAPiInstruction; -import com.ibm.wala.ssa.SSAStoreIndirectInstruction; -import com.ibm.wala.ssa.SSAUnaryOpInstruction; -import com.ibm.wala.ssa.SymbolTable; -import com.ibm.wala.types.TypeReference; -import com.ibm.wala.util.CancelException; -import com.ibm.wala.util.CancelRuntimeException; -import com.ibm.wala.util.MonitorUtil.IProgressMonitor; -import com.ibm.wala.util.debug.Assertions; - -/** - * This class performs intraprocedural type propagation on an SSA IR. - */ -public class TypeInference extends SSAInference implements FixedPointConstants { - - private static final boolean DEBUG = false; - - public static TypeInference make(IR ir, boolean doPrimitives) { - return new TypeInference(ir, doPrimitives); - } - - /** - * The governing SSA form - */ - final protected IR ir; - - /** - * The governing class hierarchy - */ - final protected IClassHierarchy cha; - - final protected Language language; - - /** - * 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; - - private boolean solved = false; - - protected TypeInference(IR ir, boolean doPrimitives) { - if (ir == null) { - throw new IllegalArgumentException("ir is null"); - } - this.language = ir.getMethod().getDeclaringClass().getClassLoader().getLanguage(); - this.cha = ir.getMethod().getDeclaringClass().getClassHierarchy(); - this.ir = ir; - this.doPrimitives = doPrimitives; - this.BOTTOM = new ConeType(cha.getRootClass()); - initialize(); - solve(); - } - - public boolean solve() { - return solve(null); - } - - @Override - public boolean solve(IProgressMonitor monitor) { - try { - if (solved) { - return false; - } else { - boolean result = super.solve(null); - solved = true; - return result; - } - } catch (CancelException e) { - throw new CancelRuntimeException(e); - } - } - - protected void initialize() { - init(ir, this.new TypeVarFactory(), this.new TypeOperatorFactory()); - } - - @Override - protected void initializeVariables() { - - if (DEBUG) { - System.err.println("initializeVariables " + ir.getMethod()); - } - - int[] parameterValueNumbers = ir.getParameterValueNumbers(); - for (int i = 0; i < parameterValueNumbers.length; i++) { - TypeVariable v = getVariable(parameterValueNumbers[i]); - TypeReference t = ir.getParameterType(i); - - if (DEBUG) { - System.err.println("parameter " + parameterValueNumbers[i] + " " + t); - } - - if (t.isReferenceType()) { - IClass klass = cha.lookupClass(t); - if (DEBUG) { - System.err.println("klass " + klass); - } - if (klass != null) { - v.setType(new ConeType(klass)); - } else { - // give up .. default to java.lang.Object (BOTTOM) - v.setType(BOTTOM); - } - } else if (doPrimitives) { - v.setType(language.getPrimitive(t)); - } - } - - SymbolTable st = ir.getSymbolTable(); - if (st != null) { - for (int i = 0; i <= st.getMaxValueNumber(); i++) { - if (st.isConstant(i)) { - TypeVariable v = getVariable(i); - v.setType(getConstantType(i)); - } - } - } - - for (Iterator it = ir.iterateNormalInstructions(); it.hasNext();) { - SSAInstruction s = it.next(); - if (s instanceof SSAAbstractInvokeInstruction) { - SSAAbstractInvokeInstruction call = (SSAAbstractInvokeInstruction) s; - TypeVariable v = getVariable(call.getException()); - Collection defaultExceptions = call.getExceptionTypes(); - if (defaultExceptions.size() == 0) { - continue; - } - - Iterator types = defaultExceptions.iterator(); - TypeReference t = types.next(); - IClass klass = cha.lookupClass(t); - if (klass == null) { - v.setType(BOTTOM); - } else { - v.setType(new PointType(klass)); - } - - while(types.hasNext()) { - t = types.next(); - klass = cha.lookupClass(t); - if (klass != null) { - v.setType(v.getType().meet(new PointType(klass))); - } - } - - IMethod m = cha.resolveMethod(call.getDeclaredTarget()); - if (m != null) { - TypeReference[] x = null; - try { - x = m.getDeclaredExceptions(); - } catch (InvalidClassFileException e) { - e.printStackTrace(); - Assertions.UNREACHABLE(); - } catch (UnsupportedOperationException e) { - x = new TypeReference[]{ language.getThrowableType() }; - } - 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))); - } - } - } - } - } - } - } - - @Override - protected void initializeWorkList() { - addAllStatementsToWorkList(); - } - - /** - * An operator which initializes a type to a declared type. - */ - protected static final class DeclaredTypeOperator extends NullaryOperator { - private final TypeAbstraction type; - - public DeclaredTypeOperator(TypeAbstraction type) { - assert type != null; - this.type = type; - } - - /** - * Note that we need evaluate this operator at most once - */ - @Override - public byte evaluate(TypeVariable lhs) { - if (lhs.type.equals(type)) { - return NOT_CHANGED_AND_FIXED; - } else { - lhs.setType(type); - return CHANGED_AND_FIXED; - } - } - - /** - * @see java.lang.Object#toString() - */ - @Override - public String toString() { - return "delared type := " + type; - } - - public boolean isNullary() { - return true; - } - - @Override - public int hashCode() { - return 9931 * type.hashCode(); - } - - @Override - public boolean equals(Object o) { - if (o instanceof DeclaredTypeOperator) { - DeclaredTypeOperator d = (DeclaredTypeOperator) o; - return type.equals(d.type); - } else { - return false; - } - } - } - - private static final class PhiOperator extends AbstractOperator { - - private PhiOperator() { - } - - /** - * TODO: work on efficiency shortcuts for this. - */ - @Override - public byte evaluate(TypeVariable lhs, TypeVariable[] rhs) { - - if (DEBUG) { - System.err.print("PhiOperator.meet " + lhs + " "); - for (IVariable v : rhs) { - System.err.print(v + " "); - } - System.err.println(); - } - - TypeAbstraction lhsType = lhs.getType(); - TypeAbstraction meet = TypeAbstraction.TOP; - for (int i = 0; i < rhs.length; i++) { - if (rhs[i] != null && ((TypeVariable)rhs[i]).getType() != null) { - TypeVariable r = (TypeVariable) rhs[i]; - meet = meet.meet(r.getType()); - } - } - if (lhsType.equals(meet)) { - return NOT_CHANGED; - } else { - lhs.setType(meet); - return CHANGED; - } - } - - @Override - public String toString() { - return "phi meet"; - } - - @Override - public int hashCode() { - return 9929; - } - - @Override - public boolean equals(Object o) { - return (o instanceof PhiOperator); - } - } - - private static final class PiOperator extends AbstractOperator { - - private PiOperator() { - } - - /** - * TODO: work on efficiency shortcuts for this. - */ - @Override - public byte evaluate(TypeVariable lhs, TypeVariable[] rhsOperands) { - 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; - } - } - - @Override - public String toString() { - return "pi"; - } - - @Override - public int hashCode() { - return 9929 * 13; - } - - @Override - public boolean equals(Object o) { - return (o instanceof PiOperator); - } - } - - protected static class PrimitivePropagateOperator extends AbstractOperator { - - protected PrimitivePropagateOperator() { - } - - @Override - public byte evaluate(TypeVariable lhs, TypeVariable[] rhs) { - TypeAbstraction lhsType = lhs.getType(); - TypeAbstraction meet = TypeAbstraction.TOP; - for (int i = 0; i < rhs.length; i++) { - if (rhs[i] != null && ((TypeVariable)rhs[i]).getType() != null) { - TypeVariable r = (TypeVariable) rhs[i]; - meet = meet.meet(r.getType()); - } - } - if (lhsType.equals(meet)) { - return NOT_CHANGED; - } else { - lhs.setType(meet); - return CHANGED; - } - } - - @Override - public String toString() { - return "propagate"; - } - - @Override - public int hashCode() { - return 99292; - } - - @Override - public boolean equals(Object o) { - return o != null && o.getClass().equals(getClass()); - } - } - - /** - * 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; - } - - @Override - public byte evaluate(TypeVariable lhs, TypeVariable[] rhs) { - TypeAbstraction arrayType = getType(load.getArrayRef()); - if (arrayType == null || 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 && lhs.getType() == TypeAbstraction.TOP) { - lhs.setType(PrimitiveType.getPrimitive(elementType)); - return CHANGED; - } - return NOT_CHANGED; - } - - if (lhs.getType() != TypeAbstraction.TOP) { - TypeReference tType = null; - if (lhs.getType() instanceof PointType) { - tType = ((PointType) lhs.getType()).getType().getReference(); - } else if (lhs.getType() instanceof ConeType) { - tType = ((ConeType) lhs.getType()).getType().getReference(); - } else { - Assertions.UNREACHABLE("Unexpected type " + lhs.getType().getClass()); - } - if (tType.equals(elementType)) { - return NOT_CHANGED; - } else { - IClass klass = cha.lookupClass(elementType); - assert klass != null; - lhs.setType(new ConeType(klass)); - return CHANGED; - } - } else { - IClass klass = cha.lookupClass(elementType); - if (klass != null) { - lhs.setType(new ConeType(klass)); - } else { - lhs.setType(TypeAbstraction.TOP); - } - - return CHANGED; - } - } - - @Override - public String toString() { - return "getElementType " + load; - } - - @Override - public int hashCode() { - return 9923 * load.hashCode(); - } - - @Override - 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 IVisitorWithAddresses, OperatorFactory { - - protected AbstractOperator result = null; - - public AbstractOperator get(SSAInstruction instruction) { - instruction.visit(this); - AbstractOperator temp = result; - result = null; - return temp; - } - - @Override - public void visitArrayLoad(SSAArrayLoadInstruction instruction) { - result = new GetElementType(instruction); - } - - @Override - public void visitArrayLength(SSAArrayLengthInstruction instruction) { - if (!doPrimitives) { - result = null; - } else { - result = new DeclaredTypeOperator(language.getPrimitive(language.getConstantType(new Integer(1)))); - } - } - - @Override - public void visitLoadMetadata(SSALoadMetadataInstruction instruction) { - IClass jlClassKlass = cha.lookupClass(language.getMetadataType()); - assert jlClassKlass != null; - result = new DeclaredTypeOperator(new ConeType(jlClassKlass)); - } - - @Override - public void visitGet(SSAGetInstruction instruction) { - TypeReference type = instruction.getDeclaredFieldType(); - - if (doPrimitives && type.isPrimitiveType()) { - PrimitiveType p = language.getPrimitive(type); - assert p != null : "no type for " + type; - result = new DeclaredTypeOperator(p); - } 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)); - } - } - } - - @Override - 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)); - } - } else if (doPrimitives && type.isPrimitiveType()) { - result = new DeclaredTypeOperator(language.getPrimitive(type)); - } else { - result = null; - } - } - - @Override - 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)); - } - } - - @Override - public void visitCheckCast(SSACheckCastInstruction instruction) { - TypeAbstraction typeAbs = null; - for (TypeReference type : instruction.getDeclaredResultTypes()) { - IClass klass = cha.lookupClass(type); - if (klass == null) { - // a type that cannot be loaded. - // be pessimistic - typeAbs = BOTTOM; - } else { - TypeAbstraction x = null; - if (doPrimitives && type.isPrimitiveType()) { - x = language.getPrimitive(type); - } else if (type.isReferenceType()) { - x = new ConeType(klass); - } - if (x != null) { - if (typeAbs == null) { - typeAbs = x; - } else { - typeAbs = typeAbs.meet(x); - } - } - } - } - - result = new DeclaredTypeOperator(typeAbs); - } - - @Override - public void visitConversion(SSAConversionInstruction instruction) { - if (doPrimitives) { - result = new DeclaredTypeOperator(language.getPrimitive(instruction.getToType())); - } - } - - @Override - public void visitComparison(SSAComparisonInstruction instruction) { - if (doPrimitives) { - result = new DeclaredTypeOperator(language.getPrimitive(language.getConstantType(new Integer(0)))); - } - } - - @Override - public void visitBinaryOp(SSABinaryOpInstruction instruction) { - if (doPrimitives) { - result = primitivePropagateOp; - } - } - - @Override - public void visitUnaryOp(SSAUnaryOpInstruction instruction) { - if (doPrimitives) { - result = primitivePropagateOp; - } - } - - @Override - public void visitInstanceof(SSAInstanceofInstruction instruction) { - if (doPrimitives) { - result = new DeclaredTypeOperator(language.getPrimitive(language.getConstantType(Boolean.TRUE))); - } - } - - @Override - public void visitGetCaughtException(SSAGetCaughtExceptionInstruction instruction) { - TypeAbstraction type = meetDeclaredExceptionTypes(instruction); - result = new DeclaredTypeOperator(type); - } - - @Override - public void visitPhi(SSAPhiInstruction instruction) { - result = phiOp; - } - - @Override - public void visitPi(SSAPiInstruction instruction) { - result = piOp; - } - - private TypeAbstraction meetDeclaredExceptionTypes(SSAGetCaughtExceptionInstruction s) { - 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); - } - while (it.hasNext()) { - t = (TypeReference) it.next(); - IClass tClass = cha.lookupClass(t); - if (tClass == null) { - result = BOTTOM; - } else { - result = result.meet(new ConeType(tClass)); - } - } - return result; - } - - private DeclaredTypeOperator getPointerTypeOperator(TypeReference type) { - if (type.isPrimitiveType()) { - return new DeclaredTypeOperator(language.getPrimitive(type)); - } else { - IClass klass = cha.lookupClass(type); - if (klass == null) { - // a type that cannot be loaded. - // be pessimistic - return new DeclaredTypeOperator(BOTTOM); - } else { - return new DeclaredTypeOperator(new ConeType(klass)); - } - } - } - - public void visitAddressOf(SSAAddressOfInstruction instruction) { - TypeReference type = language.getPointerType(instruction.getType()); - result = getPointerTypeOperator(type); - } - - public void visitLoadIndirect(SSALoadIndirectInstruction instruction) { - result = getPointerTypeOperator(instruction.getLoadedType()); - } - - public void visitStoreIndirect(SSAStoreIndirectInstruction instruction) { - Assertions.UNREACHABLE(); - } - } - - 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(language.getPrimitive(language.getConstantType(Boolean.TRUE))); - } - } - } - - return new TypeVariable(TypeAbstraction.TOP); - } - - } - - public IR getIR() { - return ir; - } - - /** - * Return the type computed for a particular value number - */ - public TypeAbstraction getType(int valueNumber) { - if (valueNumber < 0) { - throw new IllegalArgumentException("bad value number " + valueNumber); - } - assert getVariable(valueNumber) != null : "null variable for value number " + valueNumber; - return getVariable(valueNumber).getType(); - } - - public TypeAbstraction getConstantType(int valueNumber) { - if (ir.getSymbolTable().isStringConstant(valueNumber)) { - return new PointType(cha.lookupClass(language.getStringType())); - } else { - return getConstantPrimitiveType(valueNumber); - } - } - - public TypeAbstraction getConstantPrimitiveType(int valueNumber) { - SymbolTable st = ir.getSymbolTable(); - if (!st.isConstant(valueNumber) || st.isNullConstant(valueNumber)) { - return TypeAbstraction.TOP; - } else { - return language.getPrimitive(language.getConstantType(st.getConstantValue(valueNumber))); - } - } - - 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 = getVariable(valueNumber).getType(); - return ta == BOTTOM || ta.getType() == null; - } - - /** - * Extract all results of the type inference analysis. - * - * @return an array, where the i'th variable holds the type abstraction of the i'th value number. - */ - public TypeAbstraction[] extractAllResults() { - int numberOfVars = ir.getSymbolTable().getMaxValueNumber() + 1; - TypeAbstraction[] ret = new TypeAbstraction[numberOfVars]; - - for (int i = 0; i < numberOfVars; ++i) { - TypeVariable var = getVariable(i); - ret[i] = var == null ? null : var.getType(); - } - - return ret; - } - - @Override - protected TypeVariable[] makeStmtRHS(int size) { - return new TypeVariable[size]; - } -} +/******************************************************************************* + * 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.classLoader.Language; +import com.ibm.wala.dataflow.ssa.SSAInference; +import com.ibm.wala.fixedpoint.impl.NullaryOperator; +import com.ibm.wala.fixpoint.AbstractOperator; +import com.ibm.wala.fixpoint.FixedPointConstants; +import com.ibm.wala.fixpoint.IVariable; +import com.ibm.wala.ipa.cha.IClassHierarchy; +import com.ibm.wala.shrikeCT.InvalidClassFileException; +import com.ibm.wala.ssa.IR; +import com.ibm.wala.ssa.IVisitorWithAddresses; +import com.ibm.wala.ssa.SSAAbstractInvokeInstruction; +import com.ibm.wala.ssa.SSAAddressOfInstruction; +import com.ibm.wala.ssa.SSAArrayLengthInstruction; +import com.ibm.wala.ssa.SSAArrayLoadInstruction; +import com.ibm.wala.ssa.SSABinaryOpInstruction; +import com.ibm.wala.ssa.SSACFG.ExceptionHandlerBasicBlock; +import com.ibm.wala.ssa.SSACheckCastInstruction; +import com.ibm.wala.ssa.SSAComparisonInstruction; +import com.ibm.wala.ssa.SSAConversionInstruction; +import com.ibm.wala.ssa.SSAGetCaughtExceptionInstruction; +import com.ibm.wala.ssa.SSAGetInstruction; +import com.ibm.wala.ssa.SSAInstanceofInstruction; +import com.ibm.wala.ssa.SSAInstruction; +import com.ibm.wala.ssa.SSAInvokeInstruction; +import com.ibm.wala.ssa.SSALoadIndirectInstruction; +import com.ibm.wala.ssa.SSALoadMetadataInstruction; +import com.ibm.wala.ssa.SSANewInstruction; +import com.ibm.wala.ssa.SSAPhiInstruction; +import com.ibm.wala.ssa.SSAPiInstruction; +import com.ibm.wala.ssa.SSAStoreIndirectInstruction; +import com.ibm.wala.ssa.SSAUnaryOpInstruction; +import com.ibm.wala.ssa.SymbolTable; +import com.ibm.wala.types.TypeReference; +import com.ibm.wala.util.CancelException; +import com.ibm.wala.util.CancelRuntimeException; +import com.ibm.wala.util.MonitorUtil.IProgressMonitor; +import com.ibm.wala.util.debug.Assertions; + +/** + * This class performs intraprocedural type propagation on an SSA IR. + */ +public class TypeInference extends SSAInference implements FixedPointConstants { + + private static final boolean DEBUG = false; + + public static TypeInference make(IR ir, boolean doPrimitives) { + return new TypeInference(ir, doPrimitives); + } + + /** + * The governing SSA form + */ + final protected IR ir; + + /** + * The governing class hierarchy + */ + final protected IClassHierarchy cha; + + final protected Language language; + + /** + * 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; + + private boolean solved = false; + + protected TypeInference(IR ir, boolean doPrimitives) { + if (ir == null) { + throw new IllegalArgumentException("ir is null"); + } + this.language = ir.getMethod().getDeclaringClass().getClassLoader().getLanguage(); + this.cha = ir.getMethod().getDeclaringClass().getClassHierarchy(); + this.ir = ir; + this.doPrimitives = doPrimitives; + this.BOTTOM = new ConeType(cha.getRootClass()); + initialize(); + solve(); + } + + public boolean solve() { + return solve(null); + } + + @Override + public boolean solve(IProgressMonitor monitor) { + try { + if (solved) { + return false; + } else { + boolean result = super.solve(null); + solved = true; + return result; + } + } catch (CancelException e) { + throw new CancelRuntimeException(e); + } + } + + protected void initialize() { + init(ir, this.new TypeVarFactory(), this.new TypeOperatorFactory()); + } + + @Override + protected void initializeVariables() { + + if (DEBUG) { + System.err.println("initializeVariables " + ir.getMethod()); + } + + int[] parameterValueNumbers = ir.getParameterValueNumbers(); + for (int i = 0; i < parameterValueNumbers.length; i++) { + TypeVariable v = getVariable(parameterValueNumbers[i]); + TypeReference t = ir.getParameterType(i); + + if (DEBUG) { + System.err.println("parameter " + parameterValueNumbers[i] + " " + t); + } + + if (t.isReferenceType()) { + IClass klass = cha.lookupClass(t); + if (DEBUG) { + System.err.println("klass " + klass); + } + if (klass != null) { + v.setType(new ConeType(klass)); + } else { + // give up .. default to java.lang.Object (BOTTOM) + v.setType(BOTTOM); + } + } else if (doPrimitives) { + v.setType(language.getPrimitive(t)); + } + } + + SymbolTable st = ir.getSymbolTable(); + if (st != null) { + for (int i = 0; i <= st.getMaxValueNumber(); i++) { + if (st.isConstant(i)) { + TypeVariable v = getVariable(i); + v.setType(getConstantType(i)); + } + } + } + + for (Iterator it = ir.iterateNormalInstructions(); it.hasNext();) { + SSAInstruction s = it.next(); + if (s instanceof SSAAbstractInvokeInstruction) { + SSAAbstractInvokeInstruction call = (SSAAbstractInvokeInstruction) s; + TypeVariable v = getVariable(call.getException()); + Collection defaultExceptions = call.getExceptionTypes(); + if (defaultExceptions.size() == 0) { + continue; + } + + Iterator types = defaultExceptions.iterator(); + TypeReference t = types.next(); + IClass klass = cha.lookupClass(t); + if (klass == null) { + v.setType(BOTTOM); + } else { + v.setType(new PointType(klass)); + } + + while(types.hasNext()) { + t = types.next(); + klass = cha.lookupClass(t); + if (klass != null) { + v.setType(v.getType().meet(new PointType(klass))); + } + } + + IMethod m = cha.resolveMethod(call.getDeclaredTarget()); + if (m != null) { + TypeReference[] x = null; + try { + x = m.getDeclaredExceptions(); + } catch (InvalidClassFileException e) { + e.printStackTrace(); + Assertions.UNREACHABLE(); + } catch (UnsupportedOperationException e) { + x = new TypeReference[]{ language.getThrowableType() }; + } + 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))); + } + } + } + } + } + } + } + + @Override + protected void initializeWorkList() { + addAllStatementsToWorkList(); + } + + /** + * An operator which initializes a type to a declared type. + */ + protected static final class DeclaredTypeOperator extends NullaryOperator { + private final TypeAbstraction type; + + public DeclaredTypeOperator(TypeAbstraction type) { + assert type != null; + this.type = type; + } + + /** + * Note that we need evaluate this operator at most once + */ + @Override + public byte evaluate(TypeVariable lhs) { + if (lhs.type.equals(type)) { + return NOT_CHANGED_AND_FIXED; + } else { + lhs.setType(type); + return CHANGED_AND_FIXED; + } + } + + /** + * @see java.lang.Object#toString() + */ + @Override + public String toString() { + return "delared type := " + type; + } + + public boolean isNullary() { + return true; + } + + @Override + public int hashCode() { + return 9931 * type.hashCode(); + } + + @Override + public boolean equals(Object o) { + if (o instanceof DeclaredTypeOperator) { + DeclaredTypeOperator d = (DeclaredTypeOperator) o; + return type.equals(d.type); + } else { + return false; + } + } + } + + private static final class PhiOperator extends AbstractOperator { + + private PhiOperator() { + } + + /** + * TODO: work on efficiency shortcuts for this. + */ + @Override + public byte evaluate(TypeVariable lhs, TypeVariable[] rhs) { + + if (DEBUG) { + System.err.print("PhiOperator.meet " + lhs + " "); + for (IVariable v : rhs) { + System.err.print(v + " "); + } + System.err.println(); + } + + TypeAbstraction lhsType = lhs.getType(); + TypeAbstraction meet = TypeAbstraction.TOP; + for (int i = 0; i < rhs.length; i++) { + if (rhs[i] != null && ((TypeVariable)rhs[i]).getType() != null) { + TypeVariable r = (TypeVariable) rhs[i]; + meet = meet.meet(r.getType()); + } + } + if (lhsType.equals(meet)) { + return NOT_CHANGED; + } else { + lhs.setType(meet); + return CHANGED; + } + } + + @Override + public String toString() { + return "phi meet"; + } + + @Override + public int hashCode() { + return 9929; + } + + @Override + public boolean equals(Object o) { + return (o instanceof PhiOperator); + } + } + + private static final class PiOperator extends AbstractOperator { + + private PiOperator() { + } + + /** + * TODO: work on efficiency shortcuts for this. + */ + @Override + public byte evaluate(TypeVariable lhs, TypeVariable[] rhsOperands) { + 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; + } + } + + @Override + public String toString() { + return "pi"; + } + + @Override + public int hashCode() { + return 9929 * 13; + } + + @Override + public boolean equals(Object o) { + return (o instanceof PiOperator); + } + } + + protected static class PrimitivePropagateOperator extends AbstractOperator { + + protected PrimitivePropagateOperator() { + } + + @Override + public byte evaluate(TypeVariable lhs, TypeVariable[] rhs) { + TypeAbstraction lhsType = lhs.getType(); + TypeAbstraction meet = TypeAbstraction.TOP; + for (int i = 0; i < rhs.length; i++) { + if (rhs[i] != null && ((TypeVariable)rhs[i]).getType() != null) { + TypeVariable r = (TypeVariable) rhs[i]; + meet = meet.meet(r.getType()); + } + } + if (lhsType.equals(meet)) { + return NOT_CHANGED; + } else { + lhs.setType(meet); + return CHANGED; + } + } + + @Override + public String toString() { + return "propagate"; + } + + @Override + public int hashCode() { + return 99292; + } + + @Override + public boolean equals(Object o) { + return o != null && o.getClass().equals(getClass()); + } + } + + /** + * 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; + } + + @Override + public byte evaluate(TypeVariable lhs, TypeVariable[] rhs) { + TypeAbstraction arrayType = getType(load.getArrayRef()); + if (arrayType == null || 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 && lhs.getType() == TypeAbstraction.TOP) { + lhs.setType(PrimitiveType.getPrimitive(elementType)); + return CHANGED; + } + return NOT_CHANGED; + } + + if (lhs.getType() != TypeAbstraction.TOP) { + TypeReference tType = null; + if (lhs.getType() instanceof PointType) { + tType = ((PointType) lhs.getType()).getType().getReference(); + } else if (lhs.getType() instanceof ConeType) { + tType = ((ConeType) lhs.getType()).getType().getReference(); + } else { + Assertions.UNREACHABLE("Unexpected type " + lhs.getType().getClass()); + } + if (tType.equals(elementType)) { + return NOT_CHANGED; + } else { + IClass klass = cha.lookupClass(elementType); + assert klass != null; + lhs.setType(new ConeType(klass)); + return CHANGED; + } + } else { + IClass klass = cha.lookupClass(elementType); + if (klass != null) { + lhs.setType(new ConeType(klass)); + } else { + lhs.setType(TypeAbstraction.TOP); + } + + return CHANGED; + } + } + + @Override + public String toString() { + return "getElementType " + load; + } + + @Override + public int hashCode() { + return 9923 * load.hashCode(); + } + + @Override + 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 IVisitorWithAddresses, OperatorFactory { + + protected AbstractOperator result = null; + + public AbstractOperator get(SSAInstruction instruction) { + instruction.visit(this); + AbstractOperator temp = result; + result = null; + return temp; + } + + @Override + public void visitArrayLoad(SSAArrayLoadInstruction instruction) { + result = new GetElementType(instruction); + } + + @Override + public void visitArrayLength(SSAArrayLengthInstruction instruction) { + if (!doPrimitives) { + result = null; + } else { + result = new DeclaredTypeOperator(language.getPrimitive(language.getConstantType(new Integer(1)))); + } + } + + @Override + public void visitLoadMetadata(SSALoadMetadataInstruction instruction) { + IClass jlClassKlass = cha.lookupClass(language.getMetadataType()); + assert jlClassKlass != null; + result = new DeclaredTypeOperator(new ConeType(jlClassKlass)); + } + + @Override + public void visitGet(SSAGetInstruction instruction) { + TypeReference type = instruction.getDeclaredFieldType(); + + if (doPrimitives && type.isPrimitiveType()) { + PrimitiveType p = language.getPrimitive(type); + assert p != null : "no type for " + type; + result = new DeclaredTypeOperator(p); + } 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)); + } + } + } + + @Override + 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)); + } + } else if (doPrimitives && type.isPrimitiveType()) { + result = new DeclaredTypeOperator(language.getPrimitive(type)); + } else { + result = null; + } + } + + @Override + 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)); + } + } + + @Override + public void visitCheckCast(SSACheckCastInstruction instruction) { + TypeAbstraction typeAbs = null; + for (TypeReference type : instruction.getDeclaredResultTypes()) { + IClass klass = cha.lookupClass(type); + if (klass == null) { + // a type that cannot be loaded. + // be pessimistic + typeAbs = BOTTOM; + } else { + TypeAbstraction x = null; + if (doPrimitives && type.isPrimitiveType()) { + x = language.getPrimitive(type); + } else if (type.isReferenceType()) { + x = new ConeType(klass); + } + if (x != null) { + if (typeAbs == null) { + typeAbs = x; + } else { + typeAbs = typeAbs.meet(x); + } + } + } + } + + result = new DeclaredTypeOperator(typeAbs); + } + + @Override + public void visitConversion(SSAConversionInstruction instruction) { + if (doPrimitives) { + result = new DeclaredTypeOperator(language.getPrimitive(instruction.getToType())); + } + } + + @Override + public void visitComparison(SSAComparisonInstruction instruction) { + if (doPrimitives) { + result = new DeclaredTypeOperator(language.getPrimitive(language.getConstantType(new Integer(0)))); + } + } + + @Override + public void visitBinaryOp(SSABinaryOpInstruction instruction) { + if (doPrimitives) { + result = primitivePropagateOp; + } + } + + @Override + public void visitUnaryOp(SSAUnaryOpInstruction instruction) { + if (doPrimitives) { + result = primitivePropagateOp; + } + } + + @Override + public void visitInstanceof(SSAInstanceofInstruction instruction) { + if (doPrimitives) { + result = new DeclaredTypeOperator(language.getPrimitive(language.getConstantType(Boolean.TRUE))); + } + } + + @Override + public void visitGetCaughtException(SSAGetCaughtExceptionInstruction instruction) { + TypeAbstraction type = meetDeclaredExceptionTypes(instruction); + result = new DeclaredTypeOperator(type); + } + + @Override + public void visitPhi(SSAPhiInstruction instruction) { + result = phiOp; + } + + @Override + public void visitPi(SSAPiInstruction instruction) { + result = piOp; + } + + private TypeAbstraction meetDeclaredExceptionTypes(SSAGetCaughtExceptionInstruction s) { + 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); + } + while (it.hasNext()) { + t = (TypeReference) it.next(); + IClass tClass = cha.lookupClass(t); + if (tClass == null) { + result = BOTTOM; + } else { + result = result.meet(new ConeType(tClass)); + } + } + return result; + } + + private DeclaredTypeOperator getPointerTypeOperator(TypeReference type) { + if (type.isPrimitiveType()) { + return new DeclaredTypeOperator(language.getPrimitive(type)); + } else { + IClass klass = cha.lookupClass(type); + if (klass == null) { + // a type that cannot be loaded. + // be pessimistic + return new DeclaredTypeOperator(BOTTOM); + } else { + return new DeclaredTypeOperator(new ConeType(klass)); + } + } + } + + public void visitAddressOf(SSAAddressOfInstruction instruction) { + TypeReference type = language.getPointerType(instruction.getType()); + result = getPointerTypeOperator(type); + } + + public void visitLoadIndirect(SSALoadIndirectInstruction instruction) { + result = getPointerTypeOperator(instruction.getLoadedType()); + } + + public void visitStoreIndirect(SSAStoreIndirectInstruction instruction) { + Assertions.UNREACHABLE(); + } + } + + 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(language.getPrimitive(language.getConstantType(Boolean.TRUE))); + } + } + } + + return new TypeVariable(TypeAbstraction.TOP); + } + + } + + public IR getIR() { + return ir; + } + + /** + * Return the type computed for a particular value number + */ + public TypeAbstraction getType(int valueNumber) { + if (valueNumber < 0) { + throw new IllegalArgumentException("bad value number " + valueNumber); + } + assert getVariable(valueNumber) != null : "null variable for value number " + valueNumber; + return getVariable(valueNumber).getType(); + } + + public TypeAbstraction getConstantType(int valueNumber) { + if (ir.getSymbolTable().isStringConstant(valueNumber)) { + return new PointType(cha.lookupClass(language.getStringType())); + } else { + return getConstantPrimitiveType(valueNumber); + } + } + + public TypeAbstraction getConstantPrimitiveType(int valueNumber) { + SymbolTable st = ir.getSymbolTable(); + if (!st.isConstant(valueNumber) || st.isNullConstant(valueNumber)) { + return TypeAbstraction.TOP; + } else { + return language.getPrimitive(language.getConstantType(st.getConstantValue(valueNumber))); + } + } + + 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 = getVariable(valueNumber).getType(); + return ta == BOTTOM || ta.getType() == null; + } + + /** + * Extract all results of the type inference analysis. + * + * @return an array, where the i'th variable holds the type abstraction of the i'th value number. + */ + public TypeAbstraction[] extractAllResults() { + int numberOfVars = ir.getSymbolTable().getMaxValueNumber() + 1; + TypeAbstraction[] ret = new TypeAbstraction[numberOfVars]; + + for (int i = 0; i < numberOfVars; ++i) { + TypeVariable var = getVariable(i); + ret[i] = var == null ? null : var.getType(); + } + + return ret; + } + + @Override + protected TypeVariable[] makeStmtRHS(int size) { + return new TypeVariable[size]; + } +} diff --git a/com.ibm.wala.core/src/com/ibm/wala/analysis/typeInference/TypeVariable.java b/com.ibm.wala.core/src/com/ibm/wala/analysis/typeInference/TypeVariable.java index 64095f1fc..2a32b021c 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/analysis/typeInference/TypeVariable.java +++ b/com.ibm.wala.core/src/com/ibm/wala/analysis/typeInference/TypeVariable.java @@ -1,50 +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.analysis.typeInference; - -import com.ibm.wala.fixpoint.AbstractVariable; - -/** - * A type variable in the dataflow system for type inference. - * - * @see TypeInference - */ -public class TypeVariable extends AbstractVariable { - - TypeAbstraction type; - - public TypeVariable(TypeAbstraction type) { - if (type == null) { - throw new IllegalArgumentException("null type"); - } - this.type = type; - } - - public void copyState(TypeVariable other) throws IllegalArgumentException { - if (other == null) { - throw new IllegalArgumentException("v == null"); - } - this.type = other.type; - } - - public TypeAbstraction getType() { - return type; - } - - public void setType(TypeAbstraction type) { - this.type = type; - } - - @Override - public String toString() { - return type.toString(); - } +/******************************************************************************* + * 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.fixpoint.AbstractVariable; + +/** + * A type variable in the dataflow system for type inference. + * + * @see TypeInference + */ +public class TypeVariable extends AbstractVariable { + + TypeAbstraction type; + + public TypeVariable(TypeAbstraction type) { + if (type == null) { + throw new IllegalArgumentException("null type"); + } + this.type = type; + } + + public void copyState(TypeVariable other) throws IllegalArgumentException { + if (other == null) { + throw new IllegalArgumentException("v == null"); + } + this.type = other.type; + } + + public TypeAbstraction getType() { + return type; + } + + public void setType(TypeAbstraction type) { + this.type = type; + } + + @Override + public String toString() { + return type.toString(); + } } \ No newline at end of file diff --git a/com.ibm.wala.core/src/com/ibm/wala/cfg/AbstractCFG.java b/com.ibm.wala.core/src/com/ibm/wala/cfg/AbstractCFG.java index c6f25096a..1c91efa72 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/cfg/AbstractCFG.java +++ b/com.ibm.wala.core/src/com/ibm/wala/cfg/AbstractCFG.java @@ -1,667 +1,667 @@ -/******************************************************************************* - * 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.ArrayList; -import java.util.Collection; -import java.util.HashSet; -import java.util.Iterator; -import java.util.List; - -import com.ibm.wala.classLoader.IMethod; -import com.ibm.wala.shrikeBT.Constants; -import com.ibm.wala.util.Predicate; -import com.ibm.wala.util.collections.CompoundIterator; -import com.ibm.wala.util.collections.EmptyIterator; -import com.ibm.wala.util.collections.HashSetFactory; -import com.ibm.wala.util.collections.Iterator2Collection; -import com.ibm.wala.util.collections.IteratorPlusOne; -import com.ibm.wala.util.collections.IteratorPlusTwo; -import com.ibm.wala.util.collections.NonNullSingletonIterator; -import com.ibm.wala.util.collections.SimpleVector; -import com.ibm.wala.util.debug.Assertions; -import com.ibm.wala.util.debug.UnimplementedError; -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.BasicNaturalRelation; -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; -import com.ibm.wala.util.intset.SimpleIntVector; - -/** - * Common functionality for {@link ControlFlowGraph} implementations. - */ -public abstract class AbstractCFG> implements ControlFlowGraph, Constants { - - /** - * The method this AbstractCFG represents - */ - private final IMethod method; - - /** - * An object to track nodes in this cfg - */ - final private DelegatingNumberedNodeManager nodeManager = new DelegatingNumberedNodeManager(); - - /** - * An object to track most normal edges in this cfg - */ - final private SparseNumberedEdgeManager normalEdgeManager = new SparseNumberedEdgeManager(nodeManager, 2, - BasicNaturalRelation.SIMPLE); - - /** - * An object to track not-to-exit exceptional edges in this cfg - */ - final private SparseNumberedEdgeManager exceptionalEdgeManager = new SparseNumberedEdgeManager(nodeManager, 0, - BasicNaturalRelation.SIMPLE); - - /** - * An object to track not-to-exit exceptional edges in this cfg, indexed by block number. exceptionalEdges[i] is a list of block - * numbers that are non-exit exceptional successors of block i, in order of increasing "catch scope". - */ - final private SimpleVector exceptionalSuccessors = new SimpleVector(); - - /** - * 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? - */ - final private BitVector catchBlocks; - - /** - * Cache here for efficiency - */ - private T exit; - - 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 = getNode(getMaxNumber()); - } - - @Override - public abstract boolean equals(Object o); - - @Override - public abstract int hashCode(); - - /** - * Return the entry basic block for the CFG. - */ - public T entry() { - return getNode(0); - } - - /** - * Return the exit basic block for the CFG. - */ - public T exit() { - return exit; - } - - public int getPredNodeCount(T N) { - if (N == null) { - throw new IllegalArgumentException("N is null"); - } - 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 Iterator2Collection.toSet(getPredNodes(N)).size(); - } else { - return getNumberOfNormalIn(N); - } - } else { - return getNumberOfExceptionalIn(N); - } - } - } - - public int getNumberOfNormalIn(T N) { - if (N == null) { - throw new IllegalArgumentException("N is null"); - } - 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(T N) { - if (N == null) { - throw new IllegalArgumentException("N is null"); - } - 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(T N) { - return getNumberOfNormalOut(getNumber(N)); - } - - public int getNumberOfExceptionalOut(final T N) { - return getNumberOfExceptionalOut(getNumber(N)); - } - - public Iterator getPredNodes(T N) { - if (N == null) { - throw new IllegalArgumentException("N is null"); - } - if (N.equals(exit())) { - return Predicate.filter(iterator(), new Predicate() { - @Override - public boolean test(T o) { - int i = getNumber(o); - return normalToExit.get(i) || exceptionalToExit.get(i); - } - }).iterator(); - } else { - int number = getNumber(N); - boolean normalIn = getNumberOfNormalIn(N) > 0; - boolean exceptionalIn = getNumberOfExceptionalIn(N) > 0; - if (normalIn) { - if (exceptionalIn) { - HashSet result = HashSetFactory.make(getNumberOfNormalIn(N) + getNumberOfExceptionalIn(N)); - result.addAll(Iterator2Collection.toSet(normalEdgeManager.getPredNodes(N))); - result.addAll(Iterator2Collection.toSet(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 IteratorPlusOne.make(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(T N) { - if (N == null) { - throw new IllegalArgumentException("N is null"); - } - 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(T N) { - return Iterator2Collection.toSet(getSuccNodes(N)).size(); - } - - public Iterator getSuccNodes(T N) { - int number = getNumber(N); - if (normalToExit.get(number) && exceptionalToExit.get(number)) { - return new CompoundIterator(iterateNormalSuccessorsWithoutExit(number), iterateExceptionalSuccessors(number)); - } else { - return new CompoundIterator(iterateNormalSuccessors(number), iterateExceptionalSuccessors(number)); - } - } - - /** - * @param number of a basic block - * @return the exceptional successors of the basic block, in order of increasing catch scope. - */ - private Iterator iterateExceptionalSuccessors(int number) { - if (exceptionalEdgeManager.hasAnySuccessor(number)) { - List result = new ArrayList(); - SimpleIntVector v = exceptionalSuccessors.get(number); - for (int i = 0; i <= v.getMaxIndex(); i++) { - result.add(getNode(v.get(i))); - } - if (exceptionalToExit.get(number)) { - result.add(exit); - } - return result.iterator(); - } else { - if (exceptionalToExit.get(number)) { - return new NonNullSingletonIterator(exit()); - } else { - return EmptyIterator.instance(); - } - } - } - - Iterator iterateExceptionalPredecessors(T N) { - if (N.equals(exit())) { - return Predicate.filter(iterator(), new Predicate() { - @Override - public boolean test(T o) { - int i = getNumber(o); - return exceptionalToExit.get(i); - } - }).iterator(); - } else { - return exceptionalEdgeManager.getPredNodes(N); - } - } - - Iterator iterateNormalPredecessors(T N) { - if (N.equals(exit())) { - return Predicate.filter(iterator(), new Predicate() { - @Override - public boolean test(T o) { - int i = getNumber(o); - return normalToExit.get(i); - } - }).iterator(); - } else { - int number = getNumber(N); - if (number > 0 && fallThru.get(number - 1)) { - return IteratorPlusOne.make(normalEdgeManager.getPredNodes(N), getNode(number - 1)); - } else { - return normalEdgeManager.getPredNodes(N); - } - } - } - - private Iterator iterateNormalSuccessors(int number) { - if (fallThru.get(number)) { - if (normalToExit.get(number)) { - return new IteratorPlusTwo(normalEdgeManager.getSuccNodes(number), getNode(number + 1), exit()); - } else { - return IteratorPlusOne.make(normalEdgeManager.getSuccNodes(number), getNode(number + 1)); - } - } else { - if (normalToExit.get(number)) { - return IteratorPlusOne.make(normalEdgeManager.getSuccNodes(number), exit()); - } else { - return normalEdgeManager.getSuccNodes(number); - } - } - } - - private Iterator iterateNormalSuccessorsWithoutExit(int number) { - if (fallThru.get(number)) { - return IteratorPlusOne.make(normalEdgeManager.getSuccNodes(number), getNode(number + 1)); - } else { - return normalEdgeManager.getSuccNodes(number); - } - } - - /** - * @param n - */ - public void addNode(T n) { - nodeManager.addNode(n); - } - - public int getMaxNumber() { - return nodeManager.getMaxNumber(); - } - - public T getNode(int number) { - return nodeManager.getNode(number); - } - - public int getNumber(T N) { - return nodeManager.getNumber(N); - } - - public int getNumberOfNodes() { - return nodeManager.getNumberOfNodes(); - } - - public Iterator iterator() { - return nodeManager.iterator(); - } - - public void addEdge(T src, T dst) throws UnimplementedError { - Assertions.UNREACHABLE("Don't call me .. use addNormalEdge or addExceptionalEdge"); - } - - public void removeEdge(T src, T dst) throws UnsupportedOperationException { - throw new UnsupportedOperationException(); - } - - public boolean hasEdge(T src, T dst) { - if (dst == null) { - throw new IllegalArgumentException("dst is null"); - } - 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(T src, T dst) { - if (dst == null) { - throw new IllegalArgumentException("dst is null"); - } - int x = getNumber(src); - if (dst.equals(exit())) { - return exceptionalToExit.get(x); - } - return exceptionalEdgeManager.hasEdge(src, dst); - } - - public boolean hasNormalEdge(T src, T dst) { - if (dst == null) { - throw new IllegalArgumentException("dst is null"); - } - 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); - } - - /** - * @throws IllegalArgumentException if src or dst is null - */ - public void addNormalEdge(T src, T dst) { - if (src == null) { - throw new IllegalArgumentException("src is null"); - } - if (dst == null) { - throw new IllegalArgumentException("dst is null"); - } - if (dst.equals(exit())) { - normalToExit.set(getNumber(src)); - } else if (getNumber(dst) == (getNumber(src) + 1)) { - fallThru.set(getNumber(src)); - } else { - normalEdgeManager.addEdge(src, dst); - } - } - - /** - * @throws IllegalArgumentException if dst is null - */ - public void addExceptionalEdge(T src, T dst) { - if (dst == null) { - throw new IllegalArgumentException("dst is null"); - } - if (dst.equals(exit())) { - exceptionalToExit.set(getNumber(src)); - } else { - exceptionalEdgeManager.addEdge(src, dst); - SimpleIntVector v = exceptionalSuccessors.get(getNumber(src)); - if (v == null) { - v = new SimpleIntVector(-1); - exceptionalSuccessors.set(getNumber(src), v); - v.set(0, getNumber(dst)); - return; - } - if (v.get(v.getMaxIndex()) != getNumber(dst)) { - v.set(v.getMaxIndex() + 1, getNumber(dst)); - } - } - } - - /* - * @see com.ibm.wala.util.graph.Graph#removeNode(com.ibm.wala.util.graph.Node) - */ - public void removeNodeAndEdges(T N) throws UnimplementedError { - Assertions.UNREACHABLE(); - } - - /* - * @see com.ibm.wala.util.graph.NodeManager#remove(com.ibm.wala.util.graph.Node) - */ - public void removeNode(T n) throws UnimplementedError { - Assertions.UNREACHABLE(); - } - - /* - * @see com.ibm.wala.util.graph.NodeManager#containsNode(com.ibm.wala.util.graph.Node) - */ - public boolean containsNode(T N) { - return nodeManager.containsNode(N); - } - - @Override - public String toString() { - StringBuffer s = new StringBuffer(""); - for (Iterator it = iterator(); it.hasNext();) { - T bb = it.next(); - s.append("BB").append(getNumber(bb)).append("\n"); - - Iterator 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 - */ - protected void setCatchBlock(int i) { - catchBlocks.set(i); - } - - /** - * @return true iff block i is a catch block - */ - public boolean isCatchBlock(int i) { - return catchBlocks.get(i); - } - - /** - * Returns the catchBlocks. - */ - public BitVector getCatchBlocks() { - return catchBlocks; - } - - public IMethod getMethod() { - return method; - } - - /* - * @see com.ibm.wala.util.graph.EdgeManager#removeEdges(java.lang.Object) - */ - public void removeAllIncidentEdges(T node) throws UnimplementedError { - Assertions.UNREACHABLE(); - } - - /* - * @see com.ibm.wala.cfg.ControlFlowGraph#getExceptionalSuccessors(com.ibm.wala.cfg.T) - */ - public List getExceptionalSuccessors(T b) { - if (b == null) { - throw new IllegalArgumentException("b is null"); - } - List result = new ArrayList(); - for (Iterator it = iterateExceptionalSuccessors(b.getNumber()); it.hasNext();) { - result.add(it.next()); - } - return result; - } - - /* - * @see com.ibm.wala.cfg.ControlFlowGraph#getNormalSuccessors(com.ibm.wala.cfg.T) - */ - public Collection getNormalSuccessors(T b) { - if (b == null) { - throw new IllegalArgumentException("b is null"); - } - return Iterator2Collection.toSet(iterateNormalSuccessors(b.getNumber())); - } - - /* - * @see com.ibm.wala.util.graph.NumberedNodeManager#iterateNodes(com.ibm.wala.util.intset.IntSet) - */ - public Iterator iterateNodes(IntSet s) { - return new NumberedNodeIterator(s, this); - } - - public void removeIncomingEdges(T node) throws UnimplementedError { - Assertions.UNREACHABLE(); - } - - public void removeOutgoingEdges(T node) throws UnimplementedError { - Assertions.UNREACHABLE(); - } - - public FixedSizeBitVector getExceptionalToExit() { - return exceptionalToExit; - } - - public FixedSizeBitVector getNormalToExit() { - return normalToExit; - } - - /* - * @see com.ibm.wala.cfg.ControlFlowGraph#getExceptionalPredecessors(com.ibm.wala.cfg.T) - */ - public Collection getExceptionalPredecessors(T b) { - if (b == null) { - throw new IllegalArgumentException("b is null"); - } - return Iterator2Collection.toSet(iterateExceptionalPredecessors(b)); - } - - /* - * @see com.ibm.wala.cfg.ControlFlowGraph#getNormalPredecessors(com.ibm.wala.cfg.T) - */ - public Collection getNormalPredecessors(T b) { - if (b == null) { - throw new IllegalArgumentException("b is null"); - } - return Iterator2Collection.toSet(iterateNormalPredecessors(b)); - } - - public IntSet getPredNodeNumbers(T node) throws UnimplementedError { - Assertions.UNREACHABLE(); - return null; - } - - /* - * TODO: optimize this. - */ - public IntSet getSuccNodeNumbers(T node) { - int number = getNumber(node); - IntSet s = normalEdgeManager.getSuccNodeNumbers(node); - MutableSparseIntSet result = s == null ? MutableSparseIntSet.makeEmpty() : MutableSparseIntSet.make(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; - } - -} +/******************************************************************************* + * 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.ArrayList; +import java.util.Collection; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; + +import com.ibm.wala.classLoader.IMethod; +import com.ibm.wala.shrikeBT.Constants; +import com.ibm.wala.util.Predicate; +import com.ibm.wala.util.collections.CompoundIterator; +import com.ibm.wala.util.collections.EmptyIterator; +import com.ibm.wala.util.collections.HashSetFactory; +import com.ibm.wala.util.collections.Iterator2Collection; +import com.ibm.wala.util.collections.IteratorPlusOne; +import com.ibm.wala.util.collections.IteratorPlusTwo; +import com.ibm.wala.util.collections.NonNullSingletonIterator; +import com.ibm.wala.util.collections.SimpleVector; +import com.ibm.wala.util.debug.Assertions; +import com.ibm.wala.util.debug.UnimplementedError; +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.BasicNaturalRelation; +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; +import com.ibm.wala.util.intset.SimpleIntVector; + +/** + * Common functionality for {@link ControlFlowGraph} implementations. + */ +public abstract class AbstractCFG> implements ControlFlowGraph, Constants { + + /** + * The method this AbstractCFG represents + */ + private final IMethod method; + + /** + * An object to track nodes in this cfg + */ + final private DelegatingNumberedNodeManager nodeManager = new DelegatingNumberedNodeManager(); + + /** + * An object to track most normal edges in this cfg + */ + final private SparseNumberedEdgeManager normalEdgeManager = new SparseNumberedEdgeManager(nodeManager, 2, + BasicNaturalRelation.SIMPLE); + + /** + * An object to track not-to-exit exceptional edges in this cfg + */ + final private SparseNumberedEdgeManager exceptionalEdgeManager = new SparseNumberedEdgeManager(nodeManager, 0, + BasicNaturalRelation.SIMPLE); + + /** + * An object to track not-to-exit exceptional edges in this cfg, indexed by block number. exceptionalEdges[i] is a list of block + * numbers that are non-exit exceptional successors of block i, in order of increasing "catch scope". + */ + final private SimpleVector exceptionalSuccessors = new SimpleVector(); + + /** + * 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? + */ + final private BitVector catchBlocks; + + /** + * Cache here for efficiency + */ + private T exit; + + 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 = getNode(getMaxNumber()); + } + + @Override + public abstract boolean equals(Object o); + + @Override + public abstract int hashCode(); + + /** + * Return the entry basic block for the CFG. + */ + public T entry() { + return getNode(0); + } + + /** + * Return the exit basic block for the CFG. + */ + public T exit() { + return exit; + } + + public int getPredNodeCount(T N) { + if (N == null) { + throw new IllegalArgumentException("N is null"); + } + 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 Iterator2Collection.toSet(getPredNodes(N)).size(); + } else { + return getNumberOfNormalIn(N); + } + } else { + return getNumberOfExceptionalIn(N); + } + } + } + + public int getNumberOfNormalIn(T N) { + if (N == null) { + throw new IllegalArgumentException("N is null"); + } + 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(T N) { + if (N == null) { + throw new IllegalArgumentException("N is null"); + } + 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(T N) { + return getNumberOfNormalOut(getNumber(N)); + } + + public int getNumberOfExceptionalOut(final T N) { + return getNumberOfExceptionalOut(getNumber(N)); + } + + public Iterator getPredNodes(T N) { + if (N == null) { + throw new IllegalArgumentException("N is null"); + } + if (N.equals(exit())) { + return Predicate.filter(iterator(), new Predicate() { + @Override + public boolean test(T o) { + int i = getNumber(o); + return normalToExit.get(i) || exceptionalToExit.get(i); + } + }).iterator(); + } else { + int number = getNumber(N); + boolean normalIn = getNumberOfNormalIn(N) > 0; + boolean exceptionalIn = getNumberOfExceptionalIn(N) > 0; + if (normalIn) { + if (exceptionalIn) { + HashSet result = HashSetFactory.make(getNumberOfNormalIn(N) + getNumberOfExceptionalIn(N)); + result.addAll(Iterator2Collection.toSet(normalEdgeManager.getPredNodes(N))); + result.addAll(Iterator2Collection.toSet(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 IteratorPlusOne.make(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(T N) { + if (N == null) { + throw new IllegalArgumentException("N is null"); + } + 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(T N) { + return Iterator2Collection.toSet(getSuccNodes(N)).size(); + } + + public Iterator getSuccNodes(T N) { + int number = getNumber(N); + if (normalToExit.get(number) && exceptionalToExit.get(number)) { + return new CompoundIterator(iterateNormalSuccessorsWithoutExit(number), iterateExceptionalSuccessors(number)); + } else { + return new CompoundIterator(iterateNormalSuccessors(number), iterateExceptionalSuccessors(number)); + } + } + + /** + * @param number of a basic block + * @return the exceptional successors of the basic block, in order of increasing catch scope. + */ + private Iterator iterateExceptionalSuccessors(int number) { + if (exceptionalEdgeManager.hasAnySuccessor(number)) { + List result = new ArrayList(); + SimpleIntVector v = exceptionalSuccessors.get(number); + for (int i = 0; i <= v.getMaxIndex(); i++) { + result.add(getNode(v.get(i))); + } + if (exceptionalToExit.get(number)) { + result.add(exit); + } + return result.iterator(); + } else { + if (exceptionalToExit.get(number)) { + return new NonNullSingletonIterator(exit()); + } else { + return EmptyIterator.instance(); + } + } + } + + Iterator iterateExceptionalPredecessors(T N) { + if (N.equals(exit())) { + return Predicate.filter(iterator(), new Predicate() { + @Override + public boolean test(T o) { + int i = getNumber(o); + return exceptionalToExit.get(i); + } + }).iterator(); + } else { + return exceptionalEdgeManager.getPredNodes(N); + } + } + + Iterator iterateNormalPredecessors(T N) { + if (N.equals(exit())) { + return Predicate.filter(iterator(), new Predicate() { + @Override + public boolean test(T o) { + int i = getNumber(o); + return normalToExit.get(i); + } + }).iterator(); + } else { + int number = getNumber(N); + if (number > 0 && fallThru.get(number - 1)) { + return IteratorPlusOne.make(normalEdgeManager.getPredNodes(N), getNode(number - 1)); + } else { + return normalEdgeManager.getPredNodes(N); + } + } + } + + private Iterator iterateNormalSuccessors(int number) { + if (fallThru.get(number)) { + if (normalToExit.get(number)) { + return new IteratorPlusTwo(normalEdgeManager.getSuccNodes(number), getNode(number + 1), exit()); + } else { + return IteratorPlusOne.make(normalEdgeManager.getSuccNodes(number), getNode(number + 1)); + } + } else { + if (normalToExit.get(number)) { + return IteratorPlusOne.make(normalEdgeManager.getSuccNodes(number), exit()); + } else { + return normalEdgeManager.getSuccNodes(number); + } + } + } + + private Iterator iterateNormalSuccessorsWithoutExit(int number) { + if (fallThru.get(number)) { + return IteratorPlusOne.make(normalEdgeManager.getSuccNodes(number), getNode(number + 1)); + } else { + return normalEdgeManager.getSuccNodes(number); + } + } + + /** + * @param n + */ + public void addNode(T n) { + nodeManager.addNode(n); + } + + public int getMaxNumber() { + return nodeManager.getMaxNumber(); + } + + public T getNode(int number) { + return nodeManager.getNode(number); + } + + public int getNumber(T N) { + return nodeManager.getNumber(N); + } + + public int getNumberOfNodes() { + return nodeManager.getNumberOfNodes(); + } + + public Iterator iterator() { + return nodeManager.iterator(); + } + + public void addEdge(T src, T dst) throws UnimplementedError { + Assertions.UNREACHABLE("Don't call me .. use addNormalEdge or addExceptionalEdge"); + } + + public void removeEdge(T src, T dst) throws UnsupportedOperationException { + throw new UnsupportedOperationException(); + } + + public boolean hasEdge(T src, T dst) { + if (dst == null) { + throw new IllegalArgumentException("dst is null"); + } + 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(T src, T dst) { + if (dst == null) { + throw new IllegalArgumentException("dst is null"); + } + int x = getNumber(src); + if (dst.equals(exit())) { + return exceptionalToExit.get(x); + } + return exceptionalEdgeManager.hasEdge(src, dst); + } + + public boolean hasNormalEdge(T src, T dst) { + if (dst == null) { + throw new IllegalArgumentException("dst is null"); + } + 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); + } + + /** + * @throws IllegalArgumentException if src or dst is null + */ + public void addNormalEdge(T src, T dst) { + if (src == null) { + throw new IllegalArgumentException("src is null"); + } + if (dst == null) { + throw new IllegalArgumentException("dst is null"); + } + if (dst.equals(exit())) { + normalToExit.set(getNumber(src)); + } else if (getNumber(dst) == (getNumber(src) + 1)) { + fallThru.set(getNumber(src)); + } else { + normalEdgeManager.addEdge(src, dst); + } + } + + /** + * @throws IllegalArgumentException if dst is null + */ + public void addExceptionalEdge(T src, T dst) { + if (dst == null) { + throw new IllegalArgumentException("dst is null"); + } + if (dst.equals(exit())) { + exceptionalToExit.set(getNumber(src)); + } else { + exceptionalEdgeManager.addEdge(src, dst); + SimpleIntVector v = exceptionalSuccessors.get(getNumber(src)); + if (v == null) { + v = new SimpleIntVector(-1); + exceptionalSuccessors.set(getNumber(src), v); + v.set(0, getNumber(dst)); + return; + } + if (v.get(v.getMaxIndex()) != getNumber(dst)) { + v.set(v.getMaxIndex() + 1, getNumber(dst)); + } + } + } + + /* + * @see com.ibm.wala.util.graph.Graph#removeNode(com.ibm.wala.util.graph.Node) + */ + public void removeNodeAndEdges(T N) throws UnimplementedError { + Assertions.UNREACHABLE(); + } + + /* + * @see com.ibm.wala.util.graph.NodeManager#remove(com.ibm.wala.util.graph.Node) + */ + public void removeNode(T n) throws UnimplementedError { + Assertions.UNREACHABLE(); + } + + /* + * @see com.ibm.wala.util.graph.NodeManager#containsNode(com.ibm.wala.util.graph.Node) + */ + public boolean containsNode(T N) { + return nodeManager.containsNode(N); + } + + @Override + public String toString() { + StringBuffer s = new StringBuffer(""); + for (Iterator it = iterator(); it.hasNext();) { + T bb = it.next(); + s.append("BB").append(getNumber(bb)).append("\n"); + + Iterator 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 + */ + protected void setCatchBlock(int i) { + catchBlocks.set(i); + } + + /** + * @return true iff block i is a catch block + */ + public boolean isCatchBlock(int i) { + return catchBlocks.get(i); + } + + /** + * Returns the catchBlocks. + */ + public BitVector getCatchBlocks() { + return catchBlocks; + } + + public IMethod getMethod() { + return method; + } + + /* + * @see com.ibm.wala.util.graph.EdgeManager#removeEdges(java.lang.Object) + */ + public void removeAllIncidentEdges(T node) throws UnimplementedError { + Assertions.UNREACHABLE(); + } + + /* + * @see com.ibm.wala.cfg.ControlFlowGraph#getExceptionalSuccessors(com.ibm.wala.cfg.T) + */ + public List getExceptionalSuccessors(T b) { + if (b == null) { + throw new IllegalArgumentException("b is null"); + } + List result = new ArrayList(); + for (Iterator it = iterateExceptionalSuccessors(b.getNumber()); it.hasNext();) { + result.add(it.next()); + } + return result; + } + + /* + * @see com.ibm.wala.cfg.ControlFlowGraph#getNormalSuccessors(com.ibm.wala.cfg.T) + */ + public Collection getNormalSuccessors(T b) { + if (b == null) { + throw new IllegalArgumentException("b is null"); + } + return Iterator2Collection.toSet(iterateNormalSuccessors(b.getNumber())); + } + + /* + * @see com.ibm.wala.util.graph.NumberedNodeManager#iterateNodes(com.ibm.wala.util.intset.IntSet) + */ + public Iterator iterateNodes(IntSet s) { + return new NumberedNodeIterator(s, this); + } + + public void removeIncomingEdges(T node) throws UnimplementedError { + Assertions.UNREACHABLE(); + } + + public void removeOutgoingEdges(T node) throws UnimplementedError { + Assertions.UNREACHABLE(); + } + + public FixedSizeBitVector getExceptionalToExit() { + return exceptionalToExit; + } + + public FixedSizeBitVector getNormalToExit() { + return normalToExit; + } + + /* + * @see com.ibm.wala.cfg.ControlFlowGraph#getExceptionalPredecessors(com.ibm.wala.cfg.T) + */ + public Collection getExceptionalPredecessors(T b) { + if (b == null) { + throw new IllegalArgumentException("b is null"); + } + return Iterator2Collection.toSet(iterateExceptionalPredecessors(b)); + } + + /* + * @see com.ibm.wala.cfg.ControlFlowGraph#getNormalPredecessors(com.ibm.wala.cfg.T) + */ + public Collection getNormalPredecessors(T b) { + if (b == null) { + throw new IllegalArgumentException("b is null"); + } + return Iterator2Collection.toSet(iterateNormalPredecessors(b)); + } + + public IntSet getPredNodeNumbers(T node) throws UnimplementedError { + Assertions.UNREACHABLE(); + return null; + } + + /* + * TODO: optimize this. + */ + public IntSet getSuccNodeNumbers(T node) { + int number = getNumber(node); + IntSet s = normalEdgeManager.getSuccNodeNumbers(node); + MutableSparseIntSet result = s == null ? MutableSparseIntSet.makeEmpty() : MutableSparseIntSet.make(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; + } + +} diff --git a/com.ibm.wala.core/src/com/ibm/wala/cfg/CFGSanitizer.java b/com.ibm.wala.core/src/com/ibm/wala/cfg/CFGSanitizer.java index 0227e0901..0ec338358 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/cfg/CFGSanitizer.java +++ b/com.ibm.wala.core/src/com/ibm/wala/cfg/CFGSanitizer.java @@ -1,181 +1,181 @@ -/******************************************************************************* - * 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.classLoader.Language; -import com.ibm.wala.ipa.cha.IClassHierarchy; -import com.ibm.wala.shrikeCT.InvalidClassFileException; -import com.ibm.wala.ssa.IR; -import com.ibm.wala.ssa.ISSABasicBlock; -import com.ibm.wala.ssa.SSACFG; -import com.ibm.wala.ssa.SSACFG.ExceptionHandlerBasicBlock; -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.types.TypeReference; -import com.ibm.wala.util.WalaException; -import com.ibm.wala.util.debug.Assertions; -import com.ibm.wala.util.graph.Graph; -import com.ibm.wala.util.graph.impl.SlowSparseNumberedGraph; - -/** - * Utility class to remove exceptional edges to exit() from a CFG - */ -public class CFGSanitizer { - - /** - * Return a view of the {@link ControlFlowGraph} for an {@link IR}, which elides all exceptional exits from PEIs in the IR. - */ - public static Graph sanitize(IR ir, IClassHierarchy cha) throws IllegalArgumentException, WalaException { - - if (ir == null) { - throw new IllegalArgumentException("ir cannot be null"); - } - - ControlFlowGraph cfg = ir.getControlFlowGraph(); - Graph g = SlowSparseNumberedGraph.make(); - // add all nodes to the graph - for (Iterator it = cfg.iterator(); it.hasNext();) { - g.addNode(it.next()); - } - - // add all edges to the graph, except those that go to exit - for (Iterator it = cfg.iterator(); it.hasNext();) { - ISSABasicBlock b = (ISSABasicBlock) it.next(); - for (Iterator it2 = cfg.getSuccNodes(b); it2.hasNext();) { - ISSABasicBlock b2 = (ISSABasicBlock) it2.next(); - - if (!b2.isExitBlock()) { - g.addEdge(b, b2); - } - } - } - - // now add edges to exit, ignoring undeclared exceptions - ISSABasicBlock exit = cfg.exit(); - - for (Iterator it = cfg.getPredNodes(exit); it.hasNext();) { - // for each predecessor of exit ... - ISSABasicBlock b = (ISSABasicBlock) it.next(); - - SSAInstruction s = ir.getInstructions()[b.getLastInstructionIndex()]; - if (s == null) { - // TODO: this shouldn't happen? - continue; - } - if (s instanceof SSAReturnInstruction || s instanceof SSAThrowInstruction || cfg.getSuccNodeCount(b) == 1) { - // return or athrow, or some statement which is not an athrow or return whose only successor is the exit node (can only - // occur in synthetic methods without a return statement? --MS); add edge to exit - g.addEdge(b, exit); - } else { - // compute types of exceptions the pei may throw - TypeReference[] exceptions = null; - try { - exceptions = computeExceptions(cha, ir, s); - } catch (InvalidClassFileException e1) { - e1.printStackTrace(); - Assertions.UNREACHABLE(); - } - // 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 = null; - try { - declared = ir.getMethod().getDeclaredExceptions(); - } catch (InvalidClassFileException e) { - e.printStackTrace(); - Assertions.UNREACHABLE(); - } - 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; - } - - /** - * What are the exception types which s may throw? - */ - private static TypeReference[] computeExceptions(IClassHierarchy cha, IR ir, SSAInstruction s) throws InvalidClassFileException { - Collection c = null; - Language l = ir.getMethod().getDeclaringClass().getClassLoader().getLanguage(); - if (s instanceof SSAInvokeInstruction) { - SSAInvokeInstruction call = (SSAInvokeInstruction) s; - c = l.inferInvokeExceptions(call.getDeclaredTarget(), cha); - } 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; - } - } - -} +/******************************************************************************* + * 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.classLoader.Language; +import com.ibm.wala.ipa.cha.IClassHierarchy; +import com.ibm.wala.shrikeCT.InvalidClassFileException; +import com.ibm.wala.ssa.IR; +import com.ibm.wala.ssa.ISSABasicBlock; +import com.ibm.wala.ssa.SSACFG; +import com.ibm.wala.ssa.SSACFG.ExceptionHandlerBasicBlock; +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.types.TypeReference; +import com.ibm.wala.util.WalaException; +import com.ibm.wala.util.debug.Assertions; +import com.ibm.wala.util.graph.Graph; +import com.ibm.wala.util.graph.impl.SlowSparseNumberedGraph; + +/** + * Utility class to remove exceptional edges to exit() from a CFG + */ +public class CFGSanitizer { + + /** + * Return a view of the {@link ControlFlowGraph} for an {@link IR}, which elides all exceptional exits from PEIs in the IR. + */ + public static Graph sanitize(IR ir, IClassHierarchy cha) throws IllegalArgumentException, WalaException { + + if (ir == null) { + throw new IllegalArgumentException("ir cannot be null"); + } + + ControlFlowGraph cfg = ir.getControlFlowGraph(); + Graph g = SlowSparseNumberedGraph.make(); + // add all nodes to the graph + for (Iterator it = cfg.iterator(); it.hasNext();) { + g.addNode(it.next()); + } + + // add all edges to the graph, except those that go to exit + for (Iterator it = cfg.iterator(); it.hasNext();) { + ISSABasicBlock b = (ISSABasicBlock) it.next(); + for (Iterator it2 = cfg.getSuccNodes(b); it2.hasNext();) { + ISSABasicBlock b2 = (ISSABasicBlock) it2.next(); + + if (!b2.isExitBlock()) { + g.addEdge(b, b2); + } + } + } + + // now add edges to exit, ignoring undeclared exceptions + ISSABasicBlock exit = cfg.exit(); + + for (Iterator it = cfg.getPredNodes(exit); it.hasNext();) { + // for each predecessor of exit ... + ISSABasicBlock b = (ISSABasicBlock) it.next(); + + SSAInstruction s = ir.getInstructions()[b.getLastInstructionIndex()]; + if (s == null) { + // TODO: this shouldn't happen? + continue; + } + if (s instanceof SSAReturnInstruction || s instanceof SSAThrowInstruction || cfg.getSuccNodeCount(b) == 1) { + // return or athrow, or some statement which is not an athrow or return whose only successor is the exit node (can only + // occur in synthetic methods without a return statement? --MS); add edge to exit + g.addEdge(b, exit); + } else { + // compute types of exceptions the pei may throw + TypeReference[] exceptions = null; + try { + exceptions = computeExceptions(cha, ir, s); + } catch (InvalidClassFileException e1) { + e1.printStackTrace(); + Assertions.UNREACHABLE(); + } + // 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 = null; + try { + declared = ir.getMethod().getDeclaredExceptions(); + } catch (InvalidClassFileException e) { + e.printStackTrace(); + Assertions.UNREACHABLE(); + } + 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; + } + + /** + * What are the exception types which s may throw? + */ + private static TypeReference[] computeExceptions(IClassHierarchy cha, IR ir, SSAInstruction s) throws InvalidClassFileException { + Collection c = null; + Language l = ir.getMethod().getDeclaringClass().getClassLoader().getLanguage(); + if (s instanceof SSAInvokeInstruction) { + SSAInvokeInstruction call = (SSAInvokeInstruction) s; + c = l.inferInvokeExceptions(call.getDeclaredTarget(), cha); + } 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; + } + } + +} diff --git a/com.ibm.wala.core/src/com/ibm/wala/cfg/ControlFlowGraph.java b/com.ibm.wala.core/src/com/ibm/wala/cfg/ControlFlowGraph.java index f21a3ae4b..44529f955 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/cfg/ControlFlowGraph.java +++ b/com.ibm.wala.core/src/com/ibm/wala/cfg/ControlFlowGraph.java @@ -1,92 +1,92 @@ -/******************************************************************************* - * 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.List; - -import com.ibm.wala.classLoader.IMethod; -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. - */ -public interface ControlFlowGraph> extends NumberedGraph { - - /** - * Return the entry basic block in the CFG - */ - public T entry(); - - /** - * @return the synthetic exit block for the cfg - */ - public T 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 T getBlockForInstruction(int index); - - /** - * @return the instructions of this CFG, as an array. - */ - I[] getInstructions(); - - /** - * TODO: move this into IR? - * - * @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 must indicate the exception-handling scope. So the first block is the first candidate catch block, - * and so on. With this invariant one can compute the exceptional control flow for a given exception type. - * - * @return the basic blocks which may be reached from b via exceptional control flow - */ - public List getExceptionalSuccessors(T b); - - /** - * The order of blocks returned should be arbitrary but deterministic. - * - * @return the basic blocks which may be reached from b via normal control flow - */ - public Collection getNormalSuccessors(T b); - - /** - * The order of blocks returned should be arbitrary but deterministic. - * - * @return the basic blocks from which b may be reached via exceptional control flow - */ - public Collection getExceptionalPredecessors(T b); - - /** - * The order of blocks returned should be arbitrary but deterministic. - * - * @return the basic blocks from which b may be reached via normal control flow - */ - public Collection getNormalPredecessors(T b); -} +/******************************************************************************* + * 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.List; + +import com.ibm.wala.classLoader.IMethod; +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. + */ +public interface ControlFlowGraph> extends NumberedGraph { + + /** + * Return the entry basic block in the CFG + */ + public T entry(); + + /** + * @return the synthetic exit block for the cfg + */ + public T 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 T getBlockForInstruction(int index); + + /** + * @return the instructions of this CFG, as an array. + */ + I[] getInstructions(); + + /** + * TODO: move this into IR? + * + * @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 must indicate the exception-handling scope. So the first block is the first candidate catch block, + * and so on. With this invariant one can compute the exceptional control flow for a given exception type. + * + * @return the basic blocks which may be reached from b via exceptional control flow + */ + public List getExceptionalSuccessors(T b); + + /** + * The order of blocks returned should be arbitrary but deterministic. + * + * @return the basic blocks which may be reached from b via normal control flow + */ + public Collection getNormalSuccessors(T b); + + /** + * The order of blocks returned should be arbitrary but deterministic. + * + * @return the basic blocks from which b may be reached via exceptional control flow + */ + public Collection getExceptionalPredecessors(T b); + + /** + * The order of blocks returned should be arbitrary but deterministic. + * + * @return the basic blocks from which b may be reached via normal control flow + */ + public Collection getNormalPredecessors(T b); +} diff --git a/com.ibm.wala.core/src/com/ibm/wala/cfg/IBasicBlock.java b/com.ibm.wala.core/src/com/ibm/wala/cfg/IBasicBlock.java index f48eb1525..a5b9bddbf 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/cfg/IBasicBlock.java +++ b/com.ibm.wala.core/src/com/ibm/wala/cfg/IBasicBlock.java @@ -1,74 +1,74 @@ -/******************************************************************************* - * 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 com.ibm.wala.classLoader.IMethod; -import com.ibm.wala.util.graph.INodeWithNumber; - -/** - * An interface for a basic block in a control flow graph. - */ -public interface IBasicBlock extends INodeWithNumber, Iterable { - - /** - * 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 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(); - -} +/******************************************************************************* + * 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 com.ibm.wala.classLoader.IMethod; +import com.ibm.wala.util.graph.INodeWithNumber; + +/** + * An interface for a basic block in a control flow graph. + */ +public interface IBasicBlock extends INodeWithNumber, Iterable { + + /** + * 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 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(); + +} diff --git a/com.ibm.wala.core/src/com/ibm/wala/cfg/ShrikeCFG.java b/com.ibm.wala.core/src/com/ibm/wala/cfg/ShrikeCFG.java index 24123479a..771ee3c09 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/cfg/ShrikeCFG.java +++ b/com.ibm.wala.core/src/com/ibm/wala/cfg/ShrikeCFG.java @@ -1,551 +1,551 @@ -/******************************************************************************* - * 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.ArrayList; -import java.util.Collection; -import java.util.Iterator; -import java.util.Set; - -import com.ibm.wala.classLoader.BytecodeLanguage; -import com.ibm.wala.classLoader.IBytecodeMethod; -import com.ibm.wala.classLoader.IClass; -import com.ibm.wala.classLoader.IClassLoader; -import com.ibm.wala.classLoader.IMethod; -import com.ibm.wala.ipa.cha.IClassHierarchy; -import com.ibm.wala.shrikeBT.ExceptionHandler; -import com.ibm.wala.shrikeBT.IInstruction; -import com.ibm.wala.shrikeBT.IInvokeInstruction; -import com.ibm.wala.shrikeBT.ReturnInstruction; -import com.ibm.wala.shrikeBT.ThrowInstruction; -import com.ibm.wala.shrikeCT.InvalidClassFileException; -import com.ibm.wala.types.ClassLoaderReference; -import com.ibm.wala.types.MethodReference; -import com.ibm.wala.types.TypeReference; -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.graph.impl.NodeWithNumber; -import com.ibm.wala.util.shrike.ShrikeUtil; -import com.ibm.wala.util.warnings.Warning; -import com.ibm.wala.util.warnings.Warnings; - -/** - * A graph of basic blocks. - */ -public class ShrikeCFG extends AbstractCFG { - - private static final boolean DEBUG = false; - - private int[] instruction2Block; - - private final IBytecodeMethod method; - - /** - * Cache this here for efficiency - */ - private final int hashBase; - - /** - * Set of Shrike {@link ExceptionHandler} objects that cover this method. - */ - final private Set exceptionHandlers = HashSetFactory.make(10); - - public static ShrikeCFG make(IBytecodeMethod m) { - return new ShrikeCFG(m); - } - - private ShrikeCFG(IBytecodeMethod method) throws IllegalArgumentException { - super(method); - if (method == null) { - throw new IllegalArgumentException("method cannot be null"); - } - this.method = method; - this.hashBase = method.hashCode() * 9967; - makeBasicBlocks(); - init(); - computeI2BMapping(); - computeEdges(); - - if (DEBUG) { - System.err.println(this); - } - } - - @Override - public IBytecodeMethod getMethod() { - return method; - } - - @Override - public int hashCode() { - return 9511 * getMethod().hashCode(); - } - - @Override - 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 = iterator(); 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 = iterator(); it.hasNext();) { - BasicBlock b = (BasicBlock) it.next(); - if (b.equals(exit())) { - continue; - } else if (b.equals(entry())) { - BasicBlock bb0 = getBlockForInstruction(0); - assert bb0 != null; - addNormalEdge(b, bb0); - } else { - b.computeOutgoingEdges(); - } - } - } - - 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; - IInstruction[] instructions = 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 (instructions[i].isPEI()) { - 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 BasicBlock getBlockForInstruction(int index) { - return getNode(instruction2Block[index]); - } - - public final class BasicBlock extends NodeWithNumber implements IBasicBlock { - - /** - * The number of the ShrikeBT instruction that begins this block. - */ - final private int startIndex; - - public BasicBlock(int startIndex) { - this.startIndex = startIndex; - } - - public boolean isCatchBlock() { - return ShrikeCFG.this.isCatchBlock(getNumber()); - } - - private void computeOutgoingEdges() { - if (DEBUG) { - System.err.println("Block " + this + ": computeOutgoingEdges()"); - } - - IInstruction last = getInstructions()[getLastInstructionIndex()]; - int[] targets = last.getBranchTargets(); - for (int i = 0; i < targets.length; i++) { - BasicBlock b = getBlockForInstruction(targets[i]); - addNormalEdgeTo(b); - } - addExceptionalEdges(last); - if (last.isFallThrough()) { - BasicBlock next = getNode(getNumber() + 1); - addNormalEdgeTo(next); - } - if (last instanceof ReturnInstruction) { - // link each return instruction to the exit block. - BasicBlock exit = 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. - */ - protected void addExceptionalEdges(IInstruction last) { - IClassHierarchy cha = getMethod().getClassHierarchy(); - if (last.isPEI()) { - Collection exceptionTypes = null; - boolean goToAllHandlers = false; - - ExceptionHandler[] hs = getExceptionHandlers(); - if (last instanceof ThrowInstruction) { - // 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) { - IClassLoader loader = getMethod().getDeclaringClass().getClassLoader(); - BytecodeLanguage l = (BytecodeLanguage) loader.getLanguage(); - exceptionTypes = l.getImplicitExceptionTypes(last); - if (last instanceof IInvokeInstruction) { - IInvokeInstruction call = (IInvokeInstruction) last; - exceptionTypes = HashSetFactory.make(exceptionTypes); - MethodReference target = MethodReference.findOrCreate(l, loader.getReference(), call.getClassType(), call - .getMethodName(), call.getMethodSignature()); - try { - exceptionTypes.addAll(l.inferInvokeExceptions(target, cha)); - } catch (InvalidClassFileException e) { - e.printStackTrace(); - Assertions.UNREACHABLE(); - } - } - } - } - - if (hs != null && hs.length > 0) { - // found a handler for this PEI - - // create a mutable copy - if (!goToAllHandlers) { - exceptionTypes = HashSetFactory.make(exceptionTypes); - } - - // this var gets set to false if goToAllHandlers is true but some enclosing exception handler catches all - // exceptions. in such a case, we need not add an exceptional edge to the method exit - boolean needEdgeToExitForAllHandlers = true; - for (int j = 0; j < hs.length; j++) { - if (DEBUG) { - System.err.println(" handler " + hs[j]); - } - BasicBlock b = getBlockForInstruction(hs[j].getHandler()); - if (DEBUG) { - System.err.println(" target " + b); - } - if (goToAllHandlers) { - // add an edge to the catch block. - if (DEBUG) { - System.err.println(" gotoAllHandlers " + b); - } - addExceptionalEdgeTo(b); - // if the handler catches all exceptions, we don't need to add an edge to the exit or any other handlers - if (hs[j].getCatchClass() == null) { - needEdgeToExitForAllHandlers = false; - break; - } - } else { - TypeReference caughtException = null; - if (hs[j].getCatchClass() != null) { - ClassLoaderReference loader = ShrikeCFG.this.getMethod().getDeclaringClass().getReference().getClassLoader(); - caughtException = ShrikeUtil.makeTypeReference(loader, hs[j].getCatchClass()); - if (DEBUG) { - System.err.println(" caughtException " + caughtException); - } - 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; - } - } else { - if (DEBUG) { - System.err.println(" catchClass() == null"); - } - // hs[j].getCatchClass() == null. - // this means that the handler catches all exceptions. - // add the edge and null out all types - if (!exceptionTypes.isEmpty()) { - addExceptionalEdgeTo(b); - exceptionTypes.clear(); - caughtException = null; - } - } - if (caughtException != null) { - IClass caughtClass = cha.lookupClass(caughtException); - // the set "caught" should be the set of exceptions that MUST - // have been caught by the handlers in scope - ArrayList caught = new ArrayList(exceptionTypes.size()); - // check if we should add an edge to the catch block. - for (TypeReference t : exceptionTypes) { - if (t != null) { - IClass klass = cha.lookupClass(t); - if (klass == null) { - Warnings.add(FailedExceptionResolutionWarning.create(caughtException)); - // conservatively add an edge - addExceptionalEdgeTo(b); - } else { - boolean subtype1 = cha.isSubclassOf(klass, caughtClass); - if (subtype1 || cha.isSubclassOf(caughtClass, klass)) { - // add the edge and null out the type from the array - addExceptionalEdgeTo(b); - if (subtype1) { - caught.add(t); - } - } - } - } - } - exceptionTypes.removeAll(caught); - } - } - } - // if needed, add an edge to the exit block. - if ((exceptionTypes == null && needEdgeToExitForAllHandlers) || (exceptionTypes != null && !exceptionTypes.isEmpty())) { - BasicBlock exit = exit(); - addExceptionalEdgeTo(exit); - } - } else { - // found no handler for this PEI ... link to the exit block. - BasicBlock exit = 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; - } - - private void addNormalEdgeTo(BasicBlock b) { - addNormalEdge(this, b); - } - - private void addExceptionalEdgeTo(BasicBlock b) { - addExceptionalEdge(this, b); - } - - 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 { - int i = 1; - BasicBlock next; - do { - next = getNode(getNumber() + i); - } while (next == null); - return next.getFirstInstructionIndex() - 1; - } - } - - public int getFirstInstructionIndex() { - return startIndex; - } - - @Override - public String toString() { - return "BB[Shrike]" + getNumber() + " - " + method.getDeclaringClass().getReference().getName() + "." + method.getName(); - } - - /* - * @see com.ibm.wala.cfg.BasicBlock#isExitBlock() - */ - public boolean isExitBlock() { - return this == ShrikeCFG.this.exit(); - } - - /* - * @see com.ibm.wala.cfg.BasicBlock#isEntryBlock() - */ - public boolean isEntryBlock() { - return this == ShrikeCFG.this.entry(); - } - - /* - * @see com.ibm.wala.cfg.BasicBlock#getMethod() - */ - public IMethod getMethod() { - return ShrikeCFG.this.getMethod(); - } - - @Override - public int hashCode() { - return hashBase + getNumber(); - } - - @Override - public boolean equals(Object o) { - return (o instanceof BasicBlock) && ((BasicBlock) o).getMethod().equals(getMethod()) - && ((BasicBlock) o).getNumber() == getNumber(); - } - - /* - * @see com.ibm.wala.cfg.BasicBlock#getNumber() - */ - public int getNumber() { - return getGraphNodeId(); - } - - public Iterator iterator() { - return new ArrayIterator(getInstructions(), getFirstInstructionIndex(), getLastInstructionIndex()); - } - } - - @Override - public String toString() { - StringBuffer s = new StringBuffer(""); - for (Iterator it = iterator(); 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 succNodes = getSuccNodes(bb); - while (succNodes.hasNext()) { - s.append(" -> BB").append(getNumber(succNodes.next())).append("\n"); - } - } - return s.toString(); - } - - public Set getExceptionHandlers() { - return exceptionHandlers; - } - - /* - * @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; - } - } - - /** - * A warning 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; - } - - @Override - public String getMsg() { - return getClass().toString() + " : " + T; - } - - public static FailedExceptionResolutionWarning create(TypeReference T) { - return new FailedExceptionResolutionWarning(T); - } - } -} +/******************************************************************************* + * 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.ArrayList; +import java.util.Collection; +import java.util.Iterator; +import java.util.Set; + +import com.ibm.wala.classLoader.BytecodeLanguage; +import com.ibm.wala.classLoader.IBytecodeMethod; +import com.ibm.wala.classLoader.IClass; +import com.ibm.wala.classLoader.IClassLoader; +import com.ibm.wala.classLoader.IMethod; +import com.ibm.wala.ipa.cha.IClassHierarchy; +import com.ibm.wala.shrikeBT.ExceptionHandler; +import com.ibm.wala.shrikeBT.IInstruction; +import com.ibm.wala.shrikeBT.IInvokeInstruction; +import com.ibm.wala.shrikeBT.ReturnInstruction; +import com.ibm.wala.shrikeBT.ThrowInstruction; +import com.ibm.wala.shrikeCT.InvalidClassFileException; +import com.ibm.wala.types.ClassLoaderReference; +import com.ibm.wala.types.MethodReference; +import com.ibm.wala.types.TypeReference; +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.graph.impl.NodeWithNumber; +import com.ibm.wala.util.shrike.ShrikeUtil; +import com.ibm.wala.util.warnings.Warning; +import com.ibm.wala.util.warnings.Warnings; + +/** + * A graph of basic blocks. + */ +public class ShrikeCFG extends AbstractCFG { + + private static final boolean DEBUG = false; + + private int[] instruction2Block; + + private final IBytecodeMethod method; + + /** + * Cache this here for efficiency + */ + private final int hashBase; + + /** + * Set of Shrike {@link ExceptionHandler} objects that cover this method. + */ + final private Set exceptionHandlers = HashSetFactory.make(10); + + public static ShrikeCFG make(IBytecodeMethod m) { + return new ShrikeCFG(m); + } + + private ShrikeCFG(IBytecodeMethod method) throws IllegalArgumentException { + super(method); + if (method == null) { + throw new IllegalArgumentException("method cannot be null"); + } + this.method = method; + this.hashBase = method.hashCode() * 9967; + makeBasicBlocks(); + init(); + computeI2BMapping(); + computeEdges(); + + if (DEBUG) { + System.err.println(this); + } + } + + @Override + public IBytecodeMethod getMethod() { + return method; + } + + @Override + public int hashCode() { + return 9511 * getMethod().hashCode(); + } + + @Override + 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 = iterator(); 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 = iterator(); it.hasNext();) { + BasicBlock b = (BasicBlock) it.next(); + if (b.equals(exit())) { + continue; + } else if (b.equals(entry())) { + BasicBlock bb0 = getBlockForInstruction(0); + assert bb0 != null; + addNormalEdge(b, bb0); + } else { + b.computeOutgoingEdges(); + } + } + } + + 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; + IInstruction[] instructions = 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 (instructions[i].isPEI()) { + 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 BasicBlock getBlockForInstruction(int index) { + return getNode(instruction2Block[index]); + } + + public final class BasicBlock extends NodeWithNumber implements IBasicBlock { + + /** + * The number of the ShrikeBT instruction that begins this block. + */ + final private int startIndex; + + public BasicBlock(int startIndex) { + this.startIndex = startIndex; + } + + public boolean isCatchBlock() { + return ShrikeCFG.this.isCatchBlock(getNumber()); + } + + private void computeOutgoingEdges() { + if (DEBUG) { + System.err.println("Block " + this + ": computeOutgoingEdges()"); + } + + IInstruction last = getInstructions()[getLastInstructionIndex()]; + int[] targets = last.getBranchTargets(); + for (int i = 0; i < targets.length; i++) { + BasicBlock b = getBlockForInstruction(targets[i]); + addNormalEdgeTo(b); + } + addExceptionalEdges(last); + if (last.isFallThrough()) { + BasicBlock next = getNode(getNumber() + 1); + addNormalEdgeTo(next); + } + if (last instanceof ReturnInstruction) { + // link each return instruction to the exit block. + BasicBlock exit = 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. + */ + protected void addExceptionalEdges(IInstruction last) { + IClassHierarchy cha = getMethod().getClassHierarchy(); + if (last.isPEI()) { + Collection exceptionTypes = null; + boolean goToAllHandlers = false; + + ExceptionHandler[] hs = getExceptionHandlers(); + if (last instanceof ThrowInstruction) { + // 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) { + IClassLoader loader = getMethod().getDeclaringClass().getClassLoader(); + BytecodeLanguage l = (BytecodeLanguage) loader.getLanguage(); + exceptionTypes = l.getImplicitExceptionTypes(last); + if (last instanceof IInvokeInstruction) { + IInvokeInstruction call = (IInvokeInstruction) last; + exceptionTypes = HashSetFactory.make(exceptionTypes); + MethodReference target = MethodReference.findOrCreate(l, loader.getReference(), call.getClassType(), call + .getMethodName(), call.getMethodSignature()); + try { + exceptionTypes.addAll(l.inferInvokeExceptions(target, cha)); + } catch (InvalidClassFileException e) { + e.printStackTrace(); + Assertions.UNREACHABLE(); + } + } + } + } + + if (hs != null && hs.length > 0) { + // found a handler for this PEI + + // create a mutable copy + if (!goToAllHandlers) { + exceptionTypes = HashSetFactory.make(exceptionTypes); + } + + // this var gets set to false if goToAllHandlers is true but some enclosing exception handler catches all + // exceptions. in such a case, we need not add an exceptional edge to the method exit + boolean needEdgeToExitForAllHandlers = true; + for (int j = 0; j < hs.length; j++) { + if (DEBUG) { + System.err.println(" handler " + hs[j]); + } + BasicBlock b = getBlockForInstruction(hs[j].getHandler()); + if (DEBUG) { + System.err.println(" target " + b); + } + if (goToAllHandlers) { + // add an edge to the catch block. + if (DEBUG) { + System.err.println(" gotoAllHandlers " + b); + } + addExceptionalEdgeTo(b); + // if the handler catches all exceptions, we don't need to add an edge to the exit or any other handlers + if (hs[j].getCatchClass() == null) { + needEdgeToExitForAllHandlers = false; + break; + } + } else { + TypeReference caughtException = null; + if (hs[j].getCatchClass() != null) { + ClassLoaderReference loader = ShrikeCFG.this.getMethod().getDeclaringClass().getReference().getClassLoader(); + caughtException = ShrikeUtil.makeTypeReference(loader, hs[j].getCatchClass()); + if (DEBUG) { + System.err.println(" caughtException " + caughtException); + } + 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; + } + } else { + if (DEBUG) { + System.err.println(" catchClass() == null"); + } + // hs[j].getCatchClass() == null. + // this means that the handler catches all exceptions. + // add the edge and null out all types + if (!exceptionTypes.isEmpty()) { + addExceptionalEdgeTo(b); + exceptionTypes.clear(); + caughtException = null; + } + } + if (caughtException != null) { + IClass caughtClass = cha.lookupClass(caughtException); + // the set "caught" should be the set of exceptions that MUST + // have been caught by the handlers in scope + ArrayList caught = new ArrayList(exceptionTypes.size()); + // check if we should add an edge to the catch block. + for (TypeReference t : exceptionTypes) { + if (t != null) { + IClass klass = cha.lookupClass(t); + if (klass == null) { + Warnings.add(FailedExceptionResolutionWarning.create(caughtException)); + // conservatively add an edge + addExceptionalEdgeTo(b); + } else { + boolean subtype1 = cha.isSubclassOf(klass, caughtClass); + if (subtype1 || cha.isSubclassOf(caughtClass, klass)) { + // add the edge and null out the type from the array + addExceptionalEdgeTo(b); + if (subtype1) { + caught.add(t); + } + } + } + } + } + exceptionTypes.removeAll(caught); + } + } + } + // if needed, add an edge to the exit block. + if ((exceptionTypes == null && needEdgeToExitForAllHandlers) || (exceptionTypes != null && !exceptionTypes.isEmpty())) { + BasicBlock exit = exit(); + addExceptionalEdgeTo(exit); + } + } else { + // found no handler for this PEI ... link to the exit block. + BasicBlock exit = 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; + } + + private void addNormalEdgeTo(BasicBlock b) { + addNormalEdge(this, b); + } + + private void addExceptionalEdgeTo(BasicBlock b) { + addExceptionalEdge(this, b); + } + + 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 { + int i = 1; + BasicBlock next; + do { + next = getNode(getNumber() + i); + } while (next == null); + return next.getFirstInstructionIndex() - 1; + } + } + + public int getFirstInstructionIndex() { + return startIndex; + } + + @Override + public String toString() { + return "BB[Shrike]" + getNumber() + " - " + method.getDeclaringClass().getReference().getName() + "." + method.getName(); + } + + /* + * @see com.ibm.wala.cfg.BasicBlock#isExitBlock() + */ + public boolean isExitBlock() { + return this == ShrikeCFG.this.exit(); + } + + /* + * @see com.ibm.wala.cfg.BasicBlock#isEntryBlock() + */ + public boolean isEntryBlock() { + return this == ShrikeCFG.this.entry(); + } + + /* + * @see com.ibm.wala.cfg.BasicBlock#getMethod() + */ + public IMethod getMethod() { + return ShrikeCFG.this.getMethod(); + } + + @Override + public int hashCode() { + return hashBase + getNumber(); + } + + @Override + public boolean equals(Object o) { + return (o instanceof BasicBlock) && ((BasicBlock) o).getMethod().equals(getMethod()) + && ((BasicBlock) o).getNumber() == getNumber(); + } + + /* + * @see com.ibm.wala.cfg.BasicBlock#getNumber() + */ + public int getNumber() { + return getGraphNodeId(); + } + + public Iterator iterator() { + return new ArrayIterator(getInstructions(), getFirstInstructionIndex(), getLastInstructionIndex()); + } + } + + @Override + public String toString() { + StringBuffer s = new StringBuffer(""); + for (Iterator it = iterator(); 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 succNodes = getSuccNodes(bb); + while (succNodes.hasNext()) { + s.append(" -> BB").append(getNumber(succNodes.next())).append("\n"); + } + } + return s.toString(); + } + + public Set getExceptionHandlers() { + return exceptionHandlers; + } + + /* + * @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; + } + } + + /** + * A warning 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; + } + + @Override + public String getMsg() { + return getClass().toString() + " : " + T; + } + + public static FailedExceptionResolutionWarning create(TypeReference T) { + return new FailedExceptionResolutionWarning(T); + } + } +} diff --git a/com.ibm.wala.core/src/com/ibm/wala/cfg/Util.java b/com.ibm.wala.core/src/com/ibm/wala/cfg/Util.java index ab132610a..5854f743e 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/cfg/Util.java +++ b/com.ibm.wala.core/src/com/ibm/wala/cfg/Util.java @@ -1,226 +1,226 @@ -/******************************************************************************* - * 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.ssa.SymbolTable; -import com.ibm.wala.util.debug.Assertions; - -/** - * Convenience methods for navigating a {@link ControlFlowGraph}. - */ -public class Util { - - /** - * @return the last instruction in basic block b, as stored in the instruction array for cfg - */ - public static SSAInstruction getLastInstruction(ControlFlowGraph cfg, IBasicBlock b) { - if (b == null) { - throw new IllegalArgumentException("b is null"); - } - if (cfg == null) { - throw new IllegalArgumentException("G is null"); - } - return (SSAInstruction) cfg.getInstructions()[b.getLastInstructionIndex()]; - } - - /** - * Does basic block b end with a conditional branch instruction? - */ - public static boolean endsWithConditionalBranch(ControlFlowGraph G, IBasicBlock b) { - return getLastInstruction(G, b) instanceof SSAConditionalBranchInstruction; - } - - /** - * Does basic block b end with a switch instruction? - */ - public static boolean endsWithSwitch(ControlFlowGraph G, IBasicBlock b) { - return getLastInstruction(G, b) instanceof SSASwitchInstruction; - } - - /** - * Given that b falls through to the next basic block, what basic block does it fall through to? - */ - public static > T getFallThruBlock(ControlFlowGraph G, T b) { - if (b == null) { - throw new IllegalArgumentException("b is null"); - } - if (G == null) { - throw new IllegalArgumentException("G is null"); - } - return G.getBlockForInstruction(b.getLastInstructionIndex() + 1); - } - - /** - * Given that b ends with a conditional branch, return the basic block to - * which control transfers if the branch is not taken. - */ - public static > T getNotTakenSuccessor(ControlFlowGraph G, T b) { - if (G == null) { - throw new IllegalArgumentException("G is null"); - } - if (!endsWithConditionalBranch(G, b)) { - throw new IllegalArgumentException(b.toString() + " does not end with a conditional branch"); - } - return getFallThruBlock(G, b); - } - - /** - * Given that b ends with a conditional branch, return the basic block to - * which control transfers if the branch is taken. - */ - public static > T getTakenSuccessor(ControlFlowGraph G, T b) { - if (G == null) { - throw new IllegalArgumentException("G is null"); - } - if (!endsWithConditionalBranch(G, b)) { - throw new IllegalArgumentException(b.toString() + " does not end with a conditional branch"); - } - T fs = getNotTakenSuccessor(G, b); - for (Iterator ss = G.getSuccNodes(b); ss.hasNext();) { - T s = ss.next(); - if (s != fs) - return s; - } - - // under pathological conditions, b may have exactly one successor (in other - // words, the - // branch is irrelevant - return fs; - } - - /** - * When the tested value of the switch statement in b has value c, which basic - * block does control transfer to. - */ - public static > T resolveSwitch(ControlFlowGraph G, T b, int c) { - assert endsWithSwitch(G, b); - SSASwitchInstruction s = (SSASwitchInstruction) getLastInstruction(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()); - } - - /** - * Is block s the default case for the switch instruction which is the last instruction of block b? - */ - public static > boolean isSwitchDefault(ControlFlowGraph G, T b, T s) { - if (G == null) { - throw new IllegalArgumentException("G is null"); - } - assert endsWithSwitch(G, b); - SSASwitchInstruction sw = (SSASwitchInstruction) getLastInstruction(G, b); - assert G.getBlockForInstruction(sw.getDefault()) != null; - return G.getBlockForInstruction(sw.getDefault()).equals(s); - } - - /** - * When a switch statement at the end of block b transfers control to block s, - * which case was taken? TODO: Is this correct? Can't we have multiple cases - * that apply? Check on this. - */ - public static > int getSwitchLabel(ControlFlowGraph G, T b, T s) { - assert endsWithSwitch(G, b); - SSASwitchInstruction sw = (SSASwitchInstruction) getLastInstruction(G, b); - int[] casesAndLabels = sw.getCasesAndLabels(); - for (int i = 0; i < casesAndLabels.length; i += 2) { - if (G.getBlockForInstruction(casesAndLabels[i + 1]).equals(s)) { - return casesAndLabels[i]; - } - } - - Assertions.UNREACHABLE(); - return -1; - } - - /** - * To which {@link IBasicBlock} does control flow from basic block bb, which ends in a - * conditional branch, when the conditional branch operands evaluate to the - * constants c1 and c2, respectively. - * - * Callers must resolve the constant values from the {@link SymbolTable} - * before calling this method. These integers are not value numbers; - */ - public static > T resolveBranch(ControlFlowGraph G, T bb, int c1, int c2) { - SSAConditionalBranchInstruction c = (SSAConditionalBranchInstruction) getLastInstruction(G, bb); - switch ((ConditionalBranchInstruction.Operator) c.getOperator()) { - case EQ: - if (c1 == c2) - return getTakenSuccessor(G, bb); - else - return getNotTakenSuccessor(G, bb); - case NE: - if (c1 != c2) - return getTakenSuccessor(G, bb); - else - return getNotTakenSuccessor(G, bb); - case LT: - if (c1 < c2) - return getTakenSuccessor(G, bb); - else - return getNotTakenSuccessor(G, bb); - case GE: - if (c1 >= c2) - return getTakenSuccessor(G, bb); - else - return getNotTakenSuccessor(G, bb); - case GT: - if (c1 > c2) - return getTakenSuccessor(G, bb); - else - return getNotTakenSuccessor(G, bb); - case LE: - if (c1 <= c2) - return getTakenSuccessor(G, bb); - else - return getNotTakenSuccessor(G, bb); - } - - Assertions.UNREACHABLE(); - return null; - } - - /** - * Given that a is a predecessor of b in the cfg .. - * - * When we enumerate the predecessors of b in order, which is the first index - * in this order in which a appears? Note that this order corresponds to the - * order of operands in a phi instruction. - */ - public static > int whichPred(ControlFlowGraph cfg, T a, T b) { - if (cfg == null) { - throw new IllegalArgumentException("cfg is null"); - } - if (a == null) { - throw new IllegalArgumentException("a is null"); - } - if (b == null) { - throw new IllegalArgumentException("b is null"); - } - 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; - } -} +/******************************************************************************* + * 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.ssa.SymbolTable; +import com.ibm.wala.util.debug.Assertions; + +/** + * Convenience methods for navigating a {@link ControlFlowGraph}. + */ +public class Util { + + /** + * @return the last instruction in basic block b, as stored in the instruction array for cfg + */ + public static SSAInstruction getLastInstruction(ControlFlowGraph cfg, IBasicBlock b) { + if (b == null) { + throw new IllegalArgumentException("b is null"); + } + if (cfg == null) { + throw new IllegalArgumentException("G is null"); + } + return (SSAInstruction) cfg.getInstructions()[b.getLastInstructionIndex()]; + } + + /** + * Does basic block b end with a conditional branch instruction? + */ + public static boolean endsWithConditionalBranch(ControlFlowGraph G, IBasicBlock b) { + return getLastInstruction(G, b) instanceof SSAConditionalBranchInstruction; + } + + /** + * Does basic block b end with a switch instruction? + */ + public static boolean endsWithSwitch(ControlFlowGraph G, IBasicBlock b) { + return getLastInstruction(G, b) instanceof SSASwitchInstruction; + } + + /** + * Given that b falls through to the next basic block, what basic block does it fall through to? + */ + public static > T getFallThruBlock(ControlFlowGraph G, T b) { + if (b == null) { + throw new IllegalArgumentException("b is null"); + } + if (G == null) { + throw new IllegalArgumentException("G is null"); + } + return G.getBlockForInstruction(b.getLastInstructionIndex() + 1); + } + + /** + * Given that b ends with a conditional branch, return the basic block to + * which control transfers if the branch is not taken. + */ + public static > T getNotTakenSuccessor(ControlFlowGraph G, T b) { + if (G == null) { + throw new IllegalArgumentException("G is null"); + } + if (!endsWithConditionalBranch(G, b)) { + throw new IllegalArgumentException(b.toString() + " does not end with a conditional branch"); + } + return getFallThruBlock(G, b); + } + + /** + * Given that b ends with a conditional branch, return the basic block to + * which control transfers if the branch is taken. + */ + public static > T getTakenSuccessor(ControlFlowGraph G, T b) { + if (G == null) { + throw new IllegalArgumentException("G is null"); + } + if (!endsWithConditionalBranch(G, b)) { + throw new IllegalArgumentException(b.toString() + " does not end with a conditional branch"); + } + T fs = getNotTakenSuccessor(G, b); + for (Iterator ss = G.getSuccNodes(b); ss.hasNext();) { + T s = ss.next(); + if (s != fs) + return s; + } + + // under pathological conditions, b may have exactly one successor (in other + // words, the + // branch is irrelevant + return fs; + } + + /** + * When the tested value of the switch statement in b has value c, which basic + * block does control transfer to. + */ + public static > T resolveSwitch(ControlFlowGraph G, T b, int c) { + assert endsWithSwitch(G, b); + SSASwitchInstruction s = (SSASwitchInstruction) getLastInstruction(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()); + } + + /** + * Is block s the default case for the switch instruction which is the last instruction of block b? + */ + public static > boolean isSwitchDefault(ControlFlowGraph G, T b, T s) { + if (G == null) { + throw new IllegalArgumentException("G is null"); + } + assert endsWithSwitch(G, b); + SSASwitchInstruction sw = (SSASwitchInstruction) getLastInstruction(G, b); + assert G.getBlockForInstruction(sw.getDefault()) != null; + return G.getBlockForInstruction(sw.getDefault()).equals(s); + } + + /** + * When a switch statement at the end of block b transfers control to block s, + * which case was taken? TODO: Is this correct? Can't we have multiple cases + * that apply? Check on this. + */ + public static > int getSwitchLabel(ControlFlowGraph G, T b, T s) { + assert endsWithSwitch(G, b); + SSASwitchInstruction sw = (SSASwitchInstruction) getLastInstruction(G, b); + int[] casesAndLabels = sw.getCasesAndLabels(); + for (int i = 0; i < casesAndLabels.length; i += 2) { + if (G.getBlockForInstruction(casesAndLabels[i + 1]).equals(s)) { + return casesAndLabels[i]; + } + } + + Assertions.UNREACHABLE(); + return -1; + } + + /** + * To which {@link IBasicBlock} does control flow from basic block bb, which ends in a + * conditional branch, when the conditional branch operands evaluate to the + * constants c1 and c2, respectively. + * + * Callers must resolve the constant values from the {@link SymbolTable} + * before calling this method. These integers are not value numbers; + */ + public static > T resolveBranch(ControlFlowGraph G, T bb, int c1, int c2) { + SSAConditionalBranchInstruction c = (SSAConditionalBranchInstruction) getLastInstruction(G, bb); + switch ((ConditionalBranchInstruction.Operator) c.getOperator()) { + case EQ: + if (c1 == c2) + return getTakenSuccessor(G, bb); + else + return getNotTakenSuccessor(G, bb); + case NE: + if (c1 != c2) + return getTakenSuccessor(G, bb); + else + return getNotTakenSuccessor(G, bb); + case LT: + if (c1 < c2) + return getTakenSuccessor(G, bb); + else + return getNotTakenSuccessor(G, bb); + case GE: + if (c1 >= c2) + return getTakenSuccessor(G, bb); + else + return getNotTakenSuccessor(G, bb); + case GT: + if (c1 > c2) + return getTakenSuccessor(G, bb); + else + return getNotTakenSuccessor(G, bb); + case LE: + if (c1 <= c2) + return getTakenSuccessor(G, bb); + else + return getNotTakenSuccessor(G, bb); + } + + Assertions.UNREACHABLE(); + return null; + } + + /** + * Given that a is a predecessor of b in the cfg .. + * + * When we enumerate the predecessors of b in order, which is the first index + * in this order in which a appears? Note that this order corresponds to the + * order of operands in a phi instruction. + */ + public static > int whichPred(ControlFlowGraph cfg, T a, T b) { + if (cfg == null) { + throw new IllegalArgumentException("cfg is null"); + } + if (a == null) { + throw new IllegalArgumentException("a is null"); + } + if (b == null) { + throw new IllegalArgumentException("b is null"); + } + 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; + } +} diff --git a/com.ibm.wala.core/src/com/ibm/wala/cfg/cdg/ControlDependenceGraph.java b/com.ibm.wala.core/src/com/ibm/wala/cfg/cdg/ControlDependenceGraph.java index acd349efa..ead3feea4 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/cfg/cdg/ControlDependenceGraph.java +++ b/com.ibm.wala.core/src/com/ibm/wala/cfg/cdg/ControlDependenceGraph.java @@ -1,264 +1,264 @@ -/******************************************************************************* - * 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.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.NumberedEdgeManager; -import com.ibm.wala.util.graph.NumberedNodeManager; -import com.ibm.wala.util.graph.dominators.DominanceFrontiers; -import com.ibm.wala.util.graph.impl.GraphInverter; -import com.ibm.wala.util.intset.IntSet; -import com.ibm.wala.util.intset.IntSetUtil; -import com.ibm.wala.util.intset.MutableIntSet; - -/** - * Control Dependence Graph - */ -public class ControlDependenceGraph> extends AbstractNumberedGraph { - - /** - * 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 edges - * of the cdg. - */ - private final NumberedEdgeManager 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> 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> buildControlDependence(boolean wantEdgeLabels) { - Map> controlDependence = HashMapFactory.make(cfg.getNumberOfNodes()); - - DominanceFrontiers RDF = new DominanceFrontiers(GraphInverter.invert(cfg), cfg.exit()); - - if (wantEdgeLabels) { - edgeLabels = HashMapFactory.make(); - } - - for (Iterator ns = cfg.iterator(); ns.hasNext();) { - HashSet s = HashSetFactory.make(2); - controlDependence.put(ns.next(), s); - } - - for (Iterator ns = cfg.iterator(); ns.hasNext();) { - T y = ns.next(); - for (Iterator ns2 = RDF.getDominanceFrontier(y); ns2.hasNext();) { - T x = ns2.next(); - controlDependence.get(x).add(y); - if (wantEdgeLabels) { - Set labels = HashSetFactory.make(); - edgeLabels.put(Pair.make(x, y), labels); - for (Iterator ss = cfg.getSuccNodes(x); ss.hasNext();) { - T 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 NumberedEdgeManager constructGraphEdges(final Map> forwardEdges) { - return new NumberedEdgeManager() { - Map> backwardEdges = HashMapFactory.make(forwardEdges.size()); - { - for (Iterator x = cfg.iterator(); x.hasNext();) { - Set s = HashSetFactory.make(); - backwardEdges.put(x.next(), s); - } - for (Iterator ps = forwardEdges.keySet().iterator(); ps.hasNext();) { - T p = ps.next(); - for (Iterator ns = ((Set) forwardEdges.get(p)).iterator(); ns.hasNext();) { - Object n = ns.next(); - backwardEdges.get(n).add(p); - } - } - } - - public Iterator getPredNodes(T N) { - if (backwardEdges.containsKey(N)) - return backwardEdges.get(N).iterator(); - else - return EmptyIterator.instance(); - } - - public IntSet getPredNodeNumbers(T node) { - MutableIntSet x = IntSetUtil.make(); - if (backwardEdges.containsKey(node)) { - for(T pred : backwardEdges.get(node)) { - x.add(pred.getNumber()); - } - } - return x; - } - - public int getPredNodeCount(T N) { - if (backwardEdges.containsKey(N)) - return ((Set) backwardEdges.get(N)).size(); - else - return 0; - } - - public Iterator getSuccNodes(T N) { - if (forwardEdges.containsKey(N)) - return forwardEdges.get(N).iterator(); - else - return EmptyIterator.instance(); - } - - public IntSet getSuccNodeNumbers(T node) { - MutableIntSet x = IntSetUtil.make(); - if (forwardEdges.containsKey(node)) { - for(T succ : forwardEdges.get(node)) { - x.add(succ.getNumber()); - } - } - return x; - } - - public int getSuccNodeCount(T N) { - if (forwardEdges.containsKey(N)) - return ((Set) forwardEdges.get(N)).size(); - else - return 0; - } - - public boolean hasEdge(T src, T dst) { - return forwardEdges.containsKey(src) && ((Set) forwardEdges.get(src)).contains(dst); - } - - public void addEdge(T src, T dst) { - throw new UnsupportedOperationException(); - } - - public void removeEdge(T src, T dst) { - throw new UnsupportedOperationException(); - } - - public void removeAllIncidentEdges(T node) { - throw new UnsupportedOperationException(); - } - - public void removeIncomingEdges(T node) { - throw new UnsupportedOperationException(); - } - - public void removeOutgoingEdges(T node) { - throw new UnsupportedOperationException(); - } - }; - } - - @Override - public String toString() { - StringBuffer sb = new StringBuffer(); - for (Iterator ns = iterator(); ns.hasNext();) { - T 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(Pair.make(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) { - if (cfg == null) { - throw new IllegalArgumentException("null cfg"); - } - this.cfg = cfg; - this.edgeManager = constructGraphEdges(buildControlDependence(wantEdgeLabels)); - } - - /** - * @param cfg governing control flow graph - */ - public ControlDependenceGraph(ControlFlowGraph cfg) { - this(cfg, false); - } - - public ControlFlowGraph getControlFlowGraph() { - 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 getEdgeLabels(Object from, Object to) { - return edgeLabels.get(Pair.make(from, to)); - } - - @Override - public NumberedNodeManager getNodeManager() { - return cfg; - } - - @Override - public NumberedEdgeManager getEdgeManager() { - return edgeManager; - } - - public boolean controlEquivalent(T bb1, T bb2) { - if (getPredNodeCount(bb1) != getPredNodeCount(bb2)) { - return false; - } - - for (Iterator pbs1 = getPredNodes(bb1); pbs1.hasNext();) { - if (!hasEdge(pbs1.next(), bb2)) { - return false; - } - } - - return true; - } -} +/******************************************************************************* + * 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.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.NumberedEdgeManager; +import com.ibm.wala.util.graph.NumberedNodeManager; +import com.ibm.wala.util.graph.dominators.DominanceFrontiers; +import com.ibm.wala.util.graph.impl.GraphInverter; +import com.ibm.wala.util.intset.IntSet; +import com.ibm.wala.util.intset.IntSetUtil; +import com.ibm.wala.util.intset.MutableIntSet; + +/** + * Control Dependence Graph + */ +public class ControlDependenceGraph> extends AbstractNumberedGraph { + + /** + * 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 edges + * of the cdg. + */ + private final NumberedEdgeManager 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> 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> buildControlDependence(boolean wantEdgeLabels) { + Map> controlDependence = HashMapFactory.make(cfg.getNumberOfNodes()); + + DominanceFrontiers RDF = new DominanceFrontiers(GraphInverter.invert(cfg), cfg.exit()); + + if (wantEdgeLabels) { + edgeLabels = HashMapFactory.make(); + } + + for (Iterator ns = cfg.iterator(); ns.hasNext();) { + HashSet s = HashSetFactory.make(2); + controlDependence.put(ns.next(), s); + } + + for (Iterator ns = cfg.iterator(); ns.hasNext();) { + T y = ns.next(); + for (Iterator ns2 = RDF.getDominanceFrontier(y); ns2.hasNext();) { + T x = ns2.next(); + controlDependence.get(x).add(y); + if (wantEdgeLabels) { + Set labels = HashSetFactory.make(); + edgeLabels.put(Pair.make(x, y), labels); + for (Iterator ss = cfg.getSuccNodes(x); ss.hasNext();) { + T 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 NumberedEdgeManager constructGraphEdges(final Map> forwardEdges) { + return new NumberedEdgeManager() { + Map> backwardEdges = HashMapFactory.make(forwardEdges.size()); + { + for (Iterator x = cfg.iterator(); x.hasNext();) { + Set s = HashSetFactory.make(); + backwardEdges.put(x.next(), s); + } + for (Iterator ps = forwardEdges.keySet().iterator(); ps.hasNext();) { + T p = ps.next(); + for (Iterator ns = ((Set) forwardEdges.get(p)).iterator(); ns.hasNext();) { + Object n = ns.next(); + backwardEdges.get(n).add(p); + } + } + } + + public Iterator getPredNodes(T N) { + if (backwardEdges.containsKey(N)) + return backwardEdges.get(N).iterator(); + else + return EmptyIterator.instance(); + } + + public IntSet getPredNodeNumbers(T node) { + MutableIntSet x = IntSetUtil.make(); + if (backwardEdges.containsKey(node)) { + for(T pred : backwardEdges.get(node)) { + x.add(pred.getNumber()); + } + } + return x; + } + + public int getPredNodeCount(T N) { + if (backwardEdges.containsKey(N)) + return ((Set) backwardEdges.get(N)).size(); + else + return 0; + } + + public Iterator getSuccNodes(T N) { + if (forwardEdges.containsKey(N)) + return forwardEdges.get(N).iterator(); + else + return EmptyIterator.instance(); + } + + public IntSet getSuccNodeNumbers(T node) { + MutableIntSet x = IntSetUtil.make(); + if (forwardEdges.containsKey(node)) { + for(T succ : forwardEdges.get(node)) { + x.add(succ.getNumber()); + } + } + return x; + } + + public int getSuccNodeCount(T N) { + if (forwardEdges.containsKey(N)) + return ((Set) forwardEdges.get(N)).size(); + else + return 0; + } + + public boolean hasEdge(T src, T dst) { + return forwardEdges.containsKey(src) && ((Set) forwardEdges.get(src)).contains(dst); + } + + public void addEdge(T src, T dst) { + throw new UnsupportedOperationException(); + } + + public void removeEdge(T src, T dst) { + throw new UnsupportedOperationException(); + } + + public void removeAllIncidentEdges(T node) { + throw new UnsupportedOperationException(); + } + + public void removeIncomingEdges(T node) { + throw new UnsupportedOperationException(); + } + + public void removeOutgoingEdges(T node) { + throw new UnsupportedOperationException(); + } + }; + } + + @Override + public String toString() { + StringBuffer sb = new StringBuffer(); + for (Iterator ns = iterator(); ns.hasNext();) { + T 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(Pair.make(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) { + if (cfg == null) { + throw new IllegalArgumentException("null cfg"); + } + this.cfg = cfg; + this.edgeManager = constructGraphEdges(buildControlDependence(wantEdgeLabels)); + } + + /** + * @param cfg governing control flow graph + */ + public ControlDependenceGraph(ControlFlowGraph cfg) { + this(cfg, false); + } + + public ControlFlowGraph getControlFlowGraph() { + 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 getEdgeLabels(Object from, Object to) { + return edgeLabels.get(Pair.make(from, to)); + } + + @Override + public NumberedNodeManager getNodeManager() { + return cfg; + } + + @Override + public NumberedEdgeManager getEdgeManager() { + return edgeManager; + } + + public boolean controlEquivalent(T bb1, T bb2) { + if (getPredNodeCount(bb1) != getPredNodeCount(bb2)) { + return false; + } + + for (Iterator pbs1 = getPredNodes(bb1); pbs1.hasNext();) { + if (!hasEdge(pbs1.next(), bb2)) { + return false; + } + } + + return true; + } +} diff --git a/com.ibm.wala.core/src/com/ibm/wala/classLoader/AbstractURLModule.java b/com.ibm.wala.core/src/com/ibm/wala/classLoader/AbstractURLModule.java index c26c998b0..315ec5516 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/classLoader/AbstractURLModule.java +++ b/com.ibm.wala.core/src/com/ibm/wala/classLoader/AbstractURLModule.java @@ -1,76 +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.debug.Assertions; -import com.ibm.wala.util.debug.UnimplementedError; -import com.ibm.wala.util.io.FileProvider; - -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 (new 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() throws UnimplementedError { - Assertions.UNREACHABLE(); - return null; - } - - public String getClassName() throws UnsupportedOperationException { - throw new UnsupportedOperationException(); - } - - public Iterator getEntries() { - return new NonNullSingletonIterator(this); - } - -} +/******************************************************************************* + * 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.debug.Assertions; +import com.ibm.wala.util.debug.UnimplementedError; +import com.ibm.wala.util.io.FileProvider; + +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 (new 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() throws UnimplementedError { + Assertions.UNREACHABLE(); + return null; + } + + public String getClassName() throws UnsupportedOperationException { + throw new UnsupportedOperationException(); + } + + public Iterator getEntries() { + return new NonNullSingletonIterator(this); + } + +} diff --git a/com.ibm.wala.core/src/com/ibm/wala/classLoader/ArrayClass.java b/com.ibm.wala.core/src/com/ibm/wala/classLoader/ArrayClass.java index 648f06d68..3e6d1a48b 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/classLoader/ArrayClass.java +++ b/com.ibm.wala.core/src/com/ibm/wala/classLoader/ArrayClass.java @@ -1,332 +1,332 @@ -/******************************************************************************* - * 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.Collection; -import java.util.Collections; -import java.util.HashSet; - -import com.ibm.wala.ipa.cha.IClassHierarchy; -import com.ibm.wala.shrikeBT.Constants; -import com.ibm.wala.types.Selector; -import com.ibm.wala.types.TypeName; -import static com.ibm.wala.types.TypeName.*; -import com.ibm.wala.types.TypeReference; -import com.ibm.wala.util.collections.HashSetFactory; -import com.ibm.wala.util.debug.Assertions; -import com.ibm.wala.util.debug.UnimplementedError; -import com.ibm.wala.util.strings.Atom; - -/** - * Implementation of {@link IClass} for array classes. Such classes would be best called 'broken covariant array types', since that - * is the semantics that they implement. - */ -public class ArrayClass implements IClass, Constants { - - private final IClassHierarchy cha; - - /** - * 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, IClassHierarchy cha) { - this.type = type; - this.loader = loader; - this.cha = cha; - 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 { - // assert loader.getReference().equals(ClassLoaderReference.Primordial); - } - } - - private final TypeReference type; - - private final IClassLoader loader; - - /* - * @see com.ibm.wala.classLoader.IClass#getClassLoader() - */ - public IClassLoader getClassLoader() { - return loader; - } - - /* - * @see com.ibm.wala.classLoader.IClass#getName() - */ - public TypeName getName() { - return getReference().getName(); - } - - /* - * @see com.ibm.wala.classLoader.IClass#isInterface() - */ - public boolean isInterface() { - return false; - } - - /* - * @see com.ibm.wala.classLoader.IClass#isAbstract() - */ - public boolean isAbstract() { - return false; - } - - /* - * @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? - } - - /* - * @see com.ibm.wala.classLoader.IClass#getSuperclass() - */ - public IClass getSuperclass() { - IClass elt = getElementClass(); - 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() == getClassLoader().getLanguage().getRootType()) { - return loader.lookupClass(getClassLoader().getLanguage().getRootType().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()); - } - } - - /* - * @see com.ibm.wala.classLoader.IClass#getMethod(com.ibm.wala.classLoader.Selector) - */ - public IMethod getMethod(Selector sig) { - return cha.lookupClass(getClassLoader().getLanguage().getRootType()).getMethod(sig); - } - - public IField getField(Atom name) { - return getSuperclass().getField(name); - } - - public IField getField(Atom name, TypeName typeName) { - return getSuperclass().getField(name, typeName); - } - - /* - * @see com.ibm.wala.classLoader.IClass#getDeclaredMethods() - */ - public Collection getDeclaredMethods() { - return Collections.emptySet(); - } - - public int getNumberOfDeclaredMethods() { - return 0; - } - - /* - * @see com.ibm.wala.classLoader.IClass#getReference() - */ - public TypeReference getReference() { - return type; - } - - /* - * @see com.ibm.wala.classLoader.IClass#getSourceFileName() - */ - public String getSourceFileName() { - return null; - } - - /* - * @see com.ibm.wala.classLoader.IClass#getClassInitializer() - */ - public IMethod getClassInitializer() { - return null; - } - - /* - * @see com.ibm.wala.classLoader.IClass#isArrayClass() - */ - public boolean isArrayClass() { - return true; - } - - @Override - 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()); - } - - @Override - public int hashCode() { - return type.hashCode(); - } - - /* - * @see com.ibm.wala.classLoader.IClass#getDeclaredFields() - */ - public Collection getDeclaredInstanceFields() throws UnsupportedOperationException { - throw new UnsupportedOperationException(); - } - - /* - * @see com.ibm.wala.classLoader.IClass#getDeclaredStaticFields() - */ - public Collection getDeclaredStaticFields() throws UnimplementedError { - Assertions.UNREACHABLE(); - return null; - } - - /* - * @see com.ibm.wala.classLoader.IClass#getAllImplementedInterfaces() - */ - public Collection getAllImplementedInterfaces() { - HashSet result = HashSetFactory.make(2); - for (TypeReference ref : getClassLoader().getLanguage().getArrayInterfaces()) { - IClass klass = loader.lookupClass(ref.getName()); - if (klass != null) { - result.add(klass); - } - } - - return result; - } - - /* - * @see com.ibm.wala.classLoader.IClass#getAllAncestorInterfaces() - */ - public Collection getAllAncestorInterfaces() throws UnsupportedOperationException { - throw new UnsupportedOperationException(); - } - - /* - * @see com.ibm.wala.classLoader.IClass#isReferenceType() - */ - public boolean isReferenceType() { - return true; - } - - public int getDimensionality() { - int mask = getReference().getDerivedMask(); - if ((mask&PrimitiveMask) == PrimitiveMask) { - mask >>= ElementBits; - } - int dims = 0; - while ((mask&ArrayMask) == ArrayMask) { - mask >>= ElementBits; - dims++; - } - assert dims>0; - return dims; - } - - /** - * @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()); - } - - /* - * @see com.ibm.wala.classLoader.IClass#getDirectInterfaces() - */ - public Collection getDirectInterfaces() throws UnimplementedError { - // TODO Auto-generated method stub - Assertions.UNREACHABLE(); - return null; - } - - @Override - 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; - } - } - - /* - * @see com.ibm.wala.classLoader.IClass#getAllInstanceFields() - */ - public Collection getAllInstanceFields() { - Assertions.UNREACHABLE(); - return null; - } - - /* - * @see com.ibm.wala.classLoader.IClass#getAllStaticFields() - */ - public Collection getAllStaticFields() { - Assertions.UNREACHABLE(); - return null; - } - - /* - * @see com.ibm.wala.classLoader.IClass#getAllMethods() - */ - public Collection getAllMethods() { - return loader.lookupClass(getClassLoader().getLanguage().getRootType().getName()).getAllMethods(); - } - - /* - * @see com.ibm.wala.classLoader.IClass#getAllFields() - */ - public Collection getAllFields() { - Assertions.UNREACHABLE(); - return null; - } - - public IClassHierarchy getClassHierarchy() { - return cha; - } - - public boolean isPublic() { - return true; - } - - public boolean isPrivate() { - return false; - } - - public InputStream getSource() { - return null; - } - -} +/******************************************************************************* + * 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.Collection; +import java.util.Collections; +import java.util.HashSet; + +import com.ibm.wala.ipa.cha.IClassHierarchy; +import com.ibm.wala.shrikeBT.Constants; +import com.ibm.wala.types.Selector; +import com.ibm.wala.types.TypeName; +import static com.ibm.wala.types.TypeName.*; +import com.ibm.wala.types.TypeReference; +import com.ibm.wala.util.collections.HashSetFactory; +import com.ibm.wala.util.debug.Assertions; +import com.ibm.wala.util.debug.UnimplementedError; +import com.ibm.wala.util.strings.Atom; + +/** + * Implementation of {@link IClass} for array classes. Such classes would be best called 'broken covariant array types', since that + * is the semantics that they implement. + */ +public class ArrayClass implements IClass, Constants { + + private final IClassHierarchy cha; + + /** + * 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, IClassHierarchy cha) { + this.type = type; + this.loader = loader; + this.cha = cha; + 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 { + // assert loader.getReference().equals(ClassLoaderReference.Primordial); + } + } + + private final TypeReference type; + + private final IClassLoader loader; + + /* + * @see com.ibm.wala.classLoader.IClass#getClassLoader() + */ + public IClassLoader getClassLoader() { + return loader; + } + + /* + * @see com.ibm.wala.classLoader.IClass#getName() + */ + public TypeName getName() { + return getReference().getName(); + } + + /* + * @see com.ibm.wala.classLoader.IClass#isInterface() + */ + public boolean isInterface() { + return false; + } + + /* + * @see com.ibm.wala.classLoader.IClass#isAbstract() + */ + public boolean isAbstract() { + return false; + } + + /* + * @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? + } + + /* + * @see com.ibm.wala.classLoader.IClass#getSuperclass() + */ + public IClass getSuperclass() { + IClass elt = getElementClass(); + 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() == getClassLoader().getLanguage().getRootType()) { + return loader.lookupClass(getClassLoader().getLanguage().getRootType().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()); + } + } + + /* + * @see com.ibm.wala.classLoader.IClass#getMethod(com.ibm.wala.classLoader.Selector) + */ + public IMethod getMethod(Selector sig) { + return cha.lookupClass(getClassLoader().getLanguage().getRootType()).getMethod(sig); + } + + public IField getField(Atom name) { + return getSuperclass().getField(name); + } + + public IField getField(Atom name, TypeName typeName) { + return getSuperclass().getField(name, typeName); + } + + /* + * @see com.ibm.wala.classLoader.IClass#getDeclaredMethods() + */ + public Collection getDeclaredMethods() { + return Collections.emptySet(); + } + + public int getNumberOfDeclaredMethods() { + return 0; + } + + /* + * @see com.ibm.wala.classLoader.IClass#getReference() + */ + public TypeReference getReference() { + return type; + } + + /* + * @see com.ibm.wala.classLoader.IClass#getSourceFileName() + */ + public String getSourceFileName() { + return null; + } + + /* + * @see com.ibm.wala.classLoader.IClass#getClassInitializer() + */ + public IMethod getClassInitializer() { + return null; + } + + /* + * @see com.ibm.wala.classLoader.IClass#isArrayClass() + */ + public boolean isArrayClass() { + return true; + } + + @Override + 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()); + } + + @Override + public int hashCode() { + return type.hashCode(); + } + + /* + * @see com.ibm.wala.classLoader.IClass#getDeclaredFields() + */ + public Collection getDeclaredInstanceFields() throws UnsupportedOperationException { + throw new UnsupportedOperationException(); + } + + /* + * @see com.ibm.wala.classLoader.IClass#getDeclaredStaticFields() + */ + public Collection getDeclaredStaticFields() throws UnimplementedError { + Assertions.UNREACHABLE(); + return null; + } + + /* + * @see com.ibm.wala.classLoader.IClass#getAllImplementedInterfaces() + */ + public Collection getAllImplementedInterfaces() { + HashSet result = HashSetFactory.make(2); + for (TypeReference ref : getClassLoader().getLanguage().getArrayInterfaces()) { + IClass klass = loader.lookupClass(ref.getName()); + if (klass != null) { + result.add(klass); + } + } + + return result; + } + + /* + * @see com.ibm.wala.classLoader.IClass#getAllAncestorInterfaces() + */ + public Collection getAllAncestorInterfaces() throws UnsupportedOperationException { + throw new UnsupportedOperationException(); + } + + /* + * @see com.ibm.wala.classLoader.IClass#isReferenceType() + */ + public boolean isReferenceType() { + return true; + } + + public int getDimensionality() { + int mask = getReference().getDerivedMask(); + if ((mask&PrimitiveMask) == PrimitiveMask) { + mask >>= ElementBits; + } + int dims = 0; + while ((mask&ArrayMask) == ArrayMask) { + mask >>= ElementBits; + dims++; + } + assert dims>0; + return dims; + } + + /** + * @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()); + } + + /* + * @see com.ibm.wala.classLoader.IClass#getDirectInterfaces() + */ + public Collection getDirectInterfaces() throws UnimplementedError { + // TODO Auto-generated method stub + Assertions.UNREACHABLE(); + return null; + } + + @Override + 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; + } + } + + /* + * @see com.ibm.wala.classLoader.IClass#getAllInstanceFields() + */ + public Collection getAllInstanceFields() { + Assertions.UNREACHABLE(); + return null; + } + + /* + * @see com.ibm.wala.classLoader.IClass#getAllStaticFields() + */ + public Collection getAllStaticFields() { + Assertions.UNREACHABLE(); + return null; + } + + /* + * @see com.ibm.wala.classLoader.IClass#getAllMethods() + */ + public Collection getAllMethods() { + return loader.lookupClass(getClassLoader().getLanguage().getRootType().getName()).getAllMethods(); + } + + /* + * @see com.ibm.wala.classLoader.IClass#getAllFields() + */ + public Collection getAllFields() { + Assertions.UNREACHABLE(); + return null; + } + + public IClassHierarchy getClassHierarchy() { + return cha; + } + + public boolean isPublic() { + return true; + } + + public boolean isPrivate() { + return false; + } + + public InputStream getSource() { + return null; + } + +} diff --git a/com.ibm.wala.core/src/com/ibm/wala/classLoader/ArrayClassLoader.java b/com.ibm.wala.core/src/com/ibm/wala/classLoader/ArrayClassLoader.java index 03edab482..1ace8aad6 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/classLoader/ArrayClassLoader.java +++ b/com.ibm.wala.core/src/com/ibm/wala/classLoader/ArrayClassLoader.java @@ -1,89 +1,89 @@ -/******************************************************************************* - * 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.ipa.cha.IClassHierarchy; -import com.ibm.wala.types.TypeName; -import com.ibm.wala.types.TypeReference; -import com.ibm.wala.util.collections.HashMapFactory; - -/** - * Pseudo-classloader for all array classes; all other IClassLoader - * implementations should delegate to this one for array classes only. - */ -public class ArrayClassLoader { - - private final static boolean DEBUG = false; - - /** - * map: TypeReference -> ArrayClass - */ - final private HashMap 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, IClassHierarchy cha) throws IllegalArgumentException { - ArrayClass arrayClass; - if (DEBUG) { - assert className.toString().startsWith("["); - } - if (delegator == null) { - throw new IllegalArgumentException("delegator must not be null"); - } - - TypeReference type = TypeReference.findOrCreate(delegator.getReference(), className); - 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,cha)); - } - } else { - arrayClass = arrayClasses.get(type); - if (arrayClass == null) { - // check that the element class is loadable. If not, return null. - IClass elementCls = delegator.lookupClass(elementType.getName()); - if (elementCls == null) { - return null; - } - - TypeReference realType = TypeReference.findOrCreateArrayOf(elementCls.getReference()); - arrayClass = arrayClasses.get(realType); - - if (arrayClass == null) { - arrayClass = new ArrayClass(realType, elementCls.getClassLoader(), cha); - } - } - arrayClasses.put(type, arrayClass); - } - return arrayClass; - } - - private static IClassLoader getRootClassLoader(IClassLoader l) { - while (l.getParent() != null) { - l = l.getParent(); - } - return l; - } - - public int getNumberOfClasses() { - return arrayClasses.size(); - } -} +/******************************************************************************* + * 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.ipa.cha.IClassHierarchy; +import com.ibm.wala.types.TypeName; +import com.ibm.wala.types.TypeReference; +import com.ibm.wala.util.collections.HashMapFactory; + +/** + * Pseudo-classloader for all array classes; all other IClassLoader + * implementations should delegate to this one for array classes only. + */ +public class ArrayClassLoader { + + private final static boolean DEBUG = false; + + /** + * map: TypeReference -> ArrayClass + */ + final private HashMap 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, IClassHierarchy cha) throws IllegalArgumentException { + ArrayClass arrayClass; + if (DEBUG) { + assert className.toString().startsWith("["); + } + if (delegator == null) { + throw new IllegalArgumentException("delegator must not be null"); + } + + TypeReference type = TypeReference.findOrCreate(delegator.getReference(), className); + 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,cha)); + } + } else { + arrayClass = arrayClasses.get(type); + if (arrayClass == null) { + // check that the element class is loadable. If not, return null. + IClass elementCls = delegator.lookupClass(elementType.getName()); + if (elementCls == null) { + return null; + } + + TypeReference realType = TypeReference.findOrCreateArrayOf(elementCls.getReference()); + arrayClass = arrayClasses.get(realType); + + if (arrayClass == null) { + arrayClass = new ArrayClass(realType, elementCls.getClassLoader(), cha); + } + } + arrayClasses.put(type, arrayClass); + } + return arrayClass; + } + + private static IClassLoader getRootClassLoader(IClassLoader l) { + while (l.getParent() != null) { + l = l.getParent(); + } + return l; + } + + public int getNumberOfClasses() { + return arrayClasses.size(); + } +} diff --git a/com.ibm.wala.core/src/com/ibm/wala/classLoader/BinaryDirectoryTreeModule.java b/com.ibm.wala.core/src/com/ibm/wala/classLoader/BinaryDirectoryTreeModule.java index fae27544e..f00d7c270 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/classLoader/BinaryDirectoryTreeModule.java +++ b/com.ibm.wala.core/src/com/ibm/wala/classLoader/BinaryDirectoryTreeModule.java @@ -1,49 +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 java.io.File; - -import com.ibm.wala.shrikeCT.InvalidClassFileException; -import com.ibm.wala.util.warnings.Warning; -import com.ibm.wala.util.warnings.Warnings; - -/** - * Module representing a directory of .class files - */ -public class BinaryDirectoryTreeModule extends DirectoryTreeModule { - - public BinaryDirectoryTreeModule(File root) { - super(root); - } - - @Override - protected boolean includeFile(File file) { - return file.getName().endsWith("class"); - } - - @Override - protected FileModule makeFile(final File file) { - try { - return new ClassFileModule(file); - } catch (InvalidClassFileException e) { - Warnings.add(new Warning(Warning.MODERATE) { - - @Override - public String getMsg() { - return "Invalid class file at path " + file.getAbsolutePath(); - } - }); - return null; - } - } - -} +/******************************************************************************* + * 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.warnings.Warning; +import com.ibm.wala.util.warnings.Warnings; + +/** + * Module representing a directory of .class files + */ +public class BinaryDirectoryTreeModule extends DirectoryTreeModule { + + public BinaryDirectoryTreeModule(File root) { + super(root); + } + + @Override + protected boolean includeFile(File file) { + return file.getName().endsWith("class"); + } + + @Override + protected FileModule makeFile(final File file) { + try { + return new ClassFileModule(file); + } catch (InvalidClassFileException e) { + Warnings.add(new Warning(Warning.MODERATE) { + + @Override + public String getMsg() { + return "Invalid class file at path " + file.getAbsolutePath(); + } + }); + return null; + } + } + +} diff --git a/com.ibm.wala.core/src/com/ibm/wala/classLoader/BytecodeClass.java b/com.ibm.wala.core/src/com/ibm/wala/classLoader/BytecodeClass.java index 36d81c985..548fc9b5b 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/classLoader/BytecodeClass.java +++ b/com.ibm.wala.core/src/com/ibm/wala/classLoader/BytecodeClass.java @@ -1,566 +1,566 @@ -/******************************************************************************* - * Copyright (c) 2007 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.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.ClassHierarchyWarning; -import com.ibm.wala.ipa.cha.IClassHierarchy; -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.types.annotations.Annotation; -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.strings.Atom; -import com.ibm.wala.util.strings.ImmutableByteArray; -import com.ibm.wala.util.warnings.Warning; -import com.ibm.wala.util.warnings.Warnings; - -/** - * A class representing which originates in some form of bytecode. - * - * @param type of classloader which loads this format of class. - */ -public abstract class BytecodeClass implements IClass { - - protected BytecodeClass(T loader, IClassHierarchy cha) { - this.loader = loader; - this.cha = cha; - } - - /** - * An Atom which holds the name of the super class. We cache this for efficiency reasons. - */ - protected ImmutableByteArray superName; - - /** - * The names of interfaces for this class. We cache this for efficiency reasons. - */ - protected ImmutableByteArray[] interfaceNames; - - /** - * The object that loaded this class. - */ - protected final T loader; - - /** - * Governing class hierarchy for this class - */ - protected final IClassHierarchy cha; - - /** - * A mapping from Selector to IMethod - * - * TODO: get rid of this for classes (though keep it for interfaces) instead ... use a VMT. - */ - protected Map methodMap; - - /** - * A mapping from Selector to IMethod used to cache method lookups from superclasses - */ - protected Map inheritCache; - - /** - * Canonical type representation - */ - protected TypeReference typeReference; - - /** - * superclass - */ - protected IClass superClass; - - /** - * Compute the superclass lazily. - */ - protected boolean superclassComputed = false; - - /** - * The IClasses that represent all interfaces this class implements (if it's a class) or extends (it it's an interface) - */ - protected Collection allInterfaces = null; - - /** - * The instance fields declared in this class. - */ - protected IField[] instanceFields; - - /** - * The static fields declared in this class. - */ - protected IField[] staticFields; - - /** - * hash code; cached here for efficiency - */ - protected int hashCode; - - private final HashMap fieldMap = HashMapFactory.make(5); - - /** - * 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; - } - - @Override - public String getMsg() { - return getClass().toString() + " : " + className; - } - - public static ClassNotFoundWarning create(ImmutableByteArray className) { - return new ClassNotFoundWarning(className); - } - } - - public IClassLoader getClassLoader() { - return loader; - } - - protected abstract IMethod[] computeDeclaredMethods() throws InvalidClassFileException; - - public TypeReference getReference() { - return typeReference; - } - - public String getSourceFileName() { - return loader.getSourceFileName(this); - } - - public InputStream getSource() { - return loader.getSource(this); - } - - @Override - public int hashCode() { - return hashCode; - } - - @Override - public String toString() { - return getReference().toString(); - } - - public boolean isArrayClass() { - return false; - } - - public IClassHierarchy getClassHierarchy() { - return cha; - } - - public TypeName getName() { - return getReference().getName(); - } - - public boolean isReferenceType() { - return getReference().isReferenceType(); - } - - public IField getField(Atom name) { - if (fieldMap.containsKey(name)) { - return fieldMap.get(name); - } else { - List fields = findDeclaredField(name); - if (!fields.isEmpty()) { - if (fields.size() == 1) { - IField f = fields.iterator().next(); - fieldMap.put(name, f); - return f; - } else { - throw new IllegalStateException("multiple fields with name " + name); - } - } else if ((superClass = getSuperclass()) != null) { - IField f = superClass.getField(name); - if (f != null) { - fieldMap.put(name, f); - return f; - } - } - // try superinterfaces - for (IClass i : getAllImplementedInterfaces()) { - IField f = i.getField(name); - if (f != null) { - fieldMap.put(name, f); - return f; - } - } - } - - return null; - } - - - public IField getField(Atom name, TypeName type) { - try { - // typically, there will be at most one field with the name - IField field = getField(name); - if (field != null && field.getFieldTypeReference().getName().equals(type)) { - return field; - } else { - return null; - } - } catch (IllegalStateException e) { - assert e.getMessage().startsWith("multiple fields with"); - // multiple fields. look through all of them and see if any have the appropriate type - List fields = findDeclaredField(name); - for (IField f : fields) { - if (f.getFieldTypeReference().getName().equals(type)) { - return f; - } - } - // check superclass - if (getSuperclass() != null) { - IField f = superClass.getField(name, type); - if (f != null) { - return f; - } - } - // try superinterfaces - for (IClass i : getAllImplementedInterfaces()) { - IField f = i.getField(name, type); - if (f != null) { - return f; - } - } - } - return null; - } - - private void computeSuperclass() { - superclassComputed = true; - - if (superName == null) { - if (!getReference().equals(loader.getLanguage().getRootType())) { - superClass = loader.lookupClass(loader.getLanguage().getRootType().getName()); - } - return; - } - - superClass = loader.lookupClass(TypeName.findOrCreate(superName)); - } - - public IClass getSuperclass() { - if (!superclassComputed) { - computeSuperclass(); - } - if (superClass == null && !getReference().equals(TypeReference.JavaLangObject)) { - throw new IllegalStateException("No superclass found for " + this + " Superclass name " + superName); - } - return superClass; - } - - /* - * @see com.ibm.wala.classLoader.IClass#getAllFields() - */ - public Collection getAllFields() { - Collection result = new LinkedList(); - result.addAll(getAllInstanceFields()); - result.addAll(getAllStaticFields()); - return result; - } - - /* - * @see com.ibm.wala.classLoader.IClass#getAllImplementedInterfaces() - */ - public Collection getAllImplementedInterfaces() { - if (allInterfaces != null) { - return allInterfaces; - } else { - Collection C = computeAllInterfacesAsCollection(); - allInterfaces = Collections.unmodifiableCollection(C); - return allInterfaces; - } - } - - /* - * @see com.ibm.wala.classLoader.IClass#getDeclaredFields() - */ - public Collection getDeclaredInstanceFields() { - return Collections.unmodifiableList(Arrays.asList(instanceFields)); - } - - /* - * @see com.ibm.wala.classLoader.IClass#getDeclaredFields() - */ - public Collection getDeclaredStaticFields() { - return Collections.unmodifiableList(Arrays.asList(staticFields)); - } - - /* - * @see com.ibm.wala.classLoader.IClass#getDirectInterfaces() - */ - public Collection getDirectInterfaces() { - return array2IClassSet(interfaceNames); - } - - /* - * @see com.ibm.wala.classLoader.IClass#getAllInstanceFields() - */ - public Collection getAllInstanceFields() { - Collection result = new LinkedList(getDeclaredInstanceFields()); - IClass s = getSuperclass(); - while (s != null) { - result.addAll(s.getDeclaredInstanceFields()); - s = s.getSuperclass(); - } - return result; - } - - /* - * @see com.ibm.wala.classLoader.IClass#getAllStaticFields() - */ - public Collection getAllStaticFields() { - Collection result = new LinkedList(getDeclaredStaticFields()); - IClass s = getSuperclass(); - while (s != null) { - result.addAll(s.getDeclaredStaticFields()); - s = s.getSuperclass(); - } - return result; - } - - /* - * @see com.ibm.wala.classLoader.IClass#getAllMethods() - */ - public Collection getAllMethods() { - Collection result = new LinkedList(); - Iterator declaredMethods = getDeclaredMethods().iterator(); - while (declaredMethods.hasNext()) { - result.add(declaredMethods.next()); - } - if (isInterface()) { - for (IClass i : getDirectInterfaces()) { - result.addAll(i.getAllMethods()); - } - } - IClass s = getSuperclass(); - while (s != null) { - Iterator superDeclaredMethods = s.getDeclaredMethods().iterator(); - while (superDeclaredMethods.hasNext()) { - result.add(superDeclaredMethods.next()); - } - s = s.getSuperclass(); - } - return result; - } - - /* - * @see com.ibm.wala.classLoader.IClass#getDeclaredMethods() - */ - public Collection getDeclaredMethods() { - if (methodMap == null) { - try { - computeMethodMap(); - } catch (InvalidClassFileException e) { - e.printStackTrace(); - Assertions.UNREACHABLE(); - } - } - return Collections.unmodifiableCollection(methodMap.values()); - } - - /* - * @see com.ibm.wala.classLoader.IClass#getMethod(com.ibm.wala.types.Selector) - */ - public IMethod getMethod(Selector selector) { - if (methodMap == null) { - try { - computeMethodMap(); - } catch (InvalidClassFileException e1) { - e1.printStackTrace(); - Assertions.UNREACHABLE(); - } - } - - // my methods + cached parent stuff - IMethod result = 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 - if (!selector.equals(MethodReference.clinitSelector) && !selector.equals(MethodReference.initSelector)) { - IClass superclass = getSuperclass(); - if (superclass != null) { - IMethod inherit = superclass.getMethod(selector); - if (inherit != null) { - if (inheritCache == null) { - inheritCache = new BimodalMap(5); - } - inheritCache.put(selector, inherit); - return inherit; - } - } - } - - // didn't find it yet. special logic for interfaces - if (isInterface() || isAbstract()) { - final Iterator it = getAllImplementedInterfaces().iterator(); - // try each superinterface - while (it.hasNext()) { - IClass k = it.next(); - result = k.getMethod(selector); - if (result != null) { - return result; - } - } - } - return null; - - } - - protected void populateFieldArrayFromList(List L, IField[] A) { - Iterator it = L.iterator(); - for (int i = 0; i < A.length; i++) { - A[i] = it.next(); - } - } - - /** - * @return Collection of IClasses, representing the interfaces this class implements. - */ - protected Collection computeAllInterfacesAsCollection() { - Collection c = getDirectInterfaces(); - Set result = HashSetFactory.make(); - for (Iterator it = c.iterator(); it.hasNext();) { - IClass klass = it.next(); - if (klass.isInterface()) { - result.add(klass); - } else { - Warnings.add(ClassHierarchyWarning.create("expected an interface " + klass)); - } - } - - // at this point result holds all interfaces the class directly extends. - // now expand to a fixed point. - Set last = null; - do { - last = HashSetFactory.make(result); - for (IClass i : last) { - result.addAll(i.getDirectInterfaces()); - } - } while (last.size() < result.size()); - - // now add any interfaces implemented by the super class - IClass sup = null; - sup = getSuperclass(); - if (sup != null) { - result.addAll(sup.getAllImplementedInterfaces()); - } - return result; - } - - /** - * @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 array2IClassSet(ImmutableByteArray[] interfaces) { - ArrayList result = new ArrayList(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; - } - - protected List findDeclaredField(Atom name) { - - List result = new ArrayList(1); - - if (instanceFields != null) { - for (int i = 0; i < instanceFields.length; i++) { - if (instanceFields[i].getName() == name) { - result.add(instanceFields[i]); - } - } - } - - if (staticFields != null) { - for (int i = 0; i < staticFields.length; i++) { - if (staticFields[i].getName() == name) { - result.add(staticFields[i]); - } - } - } - - return result; - } - - protected void addFieldToList(List L, Atom name, ImmutableByteArray fieldType, int accessFlags, - Collection annotations) { - 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, annotations); - L.add(f); - } - - /** - * set up the methodMap mapping - */ - protected void computeMethodMap() throws InvalidClassFileException { - if (methodMap == null) { - IMethod[] methods = computeDeclaredMethods(); - if (methods.length > 5) { - methodMap = HashMapFactory.make(methods.length); - } else { - methodMap = new SmallMap(); - } - for (int i = 0; i < methods.length; i++) { - IMethod m = methods[i]; - methodMap.put(m.getReference().getSelector(), m); - } - } - } - -} +/******************************************************************************* + * Copyright (c) 2007 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.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.ClassHierarchyWarning; +import com.ibm.wala.ipa.cha.IClassHierarchy; +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.types.annotations.Annotation; +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.strings.Atom; +import com.ibm.wala.util.strings.ImmutableByteArray; +import com.ibm.wala.util.warnings.Warning; +import com.ibm.wala.util.warnings.Warnings; + +/** + * A class representing which originates in some form of bytecode. + * + * @param type of classloader which loads this format of class. + */ +public abstract class BytecodeClass implements IClass { + + protected BytecodeClass(T loader, IClassHierarchy cha) { + this.loader = loader; + this.cha = cha; + } + + /** + * An Atom which holds the name of the super class. We cache this for efficiency reasons. + */ + protected ImmutableByteArray superName; + + /** + * The names of interfaces for this class. We cache this for efficiency reasons. + */ + protected ImmutableByteArray[] interfaceNames; + + /** + * The object that loaded this class. + */ + protected final T loader; + + /** + * Governing class hierarchy for this class + */ + protected final IClassHierarchy cha; + + /** + * A mapping from Selector to IMethod + * + * TODO: get rid of this for classes (though keep it for interfaces) instead ... use a VMT. + */ + protected Map methodMap; + + /** + * A mapping from Selector to IMethod used to cache method lookups from superclasses + */ + protected Map inheritCache; + + /** + * Canonical type representation + */ + protected TypeReference typeReference; + + /** + * superclass + */ + protected IClass superClass; + + /** + * Compute the superclass lazily. + */ + protected boolean superclassComputed = false; + + /** + * The IClasses that represent all interfaces this class implements (if it's a class) or extends (it it's an interface) + */ + protected Collection allInterfaces = null; + + /** + * The instance fields declared in this class. + */ + protected IField[] instanceFields; + + /** + * The static fields declared in this class. + */ + protected IField[] staticFields; + + /** + * hash code; cached here for efficiency + */ + protected int hashCode; + + private final HashMap fieldMap = HashMapFactory.make(5); + + /** + * 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; + } + + @Override + public String getMsg() { + return getClass().toString() + " : " + className; + } + + public static ClassNotFoundWarning create(ImmutableByteArray className) { + return new ClassNotFoundWarning(className); + } + } + + public IClassLoader getClassLoader() { + return loader; + } + + protected abstract IMethod[] computeDeclaredMethods() throws InvalidClassFileException; + + public TypeReference getReference() { + return typeReference; + } + + public String getSourceFileName() { + return loader.getSourceFileName(this); + } + + public InputStream getSource() { + return loader.getSource(this); + } + + @Override + public int hashCode() { + return hashCode; + } + + @Override + public String toString() { + return getReference().toString(); + } + + public boolean isArrayClass() { + return false; + } + + public IClassHierarchy getClassHierarchy() { + return cha; + } + + public TypeName getName() { + return getReference().getName(); + } + + public boolean isReferenceType() { + return getReference().isReferenceType(); + } + + public IField getField(Atom name) { + if (fieldMap.containsKey(name)) { + return fieldMap.get(name); + } else { + List fields = findDeclaredField(name); + if (!fields.isEmpty()) { + if (fields.size() == 1) { + IField f = fields.iterator().next(); + fieldMap.put(name, f); + return f; + } else { + throw new IllegalStateException("multiple fields with name " + name); + } + } else if ((superClass = getSuperclass()) != null) { + IField f = superClass.getField(name); + if (f != null) { + fieldMap.put(name, f); + return f; + } + } + // try superinterfaces + for (IClass i : getAllImplementedInterfaces()) { + IField f = i.getField(name); + if (f != null) { + fieldMap.put(name, f); + return f; + } + } + } + + return null; + } + + + public IField getField(Atom name, TypeName type) { + try { + // typically, there will be at most one field with the name + IField field = getField(name); + if (field != null && field.getFieldTypeReference().getName().equals(type)) { + return field; + } else { + return null; + } + } catch (IllegalStateException e) { + assert e.getMessage().startsWith("multiple fields with"); + // multiple fields. look through all of them and see if any have the appropriate type + List fields = findDeclaredField(name); + for (IField f : fields) { + if (f.getFieldTypeReference().getName().equals(type)) { + return f; + } + } + // check superclass + if (getSuperclass() != null) { + IField f = superClass.getField(name, type); + if (f != null) { + return f; + } + } + // try superinterfaces + for (IClass i : getAllImplementedInterfaces()) { + IField f = i.getField(name, type); + if (f != null) { + return f; + } + } + } + return null; + } + + private void computeSuperclass() { + superclassComputed = true; + + if (superName == null) { + if (!getReference().equals(loader.getLanguage().getRootType())) { + superClass = loader.lookupClass(loader.getLanguage().getRootType().getName()); + } + return; + } + + superClass = loader.lookupClass(TypeName.findOrCreate(superName)); + } + + public IClass getSuperclass() { + if (!superclassComputed) { + computeSuperclass(); + } + if (superClass == null && !getReference().equals(TypeReference.JavaLangObject)) { + throw new IllegalStateException("No superclass found for " + this + " Superclass name " + superName); + } + return superClass; + } + + /* + * @see com.ibm.wala.classLoader.IClass#getAllFields() + */ + public Collection getAllFields() { + Collection result = new LinkedList(); + result.addAll(getAllInstanceFields()); + result.addAll(getAllStaticFields()); + return result; + } + + /* + * @see com.ibm.wala.classLoader.IClass#getAllImplementedInterfaces() + */ + public Collection getAllImplementedInterfaces() { + if (allInterfaces != null) { + return allInterfaces; + } else { + Collection C = computeAllInterfacesAsCollection(); + allInterfaces = Collections.unmodifiableCollection(C); + return allInterfaces; + } + } + + /* + * @see com.ibm.wala.classLoader.IClass#getDeclaredFields() + */ + public Collection getDeclaredInstanceFields() { + return Collections.unmodifiableList(Arrays.asList(instanceFields)); + } + + /* + * @see com.ibm.wala.classLoader.IClass#getDeclaredFields() + */ + public Collection getDeclaredStaticFields() { + return Collections.unmodifiableList(Arrays.asList(staticFields)); + } + + /* + * @see com.ibm.wala.classLoader.IClass#getDirectInterfaces() + */ + public Collection getDirectInterfaces() { + return array2IClassSet(interfaceNames); + } + + /* + * @see com.ibm.wala.classLoader.IClass#getAllInstanceFields() + */ + public Collection getAllInstanceFields() { + Collection result = new LinkedList(getDeclaredInstanceFields()); + IClass s = getSuperclass(); + while (s != null) { + result.addAll(s.getDeclaredInstanceFields()); + s = s.getSuperclass(); + } + return result; + } + + /* + * @see com.ibm.wala.classLoader.IClass#getAllStaticFields() + */ + public Collection getAllStaticFields() { + Collection result = new LinkedList(getDeclaredStaticFields()); + IClass s = getSuperclass(); + while (s != null) { + result.addAll(s.getDeclaredStaticFields()); + s = s.getSuperclass(); + } + return result; + } + + /* + * @see com.ibm.wala.classLoader.IClass#getAllMethods() + */ + public Collection getAllMethods() { + Collection result = new LinkedList(); + Iterator declaredMethods = getDeclaredMethods().iterator(); + while (declaredMethods.hasNext()) { + result.add(declaredMethods.next()); + } + if (isInterface()) { + for (IClass i : getDirectInterfaces()) { + result.addAll(i.getAllMethods()); + } + } + IClass s = getSuperclass(); + while (s != null) { + Iterator superDeclaredMethods = s.getDeclaredMethods().iterator(); + while (superDeclaredMethods.hasNext()) { + result.add(superDeclaredMethods.next()); + } + s = s.getSuperclass(); + } + return result; + } + + /* + * @see com.ibm.wala.classLoader.IClass#getDeclaredMethods() + */ + public Collection getDeclaredMethods() { + if (methodMap == null) { + try { + computeMethodMap(); + } catch (InvalidClassFileException e) { + e.printStackTrace(); + Assertions.UNREACHABLE(); + } + } + return Collections.unmodifiableCollection(methodMap.values()); + } + + /* + * @see com.ibm.wala.classLoader.IClass#getMethod(com.ibm.wala.types.Selector) + */ + public IMethod getMethod(Selector selector) { + if (methodMap == null) { + try { + computeMethodMap(); + } catch (InvalidClassFileException e1) { + e1.printStackTrace(); + Assertions.UNREACHABLE(); + } + } + + // my methods + cached parent stuff + IMethod result = 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 + if (!selector.equals(MethodReference.clinitSelector) && !selector.equals(MethodReference.initSelector)) { + IClass superclass = getSuperclass(); + if (superclass != null) { + IMethod inherit = superclass.getMethod(selector); + if (inherit != null) { + if (inheritCache == null) { + inheritCache = new BimodalMap(5); + } + inheritCache.put(selector, inherit); + return inherit; + } + } + } + + // didn't find it yet. special logic for interfaces + if (isInterface() || isAbstract()) { + final Iterator it = getAllImplementedInterfaces().iterator(); + // try each superinterface + while (it.hasNext()) { + IClass k = it.next(); + result = k.getMethod(selector); + if (result != null) { + return result; + } + } + } + return null; + + } + + protected void populateFieldArrayFromList(List L, IField[] A) { + Iterator it = L.iterator(); + for (int i = 0; i < A.length; i++) { + A[i] = it.next(); + } + } + + /** + * @return Collection of IClasses, representing the interfaces this class implements. + */ + protected Collection computeAllInterfacesAsCollection() { + Collection c = getDirectInterfaces(); + Set result = HashSetFactory.make(); + for (Iterator it = c.iterator(); it.hasNext();) { + IClass klass = it.next(); + if (klass.isInterface()) { + result.add(klass); + } else { + Warnings.add(ClassHierarchyWarning.create("expected an interface " + klass)); + } + } + + // at this point result holds all interfaces the class directly extends. + // now expand to a fixed point. + Set last = null; + do { + last = HashSetFactory.make(result); + for (IClass i : last) { + result.addAll(i.getDirectInterfaces()); + } + } while (last.size() < result.size()); + + // now add any interfaces implemented by the super class + IClass sup = null; + sup = getSuperclass(); + if (sup != null) { + result.addAll(sup.getAllImplementedInterfaces()); + } + return result; + } + + /** + * @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 array2IClassSet(ImmutableByteArray[] interfaces) { + ArrayList result = new ArrayList(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; + } + + protected List findDeclaredField(Atom name) { + + List result = new ArrayList(1); + + if (instanceFields != null) { + for (int i = 0; i < instanceFields.length; i++) { + if (instanceFields[i].getName() == name) { + result.add(instanceFields[i]); + } + } + } + + if (staticFields != null) { + for (int i = 0; i < staticFields.length; i++) { + if (staticFields[i].getName() == name) { + result.add(staticFields[i]); + } + } + } + + return result; + } + + protected void addFieldToList(List L, Atom name, ImmutableByteArray fieldType, int accessFlags, + Collection annotations) { + 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, annotations); + L.add(f); + } + + /** + * set up the methodMap mapping + */ + protected void computeMethodMap() throws InvalidClassFileException { + if (methodMap == null) { + IMethod[] methods = computeDeclaredMethods(); + if (methods.length > 5) { + methodMap = HashMapFactory.make(methods.length); + } else { + methodMap = new SmallMap(); + } + for (int i = 0; i < methods.length; i++) { + IMethod m = methods[i]; + methodMap.put(m.getReference().getSelector(), m); + } + } + } + +} diff --git a/com.ibm.wala.core/src/com/ibm/wala/classLoader/CallSiteReference.java b/com.ibm.wala.core/src/com/ibm/wala/classLoader/CallSiteReference.java index 3e5ef89e0..713459ae5 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/classLoader/CallSiteReference.java +++ b/com.ibm.wala.core/src/com/ibm/wala/classLoader/CallSiteReference.java @@ -1,207 +1,207 @@ -/******************************************************************************* - * 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.CGNode; -import com.ibm.wala.ipa.callgraph.ContextItem; -import com.ibm.wala.shrikeBT.BytecodeConstants; -import com.ibm.wala.shrikeBT.IInvokeInstruction; -import com.ibm.wala.ssa.IR; -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) - * - * Note that the identity of a call site reference depends on two things: the program counter, and the containing IR. Thus, it - * suffices to define equals() and hashCode() from {@link ProgramCounter}, since this class does not maintain a pointer to the - * containing {@link IR} (or {@link CGNode}) anyway. If using a hashtable of CallSiteReference from different IRs, you probably want - * to use a wrapper which also holds a pointer to the governing CGNode. - */ -public abstract class CallSiteReference extends ProgramCounter implements BytecodeConstants, ContextItem { - - final private MethodReference declaredTarget; - - /** - * @param programCounter Index into bytecode describing this instruction - * @param declaredTarget The method target as declared at the call site - */ - protected CallSiteReference(int programCounter, MethodReference declaredTarget) { - super(programCounter); - this.declaredTarget = declaredTarget; - } - - @Override - public int hashCode() { - final int prime = 31; - int result = super.hashCode(); - result = prime * result + ((declaredTarget == null) ? 0 : declaredTarget.hashCode()); - return result; - } - - @Override - public boolean equals(Object obj) { - if (this == obj) - return true; - if (!super.equals(obj)) - return false; - if (getClass() != obj.getClass()) - return false; - CallSiteReference other = (CallSiteReference) obj; - if (declaredTarget == null) { - if (other.declaredTarget != null) - return false; - } else if (!declaredTarget.equals(other.declaredTarget)) - return false; - return true; - } - - // 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); - } - - @Override - public IInvokeInstruction.IDispatch getInvocationCode() { - return IInvokeInstruction.Dispatch.STATIC; - } - } - - static class SpecialCall extends CallSiteReference { - SpecialCall(int programCounter, MethodReference declaredTarget) { - super(programCounter, declaredTarget); - } - - @Override - public IInvokeInstruction.IDispatch getInvocationCode() { - return IInvokeInstruction.Dispatch.SPECIAL; - } - } - - static class VirtualCall extends CallSiteReference { - VirtualCall(int programCounter, MethodReference declaredTarget) { - super(programCounter, declaredTarget); - } - - @Override - public IInvokeInstruction.IDispatch getInvocationCode() { - return IInvokeInstruction.Dispatch.VIRTUAL; - } - } - - static class InterfaceCall extends CallSiteReference { - InterfaceCall(int programCounter, MethodReference declaredTarget) { - super(programCounter, declaredTarget); - } - - @Override - 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); - - throw new IllegalArgumentException("unsupported code: " + invocationCode); - } - - /** - * 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(); - - @Override - public String toString() { - return "invoke" + getInvocationString(getInvocationCode()) + " " + declaredTarget + "@" + getProgramCounter(); - } - - 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(); - } - -} +/******************************************************************************* + * 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.CGNode; +import com.ibm.wala.ipa.callgraph.ContextItem; +import com.ibm.wala.shrikeBT.BytecodeConstants; +import com.ibm.wala.shrikeBT.IInvokeInstruction; +import com.ibm.wala.ssa.IR; +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) + * + * Note that the identity of a call site reference depends on two things: the program counter, and the containing IR. Thus, it + * suffices to define equals() and hashCode() from {@link ProgramCounter}, since this class does not maintain a pointer to the + * containing {@link IR} (or {@link CGNode}) anyway. If using a hashtable of CallSiteReference from different IRs, you probably want + * to use a wrapper which also holds a pointer to the governing CGNode. + */ +public abstract class CallSiteReference extends ProgramCounter implements BytecodeConstants, ContextItem { + + final private MethodReference declaredTarget; + + /** + * @param programCounter Index into bytecode describing this instruction + * @param declaredTarget The method target as declared at the call site + */ + protected CallSiteReference(int programCounter, MethodReference declaredTarget) { + super(programCounter); + this.declaredTarget = declaredTarget; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = super.hashCode(); + result = prime * result + ((declaredTarget == null) ? 0 : declaredTarget.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (!super.equals(obj)) + return false; + if (getClass() != obj.getClass()) + return false; + CallSiteReference other = (CallSiteReference) obj; + if (declaredTarget == null) { + if (other.declaredTarget != null) + return false; + } else if (!declaredTarget.equals(other.declaredTarget)) + return false; + return true; + } + + // 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); + } + + @Override + public IInvokeInstruction.IDispatch getInvocationCode() { + return IInvokeInstruction.Dispatch.STATIC; + } + } + + static class SpecialCall extends CallSiteReference { + SpecialCall(int programCounter, MethodReference declaredTarget) { + super(programCounter, declaredTarget); + } + + @Override + public IInvokeInstruction.IDispatch getInvocationCode() { + return IInvokeInstruction.Dispatch.SPECIAL; + } + } + + static class VirtualCall extends CallSiteReference { + VirtualCall(int programCounter, MethodReference declaredTarget) { + super(programCounter, declaredTarget); + } + + @Override + public IInvokeInstruction.IDispatch getInvocationCode() { + return IInvokeInstruction.Dispatch.VIRTUAL; + } + } + + static class InterfaceCall extends CallSiteReference { + InterfaceCall(int programCounter, MethodReference declaredTarget) { + super(programCounter, declaredTarget); + } + + @Override + 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); + + throw new IllegalArgumentException("unsupported code: " + invocationCode); + } + + /** + * 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(); + + @Override + public String toString() { + return "invoke" + getInvocationString(getInvocationCode()) + " " + declaredTarget + "@" + getProgramCounter(); + } + + 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(); + } + +} diff --git a/com.ibm.wala.core/src/com/ibm/wala/classLoader/ClassFileModule.java b/com.ibm.wala.core/src/com/ibm/wala/classLoader/ClassFileModule.java index 46d1de63e..901fcf3fe 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/classLoader/ClassFileModule.java +++ b/com.ibm.wala.core/src/com/ibm/wala/classLoader/ClassFileModule.java @@ -1,51 +1,51 @@ -/******************************************************************************* - * Copyright (c) 2002 - 2006 IBM Corporation. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * IBM Corporation - initial API and implementation - *******************************************************************************/ - -package com.ibm.wala.classLoader; - -import java.io.File; - -import com.ibm.wala.shrikeCT.InvalidClassFileException; -import com.ibm.wala.util.shrike.ShrikeClassReaderHandle; -import com.ibm.wala.util.strings.ImmutableByteArray; - -/** - * A module which is a wrapper around a .class file - */ -public class ClassFileModule extends FileModule { - - private final String className; - - public ClassFileModule(File f) throws InvalidClassFileException { - super(f); - ShrikeClassReaderHandle reader = new ShrikeClassReaderHandle(this); - ImmutableByteArray name = ImmutableByteArray.make(reader.get().getName()); - className = name.toString(); - } - - - @Override - public String toString() { - return "ClassFileModule:" + getFile(); - } - - public boolean isClassFile() { - return true; - } - - public String getClassName() { - return className; - } - - public boolean isSourceFile() { - return false; - } -} +/******************************************************************************* + * 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.shrike.ShrikeClassReaderHandle; +import com.ibm.wala.util.strings.ImmutableByteArray; + +/** + * A module which is a wrapper around a .class file + */ +public class ClassFileModule extends FileModule { + + private final String className; + + public ClassFileModule(File f) throws InvalidClassFileException { + super(f); + ShrikeClassReaderHandle reader = new ShrikeClassReaderHandle(this); + ImmutableByteArray name = ImmutableByteArray.make(reader.get().getName()); + className = name.toString(); + } + + + @Override + public String toString() { + return "ClassFileModule:" + getFile(); + } + + public boolean isClassFile() { + return true; + } + + public String getClassName() { + return className; + } + + public boolean isSourceFile() { + return false; + } +} diff --git a/com.ibm.wala.core/src/com/ibm/wala/classLoader/ClassLoaderFactory.java b/com.ibm.wala.core/src/com/ibm/wala/classLoader/ClassLoaderFactory.java index 04c83486a..1b92fecfc 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/classLoader/ClassLoaderFactory.java +++ b/com.ibm.wala.core/src/com/ibm/wala/classLoader/ClassLoaderFactory.java @@ -1,32 +1,32 @@ -/******************************************************************************* - * 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.IClassHierarchy; -import com.ibm.wala.types.ClassLoaderReference; - -/** - */ -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, IClassHierarchy cha, AnalysisScope scope) - throws IOException; -} +/******************************************************************************* + * 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.IClassHierarchy; +import com.ibm.wala.types.ClassLoaderReference; + +/** + */ +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, IClassHierarchy cha, AnalysisScope scope) + throws IOException; +} diff --git a/com.ibm.wala.core/src/com/ibm/wala/classLoader/ClassLoaderFactoryImpl.java b/com.ibm.wala.core/src/com/ibm/wala/classLoader/ClassLoaderFactoryImpl.java index e0785bf55..8e01d26a3 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/classLoader/ClassLoaderFactoryImpl.java +++ b/com.ibm.wala.core/src/com/ibm/wala/classLoader/ClassLoaderFactoryImpl.java @@ -1,146 +1,146 @@ -/******************************************************************************* - * 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.IClassHierarchy; -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.Warnings; - -/** - * 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. - */ - final private SetOfClasses exclusions; - - /** - * A Mapping from ClassLoaderReference to IClassLoader - */ - final private HashMap map = HashMapFactory.make(3); - - /** - * @param exclusions - * A set of classes that class loaders should pretend don't exist. - */ - public ClassLoaderFactoryImpl(SetOfClasses exclusions) { - this.exclusions = exclusions; - } - - /** - * Return a class loader corresponding to a given class loader identifier. - * Create one if necessary. - * - * @param classLoaderReference - * identifier for the desired class loader - */ - public IClassLoader getLoader(ClassLoaderReference classLoaderReference, IClassHierarchy cha, AnalysisScope scope) - throws IOException { - if (classLoaderReference == null) { - throw new IllegalArgumentException("null classLoaderReference"); - } - 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, IClassHierarchy 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, cha); - } else - try { - // this is fragile. why are we doing things this way again? - Class impl = Class.forName(implClass); - Constructor ctor = impl.getDeclaredConstructor(new Class[] { ClassLoaderReference.class, IClassLoader.class, - SetOfClasses.class, IClassHierarchy.class }); - cl = (IClassLoader) ctor.newInstance(new Object[] { classLoaderReference, parent, exclusions, cha }); - } catch (Exception e) { - try { - Class impl = Class.forName(implClass); - Constructor ctor = impl.getDeclaredConstructor(new Class[] { ClassLoaderReference.class, ArrayClassLoader.class, - IClassLoader.class, SetOfClasses.class, IClassHierarchy.class }); - cl = (IClassLoader) ctor.newInstance(new Object[] { classLoaderReference, scope.getArrayClassLoader(), parent, - exclusions, cha }); - } catch (Exception e2) { - System.err.println("failed to load impl class " + implClass); - e2.printStackTrace(System.err); - Warnings.add(InvalidClassLoaderImplementation.create(implClass)); - cl = new ClassLoaderImpl(classLoaderReference, scope.getArrayClassLoader(), parent, exclusions, cha); - } - } - cl.init(scope.getModules(classLoaderReference)); - return cl; - } - - /** - * 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; - } - - @Override - 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; - } -} +/******************************************************************************* + * 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.IClassHierarchy; +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.Warnings; + +/** + * 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. + */ + final private SetOfClasses exclusions; + + /** + * A Mapping from ClassLoaderReference to IClassLoader + */ + final private HashMap map = HashMapFactory.make(3); + + /** + * @param exclusions + * A set of classes that class loaders should pretend don't exist. + */ + public ClassLoaderFactoryImpl(SetOfClasses exclusions) { + this.exclusions = exclusions; + } + + /** + * Return a class loader corresponding to a given class loader identifier. + * Create one if necessary. + * + * @param classLoaderReference + * identifier for the desired class loader + */ + public IClassLoader getLoader(ClassLoaderReference classLoaderReference, IClassHierarchy cha, AnalysisScope scope) + throws IOException { + if (classLoaderReference == null) { + throw new IllegalArgumentException("null classLoaderReference"); + } + 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, IClassHierarchy 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, cha); + } else + try { + // this is fragile. why are we doing things this way again? + Class impl = Class.forName(implClass); + Constructor ctor = impl.getDeclaredConstructor(new Class[] { ClassLoaderReference.class, IClassLoader.class, + SetOfClasses.class, IClassHierarchy.class }); + cl = (IClassLoader) ctor.newInstance(new Object[] { classLoaderReference, parent, exclusions, cha }); + } catch (Exception e) { + try { + Class impl = Class.forName(implClass); + Constructor ctor = impl.getDeclaredConstructor(new Class[] { ClassLoaderReference.class, ArrayClassLoader.class, + IClassLoader.class, SetOfClasses.class, IClassHierarchy.class }); + cl = (IClassLoader) ctor.newInstance(new Object[] { classLoaderReference, scope.getArrayClassLoader(), parent, + exclusions, cha }); + } catch (Exception e2) { + System.err.println("failed to load impl class " + implClass); + e2.printStackTrace(System.err); + Warnings.add(InvalidClassLoaderImplementation.create(implClass)); + cl = new ClassLoaderImpl(classLoaderReference, scope.getArrayClassLoader(), parent, exclusions, cha); + } + } + cl.init(scope.getModules(classLoaderReference)); + return cl; + } + + /** + * 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; + } + + @Override + 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; + } +} diff --git a/com.ibm.wala.core/src/com/ibm/wala/classLoader/ClassLoaderImpl.java b/com.ibm.wala.core/src/com/ibm/wala/classLoader/ClassLoaderImpl.java index aae02f476..c0715a634 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/classLoader/ClassLoaderImpl.java +++ b/com.ibm.wala.core/src/com/ibm/wala/classLoader/ClassLoaderImpl.java @@ -1,655 +1,655 @@ -/******************************************************************************* - * 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.BufferedInputStream; -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.File; -import java.io.FileInputStream; -import java.io.IOException; -import java.io.InputStream; -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 java.util.TreeSet; -import java.util.jar.JarEntry; -import java.util.jar.JarInputStream; - -import com.ibm.wala.ipa.callgraph.impl.SetOfClasses; -import com.ibm.wala.ipa.cha.IClassHierarchy; -import com.ibm.wala.shrikeCT.ClassReader; -import com.ibm.wala.shrikeCT.InvalidClassFileException; -import com.ibm.wala.ssa.SSAInstructionFactory; -import com.ibm.wala.types.ClassLoaderReference; -import com.ibm.wala.types.TypeName; -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.Iterator2Iterable; -import com.ibm.wala.util.io.FileProvider; -import com.ibm.wala.util.io.FileSuffixes; -import com.ibm.wala.util.shrike.ShrikeClassReaderHandle; -import com.ibm.wala.util.strings.Atom; -import com.ibm.wala.util.warnings.Warning; -import com.ibm.wala.util.warnings.Warnings; - -/** - * A class loader that reads class definitions from a set of Modules. - */ -public class ClassLoaderImpl implements IClassLoader { - private static final int DEBUG_LEVEL = 0; - - private static final boolean OPTIMIZE_JAR_FILE_IO = true; - - /** - * classes to ignore - */ - final private SetOfClasses exclusions; - - /** - * Identity for this class loader - */ - final private ClassLoaderReference loader; - - /** - * A mapping from class name (TypeName) to IClass - */ - protected final Map loadedClasses = HashMapFactory.make(); - - /** - * A mapping from class name (TypeName) to String (source file name) - */ - private final Map sourceMap = HashMapFactory.make(); - - /** - * Parent classloader - */ - final private IClassLoader parent; - - /** - * Governing class hierarchy - */ - protected final IClassHierarchy cha; - - /** - * an object to delegate to for loading of array classes - */ - private final ArrayClassLoader arrayClassLoader; - - /** - * @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, IClassHierarchy cha) { - - if (loader == null) { - throw new IllegalArgumentException("null loader"); - } - - this.arrayClassLoader = arrayClassLoader; - this.parent = parent; - this.loader = loader; - this.exclusions = exclusions; - this.cha = cha; - - if (DEBUG_LEVEL > 0) { - System.err.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 getSourceFiles(Module M) throws IOException { - if (DEBUG_LEVEL > 0) { - System.err.println("Get source files for " + M); - } - TreeSet sortedEntries = new TreeSet(HashCodeComparator.instance()); - sortedEntries.addAll(Iterator2Collection.toSet(M.getEntries())); - - HashSet result = HashSetFactory.make(); - for (Iterator it = sortedEntries.iterator(); it.hasNext();) { - ModuleEntry entry = (ModuleEntry) it.next(); - if (DEBUG_LEVEL > 0) { - System.err.println("consider entry for source information: " + entry); - } - if (entry.isSourceFile()) { - if (DEBUG_LEVEL > 0) { - System.err.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 getClassFiles(Module M) throws IOException { - if (DEBUG_LEVEL > 0) { - System.err.println("Get class files for " + M); - } - TreeSet sortedEntries = new TreeSet(HashCodeComparator.instance()); - sortedEntries.addAll(Iterator2Collection.toSet(M.getEntries())); - HashSet result = HashSetFactory.make(); - for (Iterator it = sortedEntries.iterator(); it.hasNext();) { - ModuleEntry entry = (ModuleEntry) it.next(); - if (DEBUG_LEVEL > 0) { - System.err.println("ClassLoaderImpl.getClassFiles:Got entry: " + entry); - } - if (entry.isClassFile()) { - if (DEBUG_LEVEL > 0) { - System.err.println("result contains: " + entry); - } - result.add(entry); - } else if (entry.isModuleFile()) { - Set s = getClassFiles(entry.asModule()); - removeClassFiles(s, result); - result.addAll(s); - } else { - if (DEBUG_LEVEL > 0) { - System.err.println("Ignoring entry: " + entry); - } - } - } - return result; - } - - /** - * Remove from s any class file module entries which already are in t - */ - private void removeClassFiles(Set s, Set t) { - Set old = HashSetFactory.make(); - for (Iterator it = t.iterator(); it.hasNext();) { - ModuleEntry m = it.next(); - old.add(m.getClassName()); - } - HashSet toRemove = HashSetFactory.make(); - for (Iterator 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 getAllClasses() { - assert loadedClasses != null; - - return loadedClasses.values(); - } - - static class ByteArrayReaderHandle extends ShrikeClassReaderHandle { - public ByteArrayReaderHandle(ModuleEntry entry, byte[] contents) { - super(entry); - assert contents != null && contents.length > 0; - this.contents = contents; - } - - private byte[] contents; - - private boolean cleared; - - @Override - public ClassReader get() throws InvalidClassFileException { - if (cleared) { - return super.get(); - } else { - return new ClassReader(contents); - } - } - - @Override - public void clear() { - if (cleared) { - super.clear(); - } else { - contents = null; - cleared = true; - } - } - - } - - /** - * Set up the set of classes loaded by this object. - */ - private void loadAllClasses(Collection moduleEntries, Map fileContents) { - for (Iterator it = moduleEntries.iterator(); it.hasNext();) { - ModuleEntry entry = it.next(); - if (!entry.isClassFile()) { - continue; - } - - String className = entry.getClassName().replace('.', '/'); - - if (DEBUG_LEVEL > 0) { - System.err.println("Consider " + className); - } - - if (exclusions != null && exclusions.contains(className)) { - if (DEBUG_LEVEL > 0) { - System.err.println("Excluding " + className); - } - continue; - } - - ShrikeClassReaderHandle entryReader = new ShrikeClassReaderHandle(entry); - - className = "L" + className; - if (DEBUG_LEVEL > 0) { - System.err.println("Load class " + className); - } - try { - TypeName T = TypeName.string2TypeName(className); - if (loadedClasses.get(T) != null) { - Warnings.add(MultipleImplementationsWarning.create(className)); - } else if (parent != null && parent.lookupClass(T) != null) { - Warnings.add(MultipleImplementationsWarning.create(className)); - } else { - // try to read from memory - ShrikeClassReaderHandle reader = entryReader; - if (fileContents != null) { - final Object contents = fileContents.get(entry.getName()); - if (contents != null) { - // reader that uses the in-memory bytes - reader = new ByteArrayReaderHandle(entry, (byte[]) contents); - } - } - ShrikeClass tmpKlass = new ShrikeClass(reader, this, cha); - if (tmpKlass.getReference().getName().equals(T)) { - // always used the reader based on the entry after this point, - // so we can null out and re-read class file contents - loadedClasses.put(T, new ShrikeClass(entryReader, this, cha)); - if (DEBUG_LEVEL > 1) { - System.err.println("put " + T + " "); - } - } else { - Warnings.add(InvalidClassFile.create(className)); - } - } - } catch (InvalidClassFileException e) { - if (DEBUG_LEVEL > 0) { - System.err.println("Ignoring class " + className + " due to InvalidClassFileException"); - } - Warnings.add(InvalidClassFile.create(className)); - } - } - } - - @SuppressWarnings("unused") - private Map getAllClassAndSourceFileContents(byte[] jarFileContents, String fileName, - Map> entrySizes) { - if (jarFileContents == null) { - return null; - } - Map entrySizesForFile = entrySizes.get(fileName); - if (entrySizesForFile == null) { - return null; - } - Map result = HashMapFactory.make(); - try { - JarInputStream s = new JarInputStream(new ByteArrayInputStream(jarFileContents)); - JarEntry entry = null; - while ((entry = s.getNextJarEntry()) != null) { - byte[] entryBytes = getEntryBytes(entry, entrySizesForFile.get(entry.getName()), s); - if (entryBytes == null) { - return null; - } - String name = entry.getName(); - if (FileSuffixes.isJarFile(name) || FileSuffixes.isWarFile(name)) { - Map nestedResult = getAllClassAndSourceFileContents(entryBytes, name, entrySizes); - if (nestedResult == null) { - return null; - } - for (String entryName : nestedResult.keySet()) { - if (!result.containsKey(entryName)) { - result.put(entryName, nestedResult.get(entryName)); - } - } - } else if (FileSuffixes.isClassFile(name) || FileSuffixes.isSourceFile(name)) { - result.put(name, entryBytes); - } - } - } catch (IOException e) { - assert false; - } - return result; - } - - private byte[] getEntryBytes(JarEntry entry, Long size, InputStream is) throws IOException { - if (size == null) { - return null; - } - ByteArrayOutputStream S = new ByteArrayOutputStream(); - int n = 0; - long count = 0; - byte[] buffer = new byte[1024]; - while (n > -1 && count < size) { - n = is.read(buffer, 0, 1024); - if (n > -1) { - S.write(buffer, 0, n); - count += n; - } - } - return S.toByteArray(); - } - - /** - * A warning 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; - } - - @Override - public String getMsg() { - return getClass().toString() + " : " + className; - } - - public static MultipleImplementationsWarning create(String className) { - return new MultipleImplementationsWarning(className); - } - } - - /** - * A warning when we encounter InvalidClassFileException - */ - private static class InvalidClassFile extends Warning { - - final String className; - - InvalidClassFile(String className) { - super(Warning.SEVERE); - this.className = className; - } - - @Override - 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 sourceModules) { - for (Iterator 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) { - System.err.println("adding to source map: " + T + " -> " + entry.getName()); - } - sourceMap.put(T, entry); - } - } - - /** - * Initialize internal data structures - * - * @throws IllegalArgumentException if modules is null - */ - public void init(List modules) throws IOException { - - if (modules == null) { - throw new IllegalArgumentException("modules is null"); - } - - // module are loaded according to the given order (same as in Java VM) - Set classModuleEntries = HashSetFactory.make(); - Set sourceModuleEntries = HashSetFactory.make(); - for (Iterator it = modules.iterator(); it.hasNext();) { - Module archive = it.next(); - if (DEBUG_LEVEL > 0) { - System.err.println("add archive: " + archive); - } - // byte[] jarFileContents = null; - if (OPTIMIZE_JAR_FILE_IO && archive instanceof JarFileModule) { - // if we have a jar file, we read the whole thing into memory and operate on that; enables more - // efficient sequential I/O - // this is work in progress; for now, we read the file into memory and throw away the contents, which - // still gives a speedup for large jar files since it reads sequentially and warms up the FS cache. we get a small slowdown - // for smaller jar files or for jar files already in the FS cache. eventually, we should - // actually use the bytes read and eliminate the slowdown - // 11/22/10: I can't figure out a way to actually use the bytes without hurting performance. Apparently, - // extracting files from a jar stored in memory via a JarInputStream is really slow compared to using - // a JarFile. Will leave this as is for now. --MS - // jarFileContents = archive instanceof JarFileModule ? getJarFileContents((JarFileModule) archive) : null; - getJarFileContents((JarFileModule) archive); - } - Set classFiles = getClassFiles(archive); - removeClassFiles(classFiles, classModuleEntries); - Set sourceFiles = getSourceFiles(archive); - Map allClassAndSourceFileContents = null; - if (OPTIMIZE_JAR_FILE_IO) { - // work in progress --MS - // if (archive instanceof JarFileModule) { - // final JarFileModule jfModule = (JarFileModule) archive; - // final String name = jfModule.getJarFile().getName(); - // Map> entrySizes = getEntrySizes(jfModule, name); - // allClassAndSourceFileContents = getAllClassAndSourceFileContents(jarFileContents, name, entrySizes); - // } - // jarFileContents = null; - } - loadAllClasses(classFiles, allClassAndSourceFileContents); - loadAllSources(sourceFiles); - for (Iterator it2 = classFiles.iterator(); it2.hasNext();) { - ModuleEntry file = it2.next(); - classModuleEntries.add(file); - } - for (Iterator it2 = sourceFiles.iterator(); it2.hasNext();) { - ModuleEntry file = it2.next(); - sourceModuleEntries.add(file); - } - } - } - - @SuppressWarnings("unused") - private Map> getEntrySizes(Module module, String name) { - Map> result = HashMapFactory.make(); - Map curFileResult = HashMapFactory.make(); - for (ModuleEntry e : Iterator2Iterable.make(module.getEntries())) { - if (e.isModuleFile()) { - result.putAll(getEntrySizes(e.asModule(), e.getName())); - } else { - if (e instanceof JarFileEntry) { - curFileResult.put(e.getName(), ((JarFileEntry) e).getSize()); - } - } - } - result.put(name, curFileResult); - return result; - } - - /** - * get the contents of a jar file. if any IO exceptions occur, catch and return null. - */ - private void getJarFileContents(JarFileModule archive) { - String jarFileName = archive.getJarFile().getName(); - InputStream s = null; - try { - File jarFile = (new FileProvider()).getFile(jarFileName); - int bufferSize = 65536; - s = new BufferedInputStream(new FileInputStream(jarFile), bufferSize); - byte[] b = new byte[1024]; - int n = s.read(b); - while (n != -1) { - n = s.read(b); - } - } catch (IOException e) { - } finally { - try { - if (s != null) { - s.close(); - } - } catch (IOException e) { - } - } - } - - public ClassLoaderReference getReference() { - return loader; - } - - public Iterator iterateAllClasses() { - return getAllClasses().iterator(); - } - - /* - * @see com.ibm.wala.classLoader.IClassLoader#lookupClass(com.ibm.wala.types.TypeName) - */ - public IClass lookupClass(TypeName className) { - if (className == null) { - throw new IllegalArgumentException("className is null"); - } - if (DEBUG_LEVEL > 1) { - System.err.println(this + ": lookupClass " + className); - } - - // treat arrays specially: - if (className.isArrayType()) { - return arrayClassLoader.lookupClass(className, this, cha); - } - - // try delegating first. - IClassLoader parent = getParent(); - if (parent != null) { - IClass result = parent.lookupClass(className); - if (result != null) { - 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(); - } - - public Language getLanguage() { - return Language.JAVA; - } - - @Override - public String toString() { - return getName().toString(); - } - - /* - * @see com.ibm.wala.classLoader.IClassLoader#getNumberOfClasses() - */ - public int getNumberOfClasses() { - return getAllClasses().size(); - } - - /* - * @see com.ibm.wala.classLoader.IClassLoader#getNumberOfMethods() - */ - public int getNumberOfMethods() { - int result = 0; - for (Iterator it = iterateAllClasses(); it.hasNext();) { - IClass klass = it.next(); - result += klass.getDeclaredMethods().size(); - } - return result; - } - - /* - * @see com.ibm.wala.classLoader.IClassLoader#getSourceFileName(com.ibm.wala.classLoader.IClass) - */ - public String getSourceFileName(IClass klass) { - if (klass == null) { - throw new IllegalArgumentException("klass is null"); - } - ModuleEntry e = sourceMap.get(klass.getName()); - return e == null ? null : e.getName(); - } - - public InputStream getSource(IMethod method, int offset) { - return getSource(method.getDeclaringClass()); - } - - public String getSourceFileName(IMethod method, int offset) { - return getSourceFileName(method.getDeclaringClass()); - } - - public InputStream getSource(IClass klass) { - if (klass == null) { - throw new IllegalArgumentException("klass is null"); - } - ModuleEntry e = sourceMap.get(klass.getName()); - return e == null ? null : e.getInputStream(); - } - - /* - * @see com.ibm.wala.classLoader.IClassLoader#removeAll(java.util.Collection) - */ - public void removeAll(Collection toRemove) { - if (toRemove == null) { - throw new IllegalArgumentException("toRemove is null"); - } - for (Iterator it = toRemove.iterator(); it.hasNext();) { - IClass klass = it.next(); - if (DEBUG_LEVEL > 0) { - System.err.println("removing " + klass.getName()); - } - loadedClasses.remove(klass.getName()); - sourceMap.remove(klass.getName()); - } - } - - public SSAInstructionFactory getInstructionFactory() { - return getLanguage().instructionFactory(); - } -} +/******************************************************************************* + * 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.BufferedInputStream; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +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 java.util.TreeSet; +import java.util.jar.JarEntry; +import java.util.jar.JarInputStream; + +import com.ibm.wala.ipa.callgraph.impl.SetOfClasses; +import com.ibm.wala.ipa.cha.IClassHierarchy; +import com.ibm.wala.shrikeCT.ClassReader; +import com.ibm.wala.shrikeCT.InvalidClassFileException; +import com.ibm.wala.ssa.SSAInstructionFactory; +import com.ibm.wala.types.ClassLoaderReference; +import com.ibm.wala.types.TypeName; +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.Iterator2Iterable; +import com.ibm.wala.util.io.FileProvider; +import com.ibm.wala.util.io.FileSuffixes; +import com.ibm.wala.util.shrike.ShrikeClassReaderHandle; +import com.ibm.wala.util.strings.Atom; +import com.ibm.wala.util.warnings.Warning; +import com.ibm.wala.util.warnings.Warnings; + +/** + * A class loader that reads class definitions from a set of Modules. + */ +public class ClassLoaderImpl implements IClassLoader { + private static final int DEBUG_LEVEL = 0; + + private static final boolean OPTIMIZE_JAR_FILE_IO = true; + + /** + * classes to ignore + */ + final private SetOfClasses exclusions; + + /** + * Identity for this class loader + */ + final private ClassLoaderReference loader; + + /** + * A mapping from class name (TypeName) to IClass + */ + protected final Map loadedClasses = HashMapFactory.make(); + + /** + * A mapping from class name (TypeName) to String (source file name) + */ + private final Map sourceMap = HashMapFactory.make(); + + /** + * Parent classloader + */ + final private IClassLoader parent; + + /** + * Governing class hierarchy + */ + protected final IClassHierarchy cha; + + /** + * an object to delegate to for loading of array classes + */ + private final ArrayClassLoader arrayClassLoader; + + /** + * @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, IClassHierarchy cha) { + + if (loader == null) { + throw new IllegalArgumentException("null loader"); + } + + this.arrayClassLoader = arrayClassLoader; + this.parent = parent; + this.loader = loader; + this.exclusions = exclusions; + this.cha = cha; + + if (DEBUG_LEVEL > 0) { + System.err.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 getSourceFiles(Module M) throws IOException { + if (DEBUG_LEVEL > 0) { + System.err.println("Get source files for " + M); + } + TreeSet sortedEntries = new TreeSet(HashCodeComparator.instance()); + sortedEntries.addAll(Iterator2Collection.toSet(M.getEntries())); + + HashSet result = HashSetFactory.make(); + for (Iterator it = sortedEntries.iterator(); it.hasNext();) { + ModuleEntry entry = (ModuleEntry) it.next(); + if (DEBUG_LEVEL > 0) { + System.err.println("consider entry for source information: " + entry); + } + if (entry.isSourceFile()) { + if (DEBUG_LEVEL > 0) { + System.err.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 getClassFiles(Module M) throws IOException { + if (DEBUG_LEVEL > 0) { + System.err.println("Get class files for " + M); + } + TreeSet sortedEntries = new TreeSet(HashCodeComparator.instance()); + sortedEntries.addAll(Iterator2Collection.toSet(M.getEntries())); + HashSet result = HashSetFactory.make(); + for (Iterator it = sortedEntries.iterator(); it.hasNext();) { + ModuleEntry entry = (ModuleEntry) it.next(); + if (DEBUG_LEVEL > 0) { + System.err.println("ClassLoaderImpl.getClassFiles:Got entry: " + entry); + } + if (entry.isClassFile()) { + if (DEBUG_LEVEL > 0) { + System.err.println("result contains: " + entry); + } + result.add(entry); + } else if (entry.isModuleFile()) { + Set s = getClassFiles(entry.asModule()); + removeClassFiles(s, result); + result.addAll(s); + } else { + if (DEBUG_LEVEL > 0) { + System.err.println("Ignoring entry: " + entry); + } + } + } + return result; + } + + /** + * Remove from s any class file module entries which already are in t + */ + private void removeClassFiles(Set s, Set t) { + Set old = HashSetFactory.make(); + for (Iterator it = t.iterator(); it.hasNext();) { + ModuleEntry m = it.next(); + old.add(m.getClassName()); + } + HashSet toRemove = HashSetFactory.make(); + for (Iterator 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 getAllClasses() { + assert loadedClasses != null; + + return loadedClasses.values(); + } + + static class ByteArrayReaderHandle extends ShrikeClassReaderHandle { + public ByteArrayReaderHandle(ModuleEntry entry, byte[] contents) { + super(entry); + assert contents != null && contents.length > 0; + this.contents = contents; + } + + private byte[] contents; + + private boolean cleared; + + @Override + public ClassReader get() throws InvalidClassFileException { + if (cleared) { + return super.get(); + } else { + return new ClassReader(contents); + } + } + + @Override + public void clear() { + if (cleared) { + super.clear(); + } else { + contents = null; + cleared = true; + } + } + + } + + /** + * Set up the set of classes loaded by this object. + */ + private void loadAllClasses(Collection moduleEntries, Map fileContents) { + for (Iterator it = moduleEntries.iterator(); it.hasNext();) { + ModuleEntry entry = it.next(); + if (!entry.isClassFile()) { + continue; + } + + String className = entry.getClassName().replace('.', '/'); + + if (DEBUG_LEVEL > 0) { + System.err.println("Consider " + className); + } + + if (exclusions != null && exclusions.contains(className)) { + if (DEBUG_LEVEL > 0) { + System.err.println("Excluding " + className); + } + continue; + } + + ShrikeClassReaderHandle entryReader = new ShrikeClassReaderHandle(entry); + + className = "L" + className; + if (DEBUG_LEVEL > 0) { + System.err.println("Load class " + className); + } + try { + TypeName T = TypeName.string2TypeName(className); + if (loadedClasses.get(T) != null) { + Warnings.add(MultipleImplementationsWarning.create(className)); + } else if (parent != null && parent.lookupClass(T) != null) { + Warnings.add(MultipleImplementationsWarning.create(className)); + } else { + // try to read from memory + ShrikeClassReaderHandle reader = entryReader; + if (fileContents != null) { + final Object contents = fileContents.get(entry.getName()); + if (contents != null) { + // reader that uses the in-memory bytes + reader = new ByteArrayReaderHandle(entry, (byte[]) contents); + } + } + ShrikeClass tmpKlass = new ShrikeClass(reader, this, cha); + if (tmpKlass.getReference().getName().equals(T)) { + // always used the reader based on the entry after this point, + // so we can null out and re-read class file contents + loadedClasses.put(T, new ShrikeClass(entryReader, this, cha)); + if (DEBUG_LEVEL > 1) { + System.err.println("put " + T + " "); + } + } else { + Warnings.add(InvalidClassFile.create(className)); + } + } + } catch (InvalidClassFileException e) { + if (DEBUG_LEVEL > 0) { + System.err.println("Ignoring class " + className + " due to InvalidClassFileException"); + } + Warnings.add(InvalidClassFile.create(className)); + } + } + } + + @SuppressWarnings("unused") + private Map getAllClassAndSourceFileContents(byte[] jarFileContents, String fileName, + Map> entrySizes) { + if (jarFileContents == null) { + return null; + } + Map entrySizesForFile = entrySizes.get(fileName); + if (entrySizesForFile == null) { + return null; + } + Map result = HashMapFactory.make(); + try { + JarInputStream s = new JarInputStream(new ByteArrayInputStream(jarFileContents)); + JarEntry entry = null; + while ((entry = s.getNextJarEntry()) != null) { + byte[] entryBytes = getEntryBytes(entry, entrySizesForFile.get(entry.getName()), s); + if (entryBytes == null) { + return null; + } + String name = entry.getName(); + if (FileSuffixes.isJarFile(name) || FileSuffixes.isWarFile(name)) { + Map nestedResult = getAllClassAndSourceFileContents(entryBytes, name, entrySizes); + if (nestedResult == null) { + return null; + } + for (String entryName : nestedResult.keySet()) { + if (!result.containsKey(entryName)) { + result.put(entryName, nestedResult.get(entryName)); + } + } + } else if (FileSuffixes.isClassFile(name) || FileSuffixes.isSourceFile(name)) { + result.put(name, entryBytes); + } + } + } catch (IOException e) { + assert false; + } + return result; + } + + private byte[] getEntryBytes(JarEntry entry, Long size, InputStream is) throws IOException { + if (size == null) { + return null; + } + ByteArrayOutputStream S = new ByteArrayOutputStream(); + int n = 0; + long count = 0; + byte[] buffer = new byte[1024]; + while (n > -1 && count < size) { + n = is.read(buffer, 0, 1024); + if (n > -1) { + S.write(buffer, 0, n); + count += n; + } + } + return S.toByteArray(); + } + + /** + * A warning 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; + } + + @Override + public String getMsg() { + return getClass().toString() + " : " + className; + } + + public static MultipleImplementationsWarning create(String className) { + return new MultipleImplementationsWarning(className); + } + } + + /** + * A warning when we encounter InvalidClassFileException + */ + private static class InvalidClassFile extends Warning { + + final String className; + + InvalidClassFile(String className) { + super(Warning.SEVERE); + this.className = className; + } + + @Override + 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 sourceModules) { + for (Iterator 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) { + System.err.println("adding to source map: " + T + " -> " + entry.getName()); + } + sourceMap.put(T, entry); + } + } + + /** + * Initialize internal data structures + * + * @throws IllegalArgumentException if modules is null + */ + public void init(List modules) throws IOException { + + if (modules == null) { + throw new IllegalArgumentException("modules is null"); + } + + // module are loaded according to the given order (same as in Java VM) + Set classModuleEntries = HashSetFactory.make(); + Set sourceModuleEntries = HashSetFactory.make(); + for (Iterator it = modules.iterator(); it.hasNext();) { + Module archive = it.next(); + if (DEBUG_LEVEL > 0) { + System.err.println("add archive: " + archive); + } + // byte[] jarFileContents = null; + if (OPTIMIZE_JAR_FILE_IO && archive instanceof JarFileModule) { + // if we have a jar file, we read the whole thing into memory and operate on that; enables more + // efficient sequential I/O + // this is work in progress; for now, we read the file into memory and throw away the contents, which + // still gives a speedup for large jar files since it reads sequentially and warms up the FS cache. we get a small slowdown + // for smaller jar files or for jar files already in the FS cache. eventually, we should + // actually use the bytes read and eliminate the slowdown + // 11/22/10: I can't figure out a way to actually use the bytes without hurting performance. Apparently, + // extracting files from a jar stored in memory via a JarInputStream is really slow compared to using + // a JarFile. Will leave this as is for now. --MS + // jarFileContents = archive instanceof JarFileModule ? getJarFileContents((JarFileModule) archive) : null; + getJarFileContents((JarFileModule) archive); + } + Set classFiles = getClassFiles(archive); + removeClassFiles(classFiles, classModuleEntries); + Set sourceFiles = getSourceFiles(archive); + Map allClassAndSourceFileContents = null; + if (OPTIMIZE_JAR_FILE_IO) { + // work in progress --MS + // if (archive instanceof JarFileModule) { + // final JarFileModule jfModule = (JarFileModule) archive; + // final String name = jfModule.getJarFile().getName(); + // Map> entrySizes = getEntrySizes(jfModule, name); + // allClassAndSourceFileContents = getAllClassAndSourceFileContents(jarFileContents, name, entrySizes); + // } + // jarFileContents = null; + } + loadAllClasses(classFiles, allClassAndSourceFileContents); + loadAllSources(sourceFiles); + for (Iterator it2 = classFiles.iterator(); it2.hasNext();) { + ModuleEntry file = it2.next(); + classModuleEntries.add(file); + } + for (Iterator it2 = sourceFiles.iterator(); it2.hasNext();) { + ModuleEntry file = it2.next(); + sourceModuleEntries.add(file); + } + } + } + + @SuppressWarnings("unused") + private Map> getEntrySizes(Module module, String name) { + Map> result = HashMapFactory.make(); + Map curFileResult = HashMapFactory.make(); + for (ModuleEntry e : Iterator2Iterable.make(module.getEntries())) { + if (e.isModuleFile()) { + result.putAll(getEntrySizes(e.asModule(), e.getName())); + } else { + if (e instanceof JarFileEntry) { + curFileResult.put(e.getName(), ((JarFileEntry) e).getSize()); + } + } + } + result.put(name, curFileResult); + return result; + } + + /** + * get the contents of a jar file. if any IO exceptions occur, catch and return null. + */ + private void getJarFileContents(JarFileModule archive) { + String jarFileName = archive.getJarFile().getName(); + InputStream s = null; + try { + File jarFile = (new FileProvider()).getFile(jarFileName); + int bufferSize = 65536; + s = new BufferedInputStream(new FileInputStream(jarFile), bufferSize); + byte[] b = new byte[1024]; + int n = s.read(b); + while (n != -1) { + n = s.read(b); + } + } catch (IOException e) { + } finally { + try { + if (s != null) { + s.close(); + } + } catch (IOException e) { + } + } + } + + public ClassLoaderReference getReference() { + return loader; + } + + public Iterator iterateAllClasses() { + return getAllClasses().iterator(); + } + + /* + * @see com.ibm.wala.classLoader.IClassLoader#lookupClass(com.ibm.wala.types.TypeName) + */ + public IClass lookupClass(TypeName className) { + if (className == null) { + throw new IllegalArgumentException("className is null"); + } + if (DEBUG_LEVEL > 1) { + System.err.println(this + ": lookupClass " + className); + } + + // treat arrays specially: + if (className.isArrayType()) { + return arrayClassLoader.lookupClass(className, this, cha); + } + + // try delegating first. + IClassLoader parent = getParent(); + if (parent != null) { + IClass result = parent.lookupClass(className); + if (result != null) { + 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(); + } + + public Language getLanguage() { + return Language.JAVA; + } + + @Override + public String toString() { + return getName().toString(); + } + + /* + * @see com.ibm.wala.classLoader.IClassLoader#getNumberOfClasses() + */ + public int getNumberOfClasses() { + return getAllClasses().size(); + } + + /* + * @see com.ibm.wala.classLoader.IClassLoader#getNumberOfMethods() + */ + public int getNumberOfMethods() { + int result = 0; + for (Iterator it = iterateAllClasses(); it.hasNext();) { + IClass klass = it.next(); + result += klass.getDeclaredMethods().size(); + } + return result; + } + + /* + * @see com.ibm.wala.classLoader.IClassLoader#getSourceFileName(com.ibm.wala.classLoader.IClass) + */ + public String getSourceFileName(IClass klass) { + if (klass == null) { + throw new IllegalArgumentException("klass is null"); + } + ModuleEntry e = sourceMap.get(klass.getName()); + return e == null ? null : e.getName(); + } + + public InputStream getSource(IMethod method, int offset) { + return getSource(method.getDeclaringClass()); + } + + public String getSourceFileName(IMethod method, int offset) { + return getSourceFileName(method.getDeclaringClass()); + } + + public InputStream getSource(IClass klass) { + if (klass == null) { + throw new IllegalArgumentException("klass is null"); + } + ModuleEntry e = sourceMap.get(klass.getName()); + return e == null ? null : e.getInputStream(); + } + + /* + * @see com.ibm.wala.classLoader.IClassLoader#removeAll(java.util.Collection) + */ + public void removeAll(Collection toRemove) { + if (toRemove == null) { + throw new IllegalArgumentException("toRemove is null"); + } + for (Iterator it = toRemove.iterator(); it.hasNext();) { + IClass klass = it.next(); + if (DEBUG_LEVEL > 0) { + System.err.println("removing " + klass.getName()); + } + loadedClasses.remove(klass.getName()); + sourceMap.remove(klass.getName()); + } + } + + public SSAInstructionFactory getInstructionFactory() { + return getLanguage().instructionFactory(); + } +} diff --git a/com.ibm.wala.core/src/com/ibm/wala/classLoader/CodeScanner.java b/com.ibm.wala.core/src/com/ibm/wala/classLoader/CodeScanner.java index 2cc4706af..7150469da 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/classLoader/CodeScanner.java +++ b/com.ibm.wala.core/src/com/ibm/wala/classLoader/CodeScanner.java @@ -1,464 +1,464 @@ -/******************************************************************************* - * 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.SSAInstruction.Visitor; -import com.ibm.wala.ssa.SSAInvokeInstruction; -import com.ibm.wala.ssa.SSANewInstruction; -import com.ibm.wala.ssa.SSAPutInstruction; -import com.ibm.wala.types.FieldReference; -import com.ibm.wala.types.TypeReference; -import com.ibm.wala.util.collections.HashSetFactory; - -/** - * Simple utilities to scan {@link IMethod}s to gather information without building an IR. - */ -public class CodeScanner { - - /** - * @throws InvalidClassFileException - * @throws IllegalArgumentException if m is null - */ - public static Collection getCallSites(IMethod m) throws InvalidClassFileException { - if (m == null) { - throw new IllegalArgumentException("m is null"); - } - if (m.isSynthetic()) { - SyntheticMethod sm = (SyntheticMethod) m; - return getCallSites(sm.getStatements()); - } else { - return getCallSitesFromShrikeBT((IBytecodeMethod) m); - } - } - - /** - * @throws InvalidClassFileException - * @throws IllegalArgumentException if m is null - */ - public static Collection getFieldsRead(IMethod m) throws InvalidClassFileException { - if (m == null) { - throw new IllegalArgumentException("m is null"); - } - if (m.isSynthetic()) { - SyntheticMethod sm = (SyntheticMethod) m; - return getFieldsRead(sm.getStatements()); - } else { - return getFieldsReadFromShrikeBT((ShrikeCTMethod) m); - } - } - - /** - * @throws InvalidClassFileException - * @throws IllegalArgumentException if m is null - */ - public static Collection getFieldsWritten(IMethod m) throws InvalidClassFileException { - if (m == null) { - throw new IllegalArgumentException("m is null"); - } - if (m.isSynthetic()) { - SyntheticMethod sm = (SyntheticMethod) m; - return getFieldsWritten(sm.getStatements()); - } else { - return getFieldsWrittenFromShrikeBT((ShrikeCTMethod) m); - } - } - - /** - * get the element types of the arrays that m may update - * - * @throws InvalidClassFileException - */ - public static Collection getArraysWritten(IMethod m) throws InvalidClassFileException { - if (m == null) { - throw new IllegalArgumentException("m is null"); - } - if (m.isSynthetic()) { - SyntheticMethod sm = (SyntheticMethod) m; - return getArraysWritten(sm.getStatements()); - } else { - return getArraysWrittenFromShrikeBT((ShrikeCTMethod) m); - } - } - - /** - * @throws InvalidClassFileException - * @throws IllegalArgumentException if m is null - */ - public static Collection getNewSites(IMethod m) throws InvalidClassFileException { - if (m == null) { - throw new IllegalArgumentException("m is null"); - } - if (m.isSynthetic()) { - SyntheticMethod sm = (SyntheticMethod) m; - return getNewSites(sm.getStatements()); - } else { - return getNewSitesFromShrikeBT((ShrikeCTMethod) m); - } - } - - public static boolean hasObjectArrayLoad(IMethod m) throws InvalidClassFileException { - if (m == null) { - throw new IllegalArgumentException("m is null"); - } - if (m.isSynthetic()) { - SyntheticMethod sm = (SyntheticMethod) m; - return hasObjectArrayLoad(sm.getStatements()); - } else { - return hasShrikeBTObjectArrayLoad((ShrikeCTMethod) m); - } - } - - public static boolean hasObjectArrayStore(IMethod m) throws InvalidClassFileException { - if (m == null) { - throw new IllegalArgumentException("m is null"); - } - if (m.isSynthetic()) { - SyntheticMethod sm = (SyntheticMethod) m; - return hasObjectArrayStore(sm.getStatements()); - } else { - return hasShrikeBTObjectArrayStore((ShrikeCTMethod) m); - } - } - - public static Set getCaughtExceptions(IMethod m) throws InvalidClassFileException { - if (m == null) { - throw new IllegalArgumentException("m is null"); - } - if (m.isSynthetic()) { - SyntheticMethod sm = (SyntheticMethod) m; - return getCaughtExceptions(m.getDeclaringClass().getClassLoader().getLanguage(), sm.getStatements()); - } else { - return getShrikeBTCaughtExceptions((ShrikeCTMethod) m); - } - } - - /** - * Return the types this method may cast to - * - * @return iterator of TypeReference - * @throws InvalidClassFileException - * @throws IllegalArgumentException if m is null - */ - public static Iterator iterateCastTypes(IMethod m) throws InvalidClassFileException { - if (m == null) { - throw new IllegalArgumentException("m is null"); - } - if (m.isSynthetic()) { - SyntheticMethod sm = (SyntheticMethod) m; - return iterateCastTypes(sm.getStatements()); - } else { - return iterateShrikeBTCastTypes((ShrikeCTMethod) m); - } - } - - private static Iterator iterateShrikeBTCastTypes(ShrikeCTMethod wrapper) throws InvalidClassFileException { - return wrapper.getCastTypes(); - } - - private static Set getShrikeBTCaughtExceptions(ShrikeCTMethod method) throws InvalidClassFileException { - return method.getCaughtExceptionTypes(); - } - - private static boolean hasShrikeBTObjectArrayStore(ShrikeCTMethod M) throws InvalidClassFileException { - for (Iterator it = M.getArraysWritten(); it.hasNext();) { - TypeReference t = (TypeReference) it.next(); - if (t.isReferenceType()) { - return true; - } - } - return false; - } - - private static Collection getCallSitesFromShrikeBT(IBytecodeMethod M) throws InvalidClassFileException { - return M.getCallSites(); - } - - /** - * @param M - * @return Iterator of TypeReference - * @throws InvalidClassFileException - */ - private static Collection getNewSitesFromShrikeBT(ShrikeCTMethod M) throws InvalidClassFileException { - return M.getNewSites(); - } - - private static List getFieldsReadFromShrikeBT(ShrikeCTMethod M) throws InvalidClassFileException { - // TODO move the logic here from ShrikeCTMethodWrapper - LinkedList result = new LinkedList(); - for (Iterator it = M.getFieldsRead(); it.hasNext();) { - result.add(it.next()); - } - return result; - } - - private static List getFieldsWrittenFromShrikeBT(ShrikeCTMethod M) throws InvalidClassFileException { - // TODO move the logic here from ShrikeCTMethodWrapper - LinkedList result = new LinkedList(); - for (Iterator it = M.getFieldsWritten(); it.hasNext();) { - result.add(it.next()); - } - return result; - } - - private static List getArraysWrittenFromShrikeBT(ShrikeCTMethod M) throws InvalidClassFileException { - // TODO move the logic here from ShrikeCTMethodWrapper - List result = new LinkedList(); - for (Iterator it = M.getArraysWritten(); it.hasNext();) { - result.add(it.next()); - } - return result; - } - - private static boolean hasShrikeBTObjectArrayLoad(ShrikeCTMethod M) throws InvalidClassFileException { - for (Iterator it = M.getArraysRead(); it.hasNext();) { - TypeReference t = (TypeReference) it.next(); - if (t.isReferenceType()) { - return true; - } - } - return false; - } - - /** - * @return Set - * @throws IllegalArgumentException if statements == null - */ - public static Set getCaughtExceptions(final Language l, SSAInstruction[] statements) throws IllegalArgumentException { - if (statements == null) { - throw new IllegalArgumentException("statements == null"); - } - final HashSet result = HashSetFactory.make(10); - Visitor v = new Visitor() { - @Override - public void visitGetCaughtException(SSAGetCaughtExceptionInstruction instruction) { - Collection 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; - } - - /** - * @throws IllegalArgumentException if statements == null - */ - public static Iterator iterateCastTypes(SSAInstruction[] statements) throws IllegalArgumentException { - if (statements == null) { - throw new IllegalArgumentException("statements == null"); - } - final HashSet 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]; - for(TypeReference t : c.getDeclaredResultTypes()) { - result.add(t); - } - } - } - } - return result.iterator(); - } - - /** - * @param statements list of ssa statements - * @return List of InvokeInstruction - */ - private static List getCallSites(SSAInstruction[] statements) { - final List result = new LinkedList(); - Visitor v = new Visitor() { - @Override - 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 getNewSites(SSAInstruction[] statements) { - final List result = new LinkedList(); - Visitor v = new Visitor() { - @Override - 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 - * @throws IllegalArgumentException if statements == null - */ - public static List getFieldsRead(SSAInstruction[] statements) throws IllegalArgumentException { - if (statements == null) { - throw new IllegalArgumentException("statements == null"); - } - final List result = new LinkedList(); - Visitor v = new Visitor() { - @Override - 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 - * @throws IllegalArgumentException if statements == null - */ - public static List getFieldsWritten(SSAInstruction[] statements) throws IllegalArgumentException { - if (statements == null) { - throw new IllegalArgumentException("statements == null"); - } - final List result = new LinkedList(); - Visitor v = new Visitor() { - @Override - 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; - } - - /** - * @param statements list of ssa statements - * @return List of TypeReference - * @throws IllegalArgumentException if statements == null - */ - public static List getArraysWritten(SSAInstruction[] statements) throws IllegalArgumentException { - if (statements == null) { - throw new IllegalArgumentException("statements == null"); - } - final List result = new LinkedList(); - Visitor v = new Visitor() { - - @Override - public void visitArrayStore(SSAArrayStoreInstruction instruction) { - result.add(instruction.getElementType()); - } - - }; - 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) throws IllegalArgumentException { - - if (statements == null) { - throw new IllegalArgumentException("statements == null"); - } - class ScanVisitor extends Visitor { - boolean foundOne = false; - - @Override - 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) throws IllegalArgumentException { - - if (statements == null) { - throw new IllegalArgumentException("statements == null"); - } - class ScanVisitor extends Visitor { - boolean foundOne = false; - - @Override - 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; - } +/******************************************************************************* + * 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.SSAInstruction.Visitor; +import com.ibm.wala.ssa.SSAInvokeInstruction; +import com.ibm.wala.ssa.SSANewInstruction; +import com.ibm.wala.ssa.SSAPutInstruction; +import com.ibm.wala.types.FieldReference; +import com.ibm.wala.types.TypeReference; +import com.ibm.wala.util.collections.HashSetFactory; + +/** + * Simple utilities to scan {@link IMethod}s to gather information without building an IR. + */ +public class CodeScanner { + + /** + * @throws InvalidClassFileException + * @throws IllegalArgumentException if m is null + */ + public static Collection getCallSites(IMethod m) throws InvalidClassFileException { + if (m == null) { + throw new IllegalArgumentException("m is null"); + } + if (m.isSynthetic()) { + SyntheticMethod sm = (SyntheticMethod) m; + return getCallSites(sm.getStatements()); + } else { + return getCallSitesFromShrikeBT((IBytecodeMethod) m); + } + } + + /** + * @throws InvalidClassFileException + * @throws IllegalArgumentException if m is null + */ + public static Collection getFieldsRead(IMethod m) throws InvalidClassFileException { + if (m == null) { + throw new IllegalArgumentException("m is null"); + } + if (m.isSynthetic()) { + SyntheticMethod sm = (SyntheticMethod) m; + return getFieldsRead(sm.getStatements()); + } else { + return getFieldsReadFromShrikeBT((ShrikeCTMethod) m); + } + } + + /** + * @throws InvalidClassFileException + * @throws IllegalArgumentException if m is null + */ + public static Collection getFieldsWritten(IMethod m) throws InvalidClassFileException { + if (m == null) { + throw new IllegalArgumentException("m is null"); + } + if (m.isSynthetic()) { + SyntheticMethod sm = (SyntheticMethod) m; + return getFieldsWritten(sm.getStatements()); + } else { + return getFieldsWrittenFromShrikeBT((ShrikeCTMethod) m); + } + } + + /** + * get the element types of the arrays that m may update + * + * @throws InvalidClassFileException + */ + public static Collection getArraysWritten(IMethod m) throws InvalidClassFileException { + if (m == null) { + throw new IllegalArgumentException("m is null"); + } + if (m.isSynthetic()) { + SyntheticMethod sm = (SyntheticMethod) m; + return getArraysWritten(sm.getStatements()); + } else { + return getArraysWrittenFromShrikeBT((ShrikeCTMethod) m); + } + } + + /** + * @throws InvalidClassFileException + * @throws IllegalArgumentException if m is null + */ + public static Collection getNewSites(IMethod m) throws InvalidClassFileException { + if (m == null) { + throw new IllegalArgumentException("m is null"); + } + if (m.isSynthetic()) { + SyntheticMethod sm = (SyntheticMethod) m; + return getNewSites(sm.getStatements()); + } else { + return getNewSitesFromShrikeBT((ShrikeCTMethod) m); + } + } + + public static boolean hasObjectArrayLoad(IMethod m) throws InvalidClassFileException { + if (m == null) { + throw new IllegalArgumentException("m is null"); + } + if (m.isSynthetic()) { + SyntheticMethod sm = (SyntheticMethod) m; + return hasObjectArrayLoad(sm.getStatements()); + } else { + return hasShrikeBTObjectArrayLoad((ShrikeCTMethod) m); + } + } + + public static boolean hasObjectArrayStore(IMethod m) throws InvalidClassFileException { + if (m == null) { + throw new IllegalArgumentException("m is null"); + } + if (m.isSynthetic()) { + SyntheticMethod sm = (SyntheticMethod) m; + return hasObjectArrayStore(sm.getStatements()); + } else { + return hasShrikeBTObjectArrayStore((ShrikeCTMethod) m); + } + } + + public static Set getCaughtExceptions(IMethod m) throws InvalidClassFileException { + if (m == null) { + throw new IllegalArgumentException("m is null"); + } + if (m.isSynthetic()) { + SyntheticMethod sm = (SyntheticMethod) m; + return getCaughtExceptions(m.getDeclaringClass().getClassLoader().getLanguage(), sm.getStatements()); + } else { + return getShrikeBTCaughtExceptions((ShrikeCTMethod) m); + } + } + + /** + * Return the types this method may cast to + * + * @return iterator of TypeReference + * @throws InvalidClassFileException + * @throws IllegalArgumentException if m is null + */ + public static Iterator iterateCastTypes(IMethod m) throws InvalidClassFileException { + if (m == null) { + throw new IllegalArgumentException("m is null"); + } + if (m.isSynthetic()) { + SyntheticMethod sm = (SyntheticMethod) m; + return iterateCastTypes(sm.getStatements()); + } else { + return iterateShrikeBTCastTypes((ShrikeCTMethod) m); + } + } + + private static Iterator iterateShrikeBTCastTypes(ShrikeCTMethod wrapper) throws InvalidClassFileException { + return wrapper.getCastTypes(); + } + + private static Set getShrikeBTCaughtExceptions(ShrikeCTMethod method) throws InvalidClassFileException { + return method.getCaughtExceptionTypes(); + } + + private static boolean hasShrikeBTObjectArrayStore(ShrikeCTMethod M) throws InvalidClassFileException { + for (Iterator it = M.getArraysWritten(); it.hasNext();) { + TypeReference t = (TypeReference) it.next(); + if (t.isReferenceType()) { + return true; + } + } + return false; + } + + private static Collection getCallSitesFromShrikeBT(IBytecodeMethod M) throws InvalidClassFileException { + return M.getCallSites(); + } + + /** + * @param M + * @return Iterator of TypeReference + * @throws InvalidClassFileException + */ + private static Collection getNewSitesFromShrikeBT(ShrikeCTMethod M) throws InvalidClassFileException { + return M.getNewSites(); + } + + private static List getFieldsReadFromShrikeBT(ShrikeCTMethod M) throws InvalidClassFileException { + // TODO move the logic here from ShrikeCTMethodWrapper + LinkedList result = new LinkedList(); + for (Iterator it = M.getFieldsRead(); it.hasNext();) { + result.add(it.next()); + } + return result; + } + + private static List getFieldsWrittenFromShrikeBT(ShrikeCTMethod M) throws InvalidClassFileException { + // TODO move the logic here from ShrikeCTMethodWrapper + LinkedList result = new LinkedList(); + for (Iterator it = M.getFieldsWritten(); it.hasNext();) { + result.add(it.next()); + } + return result; + } + + private static List getArraysWrittenFromShrikeBT(ShrikeCTMethod M) throws InvalidClassFileException { + // TODO move the logic here from ShrikeCTMethodWrapper + List result = new LinkedList(); + for (Iterator it = M.getArraysWritten(); it.hasNext();) { + result.add(it.next()); + } + return result; + } + + private static boolean hasShrikeBTObjectArrayLoad(ShrikeCTMethod M) throws InvalidClassFileException { + for (Iterator it = M.getArraysRead(); it.hasNext();) { + TypeReference t = (TypeReference) it.next(); + if (t.isReferenceType()) { + return true; + } + } + return false; + } + + /** + * @return Set + * @throws IllegalArgumentException if statements == null + */ + public static Set getCaughtExceptions(final Language l, SSAInstruction[] statements) throws IllegalArgumentException { + if (statements == null) { + throw new IllegalArgumentException("statements == null"); + } + final HashSet result = HashSetFactory.make(10); + Visitor v = new Visitor() { + @Override + public void visitGetCaughtException(SSAGetCaughtExceptionInstruction instruction) { + Collection 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; + } + + /** + * @throws IllegalArgumentException if statements == null + */ + public static Iterator iterateCastTypes(SSAInstruction[] statements) throws IllegalArgumentException { + if (statements == null) { + throw new IllegalArgumentException("statements == null"); + } + final HashSet 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]; + for(TypeReference t : c.getDeclaredResultTypes()) { + result.add(t); + } + } + } + } + return result.iterator(); + } + + /** + * @param statements list of ssa statements + * @return List of InvokeInstruction + */ + private static List getCallSites(SSAInstruction[] statements) { + final List result = new LinkedList(); + Visitor v = new Visitor() { + @Override + 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 getNewSites(SSAInstruction[] statements) { + final List result = new LinkedList(); + Visitor v = new Visitor() { + @Override + 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 + * @throws IllegalArgumentException if statements == null + */ + public static List getFieldsRead(SSAInstruction[] statements) throws IllegalArgumentException { + if (statements == null) { + throw new IllegalArgumentException("statements == null"); + } + final List result = new LinkedList(); + Visitor v = new Visitor() { + @Override + 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 + * @throws IllegalArgumentException if statements == null + */ + public static List getFieldsWritten(SSAInstruction[] statements) throws IllegalArgumentException { + if (statements == null) { + throw new IllegalArgumentException("statements == null"); + } + final List result = new LinkedList(); + Visitor v = new Visitor() { + @Override + 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; + } + + /** + * @param statements list of ssa statements + * @return List of TypeReference + * @throws IllegalArgumentException if statements == null + */ + public static List getArraysWritten(SSAInstruction[] statements) throws IllegalArgumentException { + if (statements == null) { + throw new IllegalArgumentException("statements == null"); + } + final List result = new LinkedList(); + Visitor v = new Visitor() { + + @Override + public void visitArrayStore(SSAArrayStoreInstruction instruction) { + result.add(instruction.getElementType()); + } + + }; + 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) throws IllegalArgumentException { + + if (statements == null) { + throw new IllegalArgumentException("statements == null"); + } + class ScanVisitor extends Visitor { + boolean foundOne = false; + + @Override + 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) throws IllegalArgumentException { + + if (statements == null) { + throw new IllegalArgumentException("statements == null"); + } + class ScanVisitor extends Visitor { + boolean foundOne = false; + + @Override + 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; + } } \ No newline at end of file diff --git a/com.ibm.wala.core/src/com/ibm/wala/classLoader/DirectoryTreeModule.java b/com.ibm.wala.core/src/com/ibm/wala/classLoader/DirectoryTreeModule.java index 110027ff7..a96e60e7d 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/classLoader/DirectoryTreeModule.java +++ b/com.ibm.wala.core/src/com/ibm/wala/classLoader/DirectoryTreeModule.java @@ -1,106 +1,106 @@ -/******************************************************************************* - * 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.Iterator; -import java.util.Set; - -import com.ibm.wala.util.collections.HashSetFactory; - -/** - * A module containing files under some directory. - */ -public abstract class DirectoryTreeModule implements Module { - - protected final File root; - - /** - * @param root a directory - */ - DirectoryTreeModule(File root) throws IllegalArgumentException { - this.root = root; - if (root == null) { - throw new IllegalArgumentException("null root"); - } - if (!root.isDirectory()) { - throw new IllegalArgumentException("root is not a directory " + root); - } - } - - /** - * returns null if unsuccessful in creating FileModule - */ - protected abstract FileModule makeFile(File file); - - protected abstract boolean includeFile(File file); - - private Set getEntriesRecursive(File dir) { - Set result = HashSetFactory.make(); - File[] files = dir.listFiles(); - if (files != null) { - for (int i = 0; i < files.length; i++) { - if (files[i].isDirectory()) { - result.addAll(getEntriesRecursive(files[i])); - } else if (includeFile(files[i])) { - FileModule fileModule = makeFile(files[i]); - if (fileModule != null) { - result.add(fileModule); - } - } - } - } else { - // TODO: replace this with a real warning when the WarningSets are - // revamped - System.err.println(("Warning: failed to retrieve files in " + dir)); - } - - return result; - } - - public Iterator getEntries() { - return getEntriesRecursive(root).iterator(); - } - - public String getPath() { - return root.getAbsolutePath(); - } - - @Override - public String toString() { - return getClass().getName() + ":" + getPath(); - } - - @Override - public int hashCode() { - final int prime = 31; - int result = 1; - result = prime * result + ((root == null) ? 0 : root.hashCode()); - return result; - } - - @Override - public boolean equals(Object obj) { - if (this == obj) - return true; - if (obj == null) - return false; - if (getClass() != obj.getClass()) - return false; - final DirectoryTreeModule other = (DirectoryTreeModule) obj; - if (root == null) { - if (other.root != null) - return false; - } else if (!root.equals(other.root)) - return false; - return true; - } -} +/******************************************************************************* + * 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.Iterator; +import java.util.Set; + +import com.ibm.wala.util.collections.HashSetFactory; + +/** + * A module containing files under some directory. + */ +public abstract class DirectoryTreeModule implements Module { + + protected final File root; + + /** + * @param root a directory + */ + DirectoryTreeModule(File root) throws IllegalArgumentException { + this.root = root; + if (root == null) { + throw new IllegalArgumentException("null root"); + } + if (!root.isDirectory()) { + throw new IllegalArgumentException("root is not a directory " + root); + } + } + + /** + * returns null if unsuccessful in creating FileModule + */ + protected abstract FileModule makeFile(File file); + + protected abstract boolean includeFile(File file); + + private Set getEntriesRecursive(File dir) { + Set result = HashSetFactory.make(); + File[] files = dir.listFiles(); + if (files != null) { + for (int i = 0; i < files.length; i++) { + if (files[i].isDirectory()) { + result.addAll(getEntriesRecursive(files[i])); + } else if (includeFile(files[i])) { + FileModule fileModule = makeFile(files[i]); + if (fileModule != null) { + result.add(fileModule); + } + } + } + } else { + // TODO: replace this with a real warning when the WarningSets are + // revamped + System.err.println(("Warning: failed to retrieve files in " + dir)); + } + + return result; + } + + public Iterator getEntries() { + return getEntriesRecursive(root).iterator(); + } + + public String getPath() { + return root.getAbsolutePath(); + } + + @Override + public String toString() { + return getClass().getName() + ":" + getPath(); + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((root == null) ? 0 : root.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + final DirectoryTreeModule other = (DirectoryTreeModule) obj; + if (root == null) { + if (other.root != null) + return false; + } else if (!root.equals(other.root)) + return false; + return true; + } +} diff --git a/com.ibm.wala.core/src/com/ibm/wala/classLoader/FieldImpl.java b/com.ibm.wala.core/src/com/ibm/wala/classLoader/FieldImpl.java index 0cba27510..141233efe 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/classLoader/FieldImpl.java +++ b/com.ibm.wala.core/src/com/ibm/wala/classLoader/FieldImpl.java @@ -1,133 +1,133 @@ -/******************************************************************************* - * 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.Collections; - -import com.ibm.wala.ipa.cha.IClassHierarchy; -import com.ibm.wala.shrikeCT.ClassConstants; -import com.ibm.wala.types.FieldReference; -import com.ibm.wala.types.TypeReference; -import com.ibm.wala.types.annotations.Annotation; -import com.ibm.wala.util.strings.Atom; - -/** - * Implementation of a canonical field reference. TODO: canonicalize these? - * TODO: don't cache fieldType here .. move to class? - */ -public final class FieldImpl implements IField { - - private final IClass declaringClass; - - private final FieldReference fieldRef; - - private final int accessFlags; - - private final Collection annotations; - - public FieldImpl(IClass declaringClass, FieldReference canonicalRef, int accessFlags, Collection annotations) { - this.declaringClass = declaringClass; - this.fieldRef = canonicalRef; - this.accessFlags = accessFlags; - this.annotations = annotations; - if (declaringClass == null) { - throw new IllegalArgumentException("null declaringClass"); - } - if (fieldRef == null) { - throw new IllegalArgumentException("null canonicalRef"); - } - } - - /* - * @see com.ibm.wala.classLoader.IMember#getDeclaringClass() - */ - public IClass getDeclaringClass() { - return declaringClass; - } - - /* - * @see java.lang.Object#equals(java.lang.Object) - */ - @Override - 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; - } - } - - @Override - public int hashCode() { - return 87049 * declaringClass.hashCode() + fieldRef.hashCode(); - } - - @Override - public String toString() { - FieldReference fr = getReference(); - return fr.toString(); - } - - public FieldReference getReference() { - return FieldReference.findOrCreate(getDeclaringClass().getReference(), getName(), getFieldTypeReference()); - } - - /* - * @see com.ibm.wala.classLoader.IMember#getName() - */ - public Atom getName() { - return fieldRef.getName(); - } - - /* - * @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); - } - - public boolean isVolatile() { - return ((accessFlags & ClassConstants.ACC_VOLATILE) != 0); - } - - public IClassHierarchy getClassHierarchy() { - return declaringClass.getClassHierarchy(); - } - - public Collection getAnnotations() { - return annotations == null ? null : Collections.unmodifiableCollection(annotations); - } - - +/******************************************************************************* + * 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.Collections; + +import com.ibm.wala.ipa.cha.IClassHierarchy; +import com.ibm.wala.shrikeCT.ClassConstants; +import com.ibm.wala.types.FieldReference; +import com.ibm.wala.types.TypeReference; +import com.ibm.wala.types.annotations.Annotation; +import com.ibm.wala.util.strings.Atom; + +/** + * Implementation of a canonical field reference. TODO: canonicalize these? + * TODO: don't cache fieldType here .. move to class? + */ +public final class FieldImpl implements IField { + + private final IClass declaringClass; + + private final FieldReference fieldRef; + + private final int accessFlags; + + private final Collection annotations; + + public FieldImpl(IClass declaringClass, FieldReference canonicalRef, int accessFlags, Collection annotations) { + this.declaringClass = declaringClass; + this.fieldRef = canonicalRef; + this.accessFlags = accessFlags; + this.annotations = annotations; + if (declaringClass == null) { + throw new IllegalArgumentException("null declaringClass"); + } + if (fieldRef == null) { + throw new IllegalArgumentException("null canonicalRef"); + } + } + + /* + * @see com.ibm.wala.classLoader.IMember#getDeclaringClass() + */ + public IClass getDeclaringClass() { + return declaringClass; + } + + /* + * @see java.lang.Object#equals(java.lang.Object) + */ + @Override + 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; + } + } + + @Override + public int hashCode() { + return 87049 * declaringClass.hashCode() + fieldRef.hashCode(); + } + + @Override + public String toString() { + FieldReference fr = getReference(); + return fr.toString(); + } + + public FieldReference getReference() { + return FieldReference.findOrCreate(getDeclaringClass().getReference(), getName(), getFieldTypeReference()); + } + + /* + * @see com.ibm.wala.classLoader.IMember#getName() + */ + public Atom getName() { + return fieldRef.getName(); + } + + /* + * @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); + } + + public boolean isVolatile() { + return ((accessFlags & ClassConstants.ACC_VOLATILE) != 0); + } + + public IClassHierarchy getClassHierarchy() { + return declaringClass.getClassHierarchy(); + } + + public Collection getAnnotations() { + return annotations == null ? null : Collections.unmodifiableCollection(annotations); + } + + } \ No newline at end of file diff --git a/com.ibm.wala.core/src/com/ibm/wala/classLoader/FileModule.java b/com.ibm.wala.core/src/com/ibm/wala/classLoader/FileModule.java index e09fee1c9..39996da22 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/classLoader/FileModule.java +++ b/com.ibm.wala.core/src/com/ibm/wala/classLoader/FileModule.java @@ -1,110 +1,110 @@ -/******************************************************************************* - * 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; -import com.ibm.wala.util.debug.UnimplementedError; - -/** - * A module which is a wrapper around a file in the filesystem - */ -public abstract class FileModule implements Module, ModuleEntry { - - private final File file; - - public FileModule(File f) throws IllegalArgumentException { - if (f == null) { - throw new IllegalArgumentException("f is null"); - } - this.file = f; - if (!f.exists()) { - throw new IllegalArgumentException("bad file " + f.getAbsolutePath()); - } - } - - public String getAbsolutePath() { - return file.getAbsolutePath(); - } - - /* - * @see com.ibm.wala.classLoader.Module#getEntries() - */ - public Iterator getEntries() { - return new NonNullSingletonIterator(this); - } - - @Override - public int hashCode() { - return file.hashCode(); - } - - @Override - public boolean equals(Object o) { - if (o == null) { - return false; - } - if (o.getClass().equals(getClass())) { - FileModule other = (FileModule) o; - return getName().equals(other.getName()); - } else { - return false; - } - } - - /* - * @see com.ibm.wala.classLoader.ModuleEntry#getName() - */ - public String getName() { - return file.getName(); - } - - /* - * @see com.ibm.wala.classLoader.ModuleEntry#getInputStream() - */ - public InputStream getInputStream() { - try { - if (!file.exists()) { - System.err.println("PANIC: File does not exist! " + file); - } - return new FileInputStream(file); - } catch (FileNotFoundException e) { - e.printStackTrace(); - Assertions.UNREACHABLE("could not read " + file); - return null; - } - } - - /* - * @see com.ibm.wala.classLoader.ModuleEntry#isModuleFile() - */ - public boolean isModuleFile() { - return false; - } - - /** - * @return Returns the file. - */ - public File getFile() { - return file; - } - - public Module asModule() throws UnimplementedError { - Assertions.UNREACHABLE("implement me"); - return null; - } -} +/******************************************************************************* + * 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; +import com.ibm.wala.util.debug.UnimplementedError; + +/** + * A module which is a wrapper around a file in the filesystem + */ +public abstract class FileModule implements Module, ModuleEntry { + + private final File file; + + public FileModule(File f) throws IllegalArgumentException { + if (f == null) { + throw new IllegalArgumentException("f is null"); + } + this.file = f; + if (!f.exists()) { + throw new IllegalArgumentException("bad file " + f.getAbsolutePath()); + } + } + + public String getAbsolutePath() { + return file.getAbsolutePath(); + } + + /* + * @see com.ibm.wala.classLoader.Module#getEntries() + */ + public Iterator getEntries() { + return new NonNullSingletonIterator(this); + } + + @Override + public int hashCode() { + return file.hashCode(); + } + + @Override + public boolean equals(Object o) { + if (o == null) { + return false; + } + if (o.getClass().equals(getClass())) { + FileModule other = (FileModule) o; + return getName().equals(other.getName()); + } else { + return false; + } + } + + /* + * @see com.ibm.wala.classLoader.ModuleEntry#getName() + */ + public String getName() { + return file.getName(); + } + + /* + * @see com.ibm.wala.classLoader.ModuleEntry#getInputStream() + */ + public InputStream getInputStream() { + try { + if (!file.exists()) { + System.err.println("PANIC: File does not exist! " + file); + } + return new FileInputStream(file); + } catch (FileNotFoundException e) { + e.printStackTrace(); + Assertions.UNREACHABLE("could not read " + file); + return null; + } + } + + /* + * @see com.ibm.wala.classLoader.ModuleEntry#isModuleFile() + */ + public boolean isModuleFile() { + return false; + } + + /** + * @return Returns the file. + */ + public File getFile() { + return file; + } + + public Module asModule() throws UnimplementedError { + Assertions.UNREACHABLE("implement me"); + return null; + } +} diff --git a/com.ibm.wala.core/src/com/ibm/wala/classLoader/IClass.java b/com.ibm.wala.core/src/com/ibm/wala/classLoader/IClass.java index 03fa72f41..514e84bc1 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/classLoader/IClass.java +++ b/com.ibm.wala.core/src/com/ibm/wala/classLoader/IClass.java @@ -1,181 +1,181 @@ -/******************************************************************************* - * 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.Collection; -import java.util.NoSuchElementException; - -import com.ibm.wala.ipa.cha.IClassHierarchyDweller; -import com.ibm.wala.types.Selector; -import com.ibm.wala.types.TypeName; -import com.ibm.wala.types.TypeReference; -import com.ibm.wala.util.strings.Atom; - -/** - * Basic interface for an object that represents a single Java class for analysis purposes, including array classes. - */ -public interface IClass extends IClassHierarchyDweller { - - /** - * 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? - */ - boolean isInterface(); - - /** - * @return true iff this class is abstract - */ - boolean isAbstract(); - - /** - * @return true iff this class is public - */ - boolean isPublic(); - - /** - * @return true iff this class is private - */ - boolean isPrivate(); - - /** - * 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() throws UnsupportedOperationException; - - /** - * @return the superclass, or null if java.lang.Object - * @throws IllegalStateException if there's some problem determining the superclass - */ - IClass getSuperclass(); - - /** - * @return Collection of (IClass) interfaces this class directly implements. If this class is an interface, returns the interfaces - * it immediately extends. - */ - Collection getDirectInterfaces(); - - /** - * @return Collection of (IClass) interfaces this class implements, including all ancestors of interfaces immediately implemented. - * If this class is an interface, it returns all super-interfaces. - */ - Collection getAllImplementedInterfaces(); - - /** - * 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. - * - * @throws IllegalStateException if the class contains multiple fields with name name. - */ - IField getField(Atom name); - - /** - * Finds a field, given a name and a type. Returns null if not found. - */ - IField getField(Atom name, TypeName type); - - /** - * @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 - * @throws NoSuchElementException if this class was generated from more than one source file - * The assumption that a class is generated from a single source file is java - * specific, and will change in the future. In place of this API, use the APIs in IClassLoader. - * SJF .. we should think about this deprecation. postponing deprecation for now. - */ - String getSourceFileName() throws NoSuchElementException; - - /** - * @return String representing the source file holding this class, or null if not found - * @throws NoSuchElementException if this class was generated from more than one source file - * The assumption that a class is generated from a single source file is java - * specific, and will change in the future. In place of this API, use the APIs in IClassLoader. - * SJF .. we should think about this deprecation. postponing deprecation for now. - */ - InputStream getSource() throws NoSuchElementException; - - /** - * @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. - */ - Collection getDeclaredMethods(); - - /** - * Compute the instance fields declared by this class or any of its superclasses. - */ - Collection getAllInstanceFields(); - - /** - * Compute the static fields declared by this class or any of its superclasses. - */ - Collection getAllStaticFields(); - - /** - * Compute the instance and static fields declared by this class or any of its superclasses. - */ - Collection getAllFields(); - - /** - * Compute the methods declared by this class or any of its superclasses. - */ - Collection getAllMethods(); - - /** - * Compute the instance fields declared by this class. - * - * @return Collection of IFields - */ - Collection getDeclaredInstanceFields(); - - /** - * @return Collection of IField - */ - Collection 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(); - -} +/******************************************************************************* + * 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.Collection; +import java.util.NoSuchElementException; + +import com.ibm.wala.ipa.cha.IClassHierarchyDweller; +import com.ibm.wala.types.Selector; +import com.ibm.wala.types.TypeName; +import com.ibm.wala.types.TypeReference; +import com.ibm.wala.util.strings.Atom; + +/** + * Basic interface for an object that represents a single Java class for analysis purposes, including array classes. + */ +public interface IClass extends IClassHierarchyDweller { + + /** + * 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? + */ + boolean isInterface(); + + /** + * @return true iff this class is abstract + */ + boolean isAbstract(); + + /** + * @return true iff this class is public + */ + boolean isPublic(); + + /** + * @return true iff this class is private + */ + boolean isPrivate(); + + /** + * 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() throws UnsupportedOperationException; + + /** + * @return the superclass, or null if java.lang.Object + * @throws IllegalStateException if there's some problem determining the superclass + */ + IClass getSuperclass(); + + /** + * @return Collection of (IClass) interfaces this class directly implements. If this class is an interface, returns the interfaces + * it immediately extends. + */ + Collection getDirectInterfaces(); + + /** + * @return Collection of (IClass) interfaces this class implements, including all ancestors of interfaces immediately implemented. + * If this class is an interface, it returns all super-interfaces. + */ + Collection getAllImplementedInterfaces(); + + /** + * 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. + * + * @throws IllegalStateException if the class contains multiple fields with name name. + */ + IField getField(Atom name); + + /** + * Finds a field, given a name and a type. Returns null if not found. + */ + IField getField(Atom name, TypeName type); + + /** + * @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 + * @throws NoSuchElementException if this class was generated from more than one source file + * The assumption that a class is generated from a single source file is java + * specific, and will change in the future. In place of this API, use the APIs in IClassLoader. + * SJF .. we should think about this deprecation. postponing deprecation for now. + */ + String getSourceFileName() throws NoSuchElementException; + + /** + * @return String representing the source file holding this class, or null if not found + * @throws NoSuchElementException if this class was generated from more than one source file + * The assumption that a class is generated from a single source file is java + * specific, and will change in the future. In place of this API, use the APIs in IClassLoader. + * SJF .. we should think about this deprecation. postponing deprecation for now. + */ + InputStream getSource() throws NoSuchElementException; + + /** + * @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. + */ + Collection getDeclaredMethods(); + + /** + * Compute the instance fields declared by this class or any of its superclasses. + */ + Collection getAllInstanceFields(); + + /** + * Compute the static fields declared by this class or any of its superclasses. + */ + Collection getAllStaticFields(); + + /** + * Compute the instance and static fields declared by this class or any of its superclasses. + */ + Collection getAllFields(); + + /** + * Compute the methods declared by this class or any of its superclasses. + */ + Collection getAllMethods(); + + /** + * Compute the instance fields declared by this class. + * + * @return Collection of IFields + */ + Collection getDeclaredInstanceFields(); + + /** + * @return Collection of IField + */ + Collection 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(); + +} diff --git a/com.ibm.wala.core/src/com/ibm/wala/classLoader/IClassLoader.java b/com.ibm.wala.core/src/com/ibm/wala/classLoader/IClassLoader.java index f892fdead..b459e94e0 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/classLoader/IClassLoader.java +++ b/com.ibm.wala.core/src/com/ibm/wala/classLoader/IClassLoader.java @@ -1,128 +1,128 @@ -/******************************************************************************* - * Copyright (c) 2002 - 2006 IBM Corporation. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * IBM Corporation - initial API and implementation - *******************************************************************************/ - -package com.ibm.wala.classLoader; - -import java.io.IOException; -import java.io.InputStream; -import java.util.Collection; -import java.util.Iterator; -import java.util.List; -import java.util.NoSuchElementException; - -import com.ibm.wala.ssa.SSAInstructionFactory; -import com.ibm.wala.types.ClassLoaderReference; -import com.ibm.wala.types.TypeName; -import com.ibm.wala.util.strings.Atom; - -/** - * Base class for an object that represents a single Java classloader for analysis purposes. - */ -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 classes loaded by this loader - */ - public abstract Iterator 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(); - - /** - * @return the unique name that identifies the programming language from which this class loader loads code. - */ - Language getLanguage(); - - SSAInstructionFactory getInstructionFactory(); - - public abstract int getNumberOfMethods(); - - /** - * @param method The method for which information is desired - * @param offset an offset into the bytecode of the given method. - * @return name of the source file corresponding to the given offset in the given method. Note that - * this api allows a single method to arise from multiple source files, which is deliberate as it - * can happen in some languages. - */ - public abstract String getSourceFileName(IMethod method, int offset); - - /** - * @param method The method for which information is desired - * @param offset an offset into the bytecode of the given method. - * @return input stream representing the source file for a given bytecode index of a given method, - * or null if not available - */ - public abstract InputStream getSource(IMethod method, int offset); - - /** - * @param klass the class for which information is desired. - * @return name of source file corresponding to the class, or null if not available - * @throws NoSuchElementException if this class was generated from more than one source file - * The assumption that a class is generated from a single source file is java - * specific, and will change in the future. In place of this API, use the version that takes - * a method and an offset, since that is now the granularity at which source file information - * will be recorded. - * SJF .. we should think about this deprecation. postponing deprecation for now. - */ - public abstract String getSourceFileName(IClass klass) throws NoSuchElementException; - - /** - * @return input stream representing the source file for a class, or null if not available - * @throws NoSuchElementException if this class was generated from more than one source file - * The assumption that a class is generated from a single source file is java - * specific, and will change in the future. In place of this API, use the version that takes - * a method and an offset, since that is now the granularity at which source file information - * will be recorded. - * SJF .. we should think about this deprecation. postponing deprecation for now. - */ - public abstract InputStream getSource(IClass klass) throws NoSuchElementException; - - /** - * @return the parent IClassLoader, if any, or null - */ - public abstract IClassLoader getParent(); - - /** - * Initialize internal data structures. - * - * @throws IOException - * @throws IllegalArgumentException if modules is null - */ - public void init(List modules) throws IOException; - - /** - * blow away references to any classes in the set - * - * @param toRemove Collection - */ - public abstract void removeAll(Collection toRemove); -} +/******************************************************************************* + * 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.util.Collection; +import java.util.Iterator; +import java.util.List; +import java.util.NoSuchElementException; + +import com.ibm.wala.ssa.SSAInstructionFactory; +import com.ibm.wala.types.ClassLoaderReference; +import com.ibm.wala.types.TypeName; +import com.ibm.wala.util.strings.Atom; + +/** + * Base class for an object that represents a single Java classloader for analysis purposes. + */ +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 classes loaded by this loader + */ + public abstract Iterator 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(); + + /** + * @return the unique name that identifies the programming language from which this class loader loads code. + */ + Language getLanguage(); + + SSAInstructionFactory getInstructionFactory(); + + public abstract int getNumberOfMethods(); + + /** + * @param method The method for which information is desired + * @param offset an offset into the bytecode of the given method. + * @return name of the source file corresponding to the given offset in the given method. Note that + * this api allows a single method to arise from multiple source files, which is deliberate as it + * can happen in some languages. + */ + public abstract String getSourceFileName(IMethod method, int offset); + + /** + * @param method The method for which information is desired + * @param offset an offset into the bytecode of the given method. + * @return input stream representing the source file for a given bytecode index of a given method, + * or null if not available + */ + public abstract InputStream getSource(IMethod method, int offset); + + /** + * @param klass the class for which information is desired. + * @return name of source file corresponding to the class, or null if not available + * @throws NoSuchElementException if this class was generated from more than one source file + * The assumption that a class is generated from a single source file is java + * specific, and will change in the future. In place of this API, use the version that takes + * a method and an offset, since that is now the granularity at which source file information + * will be recorded. + * SJF .. we should think about this deprecation. postponing deprecation for now. + */ + public abstract String getSourceFileName(IClass klass) throws NoSuchElementException; + + /** + * @return input stream representing the source file for a class, or null if not available + * @throws NoSuchElementException if this class was generated from more than one source file + * The assumption that a class is generated from a single source file is java + * specific, and will change in the future. In place of this API, use the version that takes + * a method and an offset, since that is now the granularity at which source file information + * will be recorded. + * SJF .. we should think about this deprecation. postponing deprecation for now. + */ + public abstract InputStream getSource(IClass klass) throws NoSuchElementException; + + /** + * @return the parent IClassLoader, if any, or null + */ + public abstract IClassLoader getParent(); + + /** + * Initialize internal data structures. + * + * @throws IOException + * @throws IllegalArgumentException if modules is null + */ + public void init(List modules) throws IOException; + + /** + * blow away references to any classes in the set + * + * @param toRemove Collection + */ + public abstract void removeAll(Collection toRemove); +} diff --git a/com.ibm.wala.core/src/com/ibm/wala/classLoader/IField.java b/com.ibm.wala.core/src/com/ibm/wala/classLoader/IField.java index d985e8b4f..e04c7730c 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/classLoader/IField.java +++ b/com.ibm.wala.core/src/com/ibm/wala/classLoader/IField.java @@ -1,46 +1,46 @@ -/******************************************************************************* - * Copyright (c) 2002 - 2006 IBM Corporation. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * IBM Corporation - initial API and implementation - *******************************************************************************/ -package com.ibm.wala.classLoader; - -import com.ibm.wala.types.FieldReference; -import com.ibm.wala.types.TypeReference; - -/** - */ -public interface IField extends IMember { - - /** - * @return the canonical TypeReference of the declared type of the field - */ - public TypeReference getFieldTypeReference(); - - /** - * @return canonical FieldReference representing this field - */ - public FieldReference getReference(); - - /** - * Is this field final? - */ - public boolean isFinal(); - - public boolean isPrivate(); - public boolean isProtected(); - public boolean isPublic(); - public boolean isStatic(); - - /** - * Is this member volatile? - */ - boolean isVolatile(); - - -} +/******************************************************************************* + * 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; + +/** + */ +public interface IField extends IMember { + + /** + * @return the canonical TypeReference of the declared type of the field + */ + public TypeReference getFieldTypeReference(); + + /** + * @return canonical FieldReference representing this field + */ + public FieldReference getReference(); + + /** + * Is this field final? + */ + public boolean isFinal(); + + public boolean isPrivate(); + public boolean isProtected(); + public boolean isPublic(); + public boolean isStatic(); + + /** + * Is this member volatile? + */ + boolean isVolatile(); + + +} diff --git a/com.ibm.wala.core/src/com/ibm/wala/classLoader/IMember.java b/com.ibm.wala.core/src/com/ibm/wala/classLoader/IMember.java index 740338baf..6fe0d690a 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/classLoader/IMember.java +++ b/com.ibm.wala.core/src/com/ibm/wala/classLoader/IMember.java @@ -1,41 +1,41 @@ -/******************************************************************************* - * 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.IClassHierarchyDweller; -import com.ibm.wala.util.strings.Atom; - -/** - * Basic interface for an object that represents a single - * Java member (method or field) for analysis purposes. - */ -public interface IMember extends IClassHierarchyDweller { - - /** - * 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 member static? - */ - boolean isStatic(); - -} +/******************************************************************************* + * 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.IClassHierarchyDweller; +import com.ibm.wala.util.strings.Atom; + +/** + * Basic interface for an object that represents a single + * Java member (method or field) for analysis purposes. + */ +public interface IMember extends IClassHierarchyDweller { + + /** + * 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 member static? + */ + boolean isStatic(); + +} diff --git a/com.ibm.wala.core/src/com/ibm/wala/classLoader/IMethod.java b/com.ibm.wala.core/src/com/ibm/wala/classLoader/IMethod.java index bbd810b7a..1e342097a 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/classLoader/IMethod.java +++ b/com.ibm.wala.core/src/com/ibm/wala/classLoader/IMethod.java @@ -1,141 +1,141 @@ -/******************************************************************************* - * 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.shrikeCT.InvalidClassFileException; -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. - */ -public interface IMethod extends IMember, ContextItem { - - /** - * Is this method synchronized? - */ - boolean isSynchronized(); - - /** - * Is this method a class initializer? - */ - boolean isClinit(); - - /** - * Is this method an object initializer? - */ - boolean isInit(); - - /** - * Is this method native? - */ - boolean isNative(); - - /** - * Did someone synthesize this method? (As opposed to reading it from a class file) - */ - boolean isSynthetic(); - - /** - * Is this method abstract? - */ - boolean isAbstract(); - - /** - * Is this method private? - */ - boolean isPrivate(); - - /** - * Is this method protected? - */ - boolean isProtected(); - - /** - * Is this method public? - */ - boolean isPublic(); - - /** - * Is this method final? - */ - boolean isFinal(); - - /** - * Is this method a bridge method? See JLS 3rd Edition 15.12.4.5 - */ - boolean isBridge(); - - /** - * @return canonical MethodReference corresponding to this method - */ - MethodReference getReference(); - - /** - * @return true iff this method has at least one exception handler - */ - boolean hasExceptionHandler(); - - /** - * 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 - * @throws InvalidClassFileException - */ - TypeReference[] getDeclaredExceptions() throws InvalidClassFileException, UnsupportedOperationException; - - /** - * @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); - - /** - * something like: com.foo.bar.createLargeOrder(IILjava.lang.String;SLjava.sql.Date;)Ljava.lang.Integer; - */ - public String getSignature(); - - /** - * something like: foo(Ljava/langString;)Ljava/lang/Class; - */ - public Selector getSelector(); - - /** - * something like: (IILjava.lang.String;SLjava.sql.Date;)Ljava.lang.Integer; - */ - Descriptor getDescriptor(); - - /** - * @return true iff the local variable table information for this method is available - */ - boolean hasLocalVariableTable(); -} +/******************************************************************************* + * 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.shrikeCT.InvalidClassFileException; +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. + */ +public interface IMethod extends IMember, ContextItem { + + /** + * Is this method synchronized? + */ + boolean isSynchronized(); + + /** + * Is this method a class initializer? + */ + boolean isClinit(); + + /** + * Is this method an object initializer? + */ + boolean isInit(); + + /** + * Is this method native? + */ + boolean isNative(); + + /** + * Did someone synthesize this method? (As opposed to reading it from a class file) + */ + boolean isSynthetic(); + + /** + * Is this method abstract? + */ + boolean isAbstract(); + + /** + * Is this method private? + */ + boolean isPrivate(); + + /** + * Is this method protected? + */ + boolean isProtected(); + + /** + * Is this method public? + */ + boolean isPublic(); + + /** + * Is this method final? + */ + boolean isFinal(); + + /** + * Is this method a bridge method? See JLS 3rd Edition 15.12.4.5 + */ + boolean isBridge(); + + /** + * @return canonical MethodReference corresponding to this method + */ + MethodReference getReference(); + + /** + * @return true iff this method has at least one exception handler + */ + boolean hasExceptionHandler(); + + /** + * 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 + * @throws InvalidClassFileException + */ + TypeReference[] getDeclaredExceptions() throws InvalidClassFileException, UnsupportedOperationException; + + /** + * @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); + + /** + * something like: com.foo.bar.createLargeOrder(IILjava.lang.String;SLjava.sql.Date;)Ljava.lang.Integer; + */ + public String getSignature(); + + /** + * something like: foo(Ljava/langString;)Ljava/lang/Class; + */ + public Selector getSelector(); + + /** + * something like: (IILjava.lang.String;SLjava.sql.Date;)Ljava.lang.Integer; + */ + Descriptor getDescriptor(); + + /** + * @return true iff the local variable table information for this method is available + */ + boolean hasLocalVariableTable(); +} diff --git a/com.ibm.wala.core/src/com/ibm/wala/classLoader/JarFileEntry.java b/com.ibm.wala.core/src/com/ibm/wala/classLoader/JarFileEntry.java index 388df5ec0..0161d1a80 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/classLoader/JarFileEntry.java +++ b/com.ibm.wala.core/src/com/ibm/wala/classLoader/JarFileEntry.java @@ -1,124 +1,124 @@ -/******************************************************************************* - * 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. - */ -public class JarFileEntry implements ModuleEntry { - - private final String entryName; - - private final JarFileModule jarFileModule; - - private final JarFile jarFile; - - protected JarFileEntry(String entryName, JarFileModule jarFile) { - this.entryName = entryName; - this.jarFileModule = jarFile; - this.jarFile = jarFile.getJarFile(); - } - - /* - * @see com.ibm.wala.classLoader.ModuleEntry#getName() - */ - public String getName() { - return entryName; - } - - /* - * @see com.ibm.wala.classLoader.ModuleEntry#isClassFile() - */ - public boolean isClassFile() { - return FileSuffixes.isClassFile(getName()); - } - - /* - * @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; - } - } - - /* - * @see com.ibm.wala.classLoader.ModuleEntry#getSize() - */ - public long getSize() { - // TODO: cache this? - return jarFile.getEntry(entryName).getSize(); - } - - @Override - public String toString() { - // TODO Auto-generated method stub - return jarFile.getName() + ":" + getName(); - } - - /* - * @see com.ibm.wala.classLoader.ModuleEntry#isModuleFile() - */ - public boolean isModuleFile() { - return FileSuffixes.isJarFile(getName()) || FileSuffixes.isWarFile(getName()); - } - - /* - * @see com.ibm.wala.classLoader.ModuleEntry#asModule() - */ - public Module asModule() { - return new NestedJarFileModule(jarFileModule, jarFile.getEntry(entryName)); - } - - public JarFile getJarFile() { - return jarFile; - } - - protected JarFileModule getJarFileModule() { - return jarFileModule; - } - - @Override - public int hashCode() { - return entryName.hashCode() * 5059 + jarFile.hashCode(); - } - - /* - * @see com.ibm.wala.classLoader.ModuleEntry#getClassName() - */ - public String getClassName() { - return FileSuffixes.stripSuffix(getName()); - } - - /* - * @see com.ibm.wala.classLoader.ModuleEntry#isSourceFile() - */ - public boolean isSourceFile() { - return FileSuffixes.isSourceFile(getName()); - } - - @Override - public boolean equals(Object obj) { - return this == obj; - } -} +/******************************************************************************* + * 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. + */ +public class JarFileEntry implements ModuleEntry { + + private final String entryName; + + private final JarFileModule jarFileModule; + + private final JarFile jarFile; + + protected JarFileEntry(String entryName, JarFileModule jarFile) { + this.entryName = entryName; + this.jarFileModule = jarFile; + this.jarFile = jarFile.getJarFile(); + } + + /* + * @see com.ibm.wala.classLoader.ModuleEntry#getName() + */ + public String getName() { + return entryName; + } + + /* + * @see com.ibm.wala.classLoader.ModuleEntry#isClassFile() + */ + public boolean isClassFile() { + return FileSuffixes.isClassFile(getName()); + } + + /* + * @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; + } + } + + /* + * @see com.ibm.wala.classLoader.ModuleEntry#getSize() + */ + public long getSize() { + // TODO: cache this? + return jarFile.getEntry(entryName).getSize(); + } + + @Override + public String toString() { + // TODO Auto-generated method stub + return jarFile.getName() + ":" + getName(); + } + + /* + * @see com.ibm.wala.classLoader.ModuleEntry#isModuleFile() + */ + public boolean isModuleFile() { + return FileSuffixes.isJarFile(getName()) || FileSuffixes.isWarFile(getName()); + } + + /* + * @see com.ibm.wala.classLoader.ModuleEntry#asModule() + */ + public Module asModule() { + return new NestedJarFileModule(jarFileModule, jarFile.getEntry(entryName)); + } + + public JarFile getJarFile() { + return jarFile; + } + + protected JarFileModule getJarFileModule() { + return jarFileModule; + } + + @Override + public int hashCode() { + return entryName.hashCode() * 5059 + jarFile.hashCode(); + } + + /* + * @see com.ibm.wala.classLoader.ModuleEntry#getClassName() + */ + public String getClassName() { + return FileSuffixes.stripSuffix(getName()); + } + + /* + * @see com.ibm.wala.classLoader.ModuleEntry#isSourceFile() + */ + public boolean isSourceFile() { + return FileSuffixes.isSourceFile(getName()); + } + + @Override + public boolean equals(Object obj) { + return this == obj; + } +} diff --git a/com.ibm.wala.core/src/com/ibm/wala/classLoader/JarFileModule.java b/com.ibm.wala.core/src/com/ibm/wala/classLoader/JarFileModule.java index 51d3bbd7b..dc7dd536b 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/classLoader/JarFileModule.java +++ b/com.ibm.wala.core/src/com/ibm/wala/classLoader/JarFileModule.java @@ -1,118 +1,118 @@ -/******************************************************************************* - * 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.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.collections.HashMapFactory; -import com.ibm.wala.util.collections.HashSetFactory; -import com.ibm.wala.util.debug.Assertions; -import com.ibm.wala.util.io.FileUtil; -import com.ibm.wala.util.ref.CacheReference; - -/** - * A module which is a wrapper around a Jar file - */ -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 cache = HashMapFactory.make(); - - public JarFileModule(JarFile f) { - if (f == null) { - throw new IllegalArgumentException("null f"); - } - this.file = f; - } - - public String getAbsolutePath() { - return file.getName(); - } - - @Override - public String toString() { - return "JarFileModule:" + file.getName(); - } - - protected ModuleEntry createEntry(ZipEntry z) { - return new JarFileEntry(z.getName(), this); - } - - /* - * @see com.ibm.wala.classLoader.Module#getEntries() - */ - public Iterator getEntries() { - HashSet result = HashSetFactory.make(); - for (Enumeration e = file.entries(); e.hasMoreElements();) { - ZipEntry Z = (ZipEntry) e.nextElement(); - result.add(createEntry(Z)); - } - return result.iterator(); - } - - // need to do equals() and hashCode() based on file name, since JarFile - // does not implement equals() / hashCode() - - @Override - public int hashCode() { - return file.getName().hashCode(); - } - - @Override - public boolean equals(Object obj) { - if (this == obj) - return true; - if (obj == null) - return false; - if (getClass() != obj.getClass()) - return false; - final JarFileModule other = (JarFileModule) obj; - if (!file.getName().equals(other.file.getName())) - return false; - return true; - } - - public byte[] getContents(ZipEntry entry) { - byte[] b = (byte[]) CacheReference.get(cache.get(entry)); - - if (b != null) { - return b; - } - - try { - InputStream s = file.getInputStream(entry); - byte[] bb = FileUtil.readBytes(s); - cache.put(entry, CacheReference.make(bb)); - s.close(); - return bb; - } catch (IOException e) { - e.printStackTrace(); - Assertions.UNREACHABLE(); - return null; - } - } - - public JarFile getJarFile() { - return file; - } - -} +/******************************************************************************* + * 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.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.collections.HashMapFactory; +import com.ibm.wala.util.collections.HashSetFactory; +import com.ibm.wala.util.debug.Assertions; +import com.ibm.wala.util.io.FileUtil; +import com.ibm.wala.util.ref.CacheReference; + +/** + * A module which is a wrapper around a Jar file + */ +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 cache = HashMapFactory.make(); + + public JarFileModule(JarFile f) { + if (f == null) { + throw new IllegalArgumentException("null f"); + } + this.file = f; + } + + public String getAbsolutePath() { + return file.getName(); + } + + @Override + public String toString() { + return "JarFileModule:" + file.getName(); + } + + protected ModuleEntry createEntry(ZipEntry z) { + return new JarFileEntry(z.getName(), this); + } + + /* + * @see com.ibm.wala.classLoader.Module#getEntries() + */ + public Iterator getEntries() { + HashSet result = HashSetFactory.make(); + for (Enumeration e = file.entries(); e.hasMoreElements();) { + ZipEntry Z = (ZipEntry) e.nextElement(); + result.add(createEntry(Z)); + } + return result.iterator(); + } + + // need to do equals() and hashCode() based on file name, since JarFile + // does not implement equals() / hashCode() + + @Override + public int hashCode() { + return file.getName().hashCode(); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + final JarFileModule other = (JarFileModule) obj; + if (!file.getName().equals(other.file.getName())) + return false; + return true; + } + + public byte[] getContents(ZipEntry entry) { + byte[] b = (byte[]) CacheReference.get(cache.get(entry)); + + if (b != null) { + return b; + } + + try { + InputStream s = file.getInputStream(entry); + byte[] bb = FileUtil.readBytes(s); + cache.put(entry, CacheReference.make(bb)); + s.close(); + return bb; + } catch (IOException e) { + e.printStackTrace(); + Assertions.UNREACHABLE(); + return null; + } + } + + public JarFile getJarFile() { + return file; + } + +} diff --git a/com.ibm.wala.core/src/com/ibm/wala/classLoader/JavaLanguage.java b/com.ibm.wala.core/src/com/ibm/wala/classLoader/JavaLanguage.java index 066c5a0d9..699785859 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/classLoader/JavaLanguage.java +++ b/com.ibm.wala.core/src/com/ibm/wala/classLoader/JavaLanguage.java @@ -1,649 +1,649 @@ -/******************************************************************************* - * Copyright (c) 2009 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 com.ibm.wala.analysis.typeInference.JavaPrimitiveType; -import com.ibm.wala.analysis.typeInference.PrimitiveType; -import com.ibm.wala.ipa.cha.IClassHierarchy; -import com.ibm.wala.shrikeBT.ConstantInstruction; -import com.ibm.wala.shrikeBT.ConstantInstruction.ClassToken; -import com.ibm.wala.shrikeBT.Constants; -import com.ibm.wala.shrikeBT.IBinaryOpInstruction; -import com.ibm.wala.shrikeBT.IComparisonInstruction; -import com.ibm.wala.shrikeBT.IConditionalBranchInstruction; -import com.ibm.wala.shrikeBT.IInstruction; -import com.ibm.wala.shrikeBT.IUnaryOpInstruction; -import com.ibm.wala.shrikeBT.Instruction; -import com.ibm.wala.shrikeCT.InvalidClassFileException; -import com.ibm.wala.ssa.SSAAddressOfInstruction; -import com.ibm.wala.ssa.SSAArrayLengthInstruction; -import com.ibm.wala.ssa.SSAArrayLoadInstruction; -import com.ibm.wala.ssa.SSAArrayStoreInstruction; -import com.ibm.wala.ssa.SSABinaryOpInstruction; -import com.ibm.wala.ssa.SSACheckCastInstruction; -import com.ibm.wala.ssa.SSAComparisonInstruction; -import com.ibm.wala.ssa.SSAConditionalBranchInstruction; -import com.ibm.wala.ssa.SSAConversionInstruction; -import com.ibm.wala.ssa.SSAGetCaughtExceptionInstruction; -import com.ibm.wala.ssa.SSAGetInstruction; -import com.ibm.wala.ssa.SSAGotoInstruction; -import com.ibm.wala.ssa.SSAInstanceofInstruction; -import com.ibm.wala.ssa.SSAInstruction; -import com.ibm.wala.ssa.SSAInstructionFactory; -import com.ibm.wala.ssa.SSAInvokeInstruction; -import com.ibm.wala.ssa.SSALoadIndirectInstruction; -import com.ibm.wala.ssa.SSALoadMetadataInstruction; -import com.ibm.wala.ssa.SSAMonitorInstruction; -import com.ibm.wala.ssa.SSANewInstruction; -import com.ibm.wala.ssa.SSAPhiInstruction; -import com.ibm.wala.ssa.SSAPiInstruction; -import com.ibm.wala.ssa.SSAPutInstruction; -import com.ibm.wala.ssa.SSAReturnInstruction; -import com.ibm.wala.ssa.SSAStoreIndirectInstruction; -import com.ibm.wala.ssa.SSASwitchInstruction; -import com.ibm.wala.ssa.SSAThrowInstruction; -import com.ibm.wala.ssa.SSAUnaryOpInstruction; -import com.ibm.wala.types.ClassLoaderReference; -import com.ibm.wala.types.FieldReference; -import com.ibm.wala.types.MethodReference; -import com.ibm.wala.types.TypeName; -import com.ibm.wala.types.TypeReference; -import com.ibm.wala.util.shrike.Exceptions.MethodResolutionFailure; -import com.ibm.wala.util.shrike.ShrikeUtil; -import com.ibm.wala.util.strings.Atom; -import com.ibm.wala.util.warnings.Warnings; - -/** - * The implementation of {@link Language} which defines Java semantics. - * - */ -public class JavaLanguage extends LanguageImpl implements BytecodeLanguage, Constants { - - public static class JavaInstructionFactory implements SSAInstructionFactory { - public SSAArrayLengthInstruction ArrayLengthInstruction(int result, int arrayref) { - return new SSAArrayLengthInstruction(result, arrayref) { - @Override - public Collection getExceptionTypes() { - return getNullPointerException(); - } - }; - } - - public SSAArrayLoadInstruction ArrayLoadInstruction(int result, int arrayref, int index, TypeReference declaredType) { - return new SSAArrayLoadInstruction(result, arrayref, index, declaredType) { - @Override - public Collection getExceptionTypes() { - return getArrayAccessExceptions(); - } - }; - } - - public SSAArrayStoreInstruction ArrayStoreInstruction(int arrayref, int index, int value, TypeReference declaredType) { - return new SSAArrayStoreInstruction(arrayref, index, value, declaredType) { - @Override - public Collection getExceptionTypes() { - if (typeIsPrimitive()) { - return getArrayAccessExceptions(); - } else { - return getAaStoreExceptions(); - } - } - }; - } - - public SSABinaryOpInstruction BinaryOpInstruction(IBinaryOpInstruction.IOperator operator, boolean overflow, boolean unsigned, - int result, int val1, int val2, boolean mayBeInteger) { - assert !overflow; - assert !unsigned; - return new SSABinaryOpInstruction(operator, result, val1, val2, mayBeInteger) { - - @Override - public SSAInstruction copyForSSA(SSAInstructionFactory insts, int[] defs, int[] uses) { - return insts.BinaryOpInstruction(getOperator(), false, false, defs == null || defs.length == 0 ? getDef(0) : defs[0], - uses == null ? getUse(0) : uses[0], uses == null ? getUse(1) : uses[1], mayBeIntegerOp()); - } - - @Override - public Collection getExceptionTypes() { - if (isPEI()) { - return getArithmeticException(); - } else { - return Collections.emptySet(); - } - } - }; - } - - public SSACheckCastInstruction CheckCastInstruction(int result, int val, int[] typeValues, boolean isPEI) { - throw new UnsupportedOperationException(); - } - - public SSACheckCastInstruction CheckCastInstruction(int result, int val, TypeReference[] types, boolean isPEI) { - assert types.length == 1; - assert isPEI; - return new SSACheckCastInstruction(result, val, types, true) { - @Override - public Collection getExceptionTypes() { - return getClassCastException(); - } - }; - } - - public SSACheckCastInstruction CheckCastInstruction(int result, int val, int typeValue, boolean isPEI) { - assert isPEI; - return CheckCastInstruction(result, val, new int[]{ typeValue }, true); - } - - public SSACheckCastInstruction CheckCastInstruction(int result, int val, TypeReference type, boolean isPEI) { - assert isPEI; - return CheckCastInstruction(result, val, new TypeReference[]{ type }, true); - } - - public SSAComparisonInstruction ComparisonInstruction(IComparisonInstruction.Operator operator, int result, int val1, int val2) { - return new SSAComparisonInstruction(operator, result, val1, val2); - } - - public SSAConditionalBranchInstruction ConditionalBranchInstruction(IConditionalBranchInstruction.IOperator operator, - TypeReference type, int val1, int val2) { - return new SSAConditionalBranchInstruction(operator, type, val1, val2); - } - - public SSAConversionInstruction ConversionInstruction(int result, int val, TypeReference fromType, TypeReference toType, - boolean overflow) { - assert !overflow; - return new SSAConversionInstruction(result, val, fromType, toType) { - @Override - public SSAInstruction copyForSSA(SSAInstructionFactory insts, int[] defs, int[] uses) throws IllegalArgumentException { - if (uses != null && uses.length == 0) { - throw new IllegalArgumentException("(uses != null) and (uses.length == 0)"); - } - return insts.ConversionInstruction(defs == null || defs.length == 0 ? getDef(0) : defs[0], uses == null ? getUse(0) - : uses[0], getFromType(), getToType(), false); - } - }; - } - - public SSAGetCaughtExceptionInstruction GetCaughtExceptionInstruction(int bbNumber, int exceptionValueNumber) { - return new SSAGetCaughtExceptionInstruction(bbNumber, exceptionValueNumber); - } - - public SSAGetInstruction GetInstruction(int result, FieldReference field) { - return new SSAGetInstruction(result, field) { - }; - } - - public SSAGetInstruction GetInstruction(int result, int ref, FieldReference field) { - return new SSAGetInstruction(result, ref, field) { - @Override - public Collection getExceptionTypes() { - return getNullPointerException(); - } - }; - } - - public SSAGotoInstruction GotoInstruction() { - return new SSAGotoInstruction(); - } - - public SSAInstanceofInstruction InstanceofInstruction(int result, int ref, TypeReference checkedType) { - return new SSAInstanceofInstruction(result, ref, checkedType); - } - - public SSAInvokeInstruction InvokeInstruction(int result, int[] params, int exception, CallSiteReference site) { - return new SSAInvokeInstruction(result, params, exception, site) { - @Override - public Collection getExceptionTypes() { - if (!isStatic()) { - return getNullPointerException(); - } else { - return Collections.emptySet(); - } - } - }; - } - - public SSAInvokeInstruction InvokeInstruction(int[] params, int exception, CallSiteReference site) { - return new SSAInvokeInstruction(params, exception, site) { - @Override - public Collection getExceptionTypes() { - if (!isStatic()) { - return getNullPointerException(); - } else { - return Collections.emptySet(); - } - } - }; - } - - public SSAMonitorInstruction MonitorInstruction(int ref, boolean isEnter) { - return new SSAMonitorInstruction(ref, isEnter) { - @Override - public Collection getExceptionTypes() { - return getNullPointerException(); - } - }; - } - - public SSANewInstruction NewInstruction(int result, NewSiteReference site) { - return new SSANewInstruction(result, site) { - @Override - public Collection getExceptionTypes() { - if (getNewSite().getDeclaredType().isArrayType()) { - return getNewArrayExceptions(); - } else { - return getNewScalarExceptions(); - } - } - }; - } - - public SSAPhiInstruction PhiInstruction(int result, int[] params) throws IllegalArgumentException { - return new SSAPhiInstruction(result, params) { - }; - } - - public SSAPutInstruction PutInstruction(int ref, int value, FieldReference field) { - return new SSAPutInstruction(ref, value, field) { - @Override - public Collection getExceptionTypes() { - return getNullPointerException(); - } - }; - } - - public SSAPutInstruction PutInstruction(int value, FieldReference field) { - return new SSAPutInstruction(value, field) { - }; - } - - public SSAReturnInstruction ReturnInstruction() { - return new SSAReturnInstruction(); - } - - public SSAReturnInstruction ReturnInstruction(int result, boolean isPrimitive) { - return new SSAReturnInstruction(result, isPrimitive); - } - - public SSASwitchInstruction SwitchInstruction(int val, int defaultLabel, int[] casesAndLabels) { - return new SSASwitchInstruction(val, defaultLabel, casesAndLabels); - } - - public SSAThrowInstruction ThrowInstruction(int exception) { - return new SSAThrowInstruction(exception) { - @Override - public Collection getExceptionTypes() { - return getNullPointerException(); - } - }; - } - - public SSAUnaryOpInstruction UnaryOpInstruction(IUnaryOpInstruction.IOperator operator, int result, int val) { - return new SSAUnaryOpInstruction(operator, result, val); - } - - public SSALoadMetadataInstruction LoadMetadataInstruction(int lval, TypeReference entityType, Object token) { - return new SSALoadMetadataInstruction(lval, entityType, token) { - @Override - public Collection getExceptionTypes() { - return loadClassExceptions; - } - }; - } - - public SSANewInstruction NewInstruction(int result, NewSiteReference site, int[] params) { - return new SSANewInstruction(result, site, params) { - @Override - public Collection getExceptionTypes() { - return getNewArrayExceptions(); - } - }; - } - - public SSAPiInstruction PiInstruction(int result, int val, int piBlock, int successorBlock, SSAInstruction cause) { - return new SSAPiInstruction(result, val, piBlock, successorBlock, cause); - } - - public SSAAddressOfInstruction AddressOfInstruction(int lval, int local, TypeReference pointeeType) { - throw new UnsupportedOperationException(); - } - - public SSAAddressOfInstruction AddressOfInstruction(int lval, int local, int indexVal, TypeReference pointeeType) { - throw new UnsupportedOperationException(); - } - - public SSAAddressOfInstruction AddressOfInstruction(int lval, int local, FieldReference field, TypeReference pointeeType) { - throw new UnsupportedOperationException(); - } - - public SSALoadIndirectInstruction LoadIndirectInstruction(int lval, TypeReference t, int addressVal) { - throw new UnsupportedOperationException(); - } - - public SSAStoreIndirectInstruction StoreIndirectInstruction(int addressVal, int rval, TypeReference pointeeType) { - throw new UnsupportedOperationException(); - } - } - - private static final Collection arrayAccessExceptions = Collections.unmodifiableCollection(Arrays - .asList(new TypeReference[] { TypeReference.JavaLangNullPointerException, - TypeReference.JavaLangArrayIndexOutOfBoundsException })); - - private static final Collection aaStoreExceptions = Collections.unmodifiableCollection(Arrays - .asList(new TypeReference[] { TypeReference.JavaLangNullPointerException, - TypeReference.JavaLangArrayIndexOutOfBoundsException, TypeReference.JavaLangArrayStoreException })); - - private static final Collection newScalarExceptions = Collections.unmodifiableCollection(Arrays - .asList(new TypeReference[] { TypeReference.JavaLangExceptionInInitializerError, TypeReference.JavaLangOutOfMemoryError })); - - private static final Collection newArrayExceptions = Collections.unmodifiableCollection(Arrays - .asList(new TypeReference[] { TypeReference.JavaLangOutOfMemoryError, TypeReference.JavaLangNegativeArraySizeException })); - - private static final Collection exceptionInInitializerError = Collections - .singleton(TypeReference.JavaLangExceptionInInitializerError); - - private static final Collection nullPointerException = Collections - .singleton(TypeReference.JavaLangNullPointerException); - - private static final Collection arithmeticException = Collections - .singleton(TypeReference.JavaLangArithmeticException); - - private static final Collection classCastException = Collections - .singleton(TypeReference.JavaLangClassCastException); - - private static final Collection classNotFoundException = Collections - .singleton(TypeReference.JavaLangClassNotFoundException); - - private static final Collection loadClassExceptions = Collections - .singleton(TypeReference.JavaLangClassNotFoundException); - - public static Collection getAaStoreExceptions() { - return aaStoreExceptions; - } - - public static Collection getArithmeticException() { - return arithmeticException; - } - - public static Collection getArrayAccessExceptions() { - return arrayAccessExceptions; - } - - public static Collection getClassCastException() { - return classCastException; - } - - public static Collection getClassNotFoundException() { - return classNotFoundException; - } - - public static Collection getNewArrayExceptions() { - return newArrayExceptions; - } - - public static Collection getNewScalarExceptions() { - return newScalarExceptions; - } - - public static Collection getNullPointerException() { - return nullPointerException; - } - - public static Collection getExceptionInInitializerError() { - return exceptionInInitializerError; - } - - public Atom getName() { - return ClassLoaderReference.Java; - } - - public TypeReference getRootType() { - return TypeReference.JavaLangObject; - } - - public TypeReference getThrowableType() { - return TypeReference.JavaLangThrowable; - } - - public TypeReference getConstantType(Object o) { - if (o == null) { - // TODO: do we really want null here instead of TypeReference.Null? - // lots of code seems to depend on this being null. - return null; - } else if (o instanceof Boolean) { - return TypeReference.Boolean; - } else if (o instanceof Long) { - return TypeReference.Long; - } else if (o instanceof Double) { - return TypeReference.Double; - } else if (o instanceof Float) { - return TypeReference.Float; - } else if (o instanceof Number) { - return TypeReference.Int; - } else if (o instanceof String) { - return TypeReference.JavaLangString; - } else if (o instanceof ClassToken || o instanceof TypeReference) { - return TypeReference.JavaLangClass; - } else if (o instanceof IMethod) { - IMethod m = (IMethod) o; - return m.isInit() ? TypeReference.JavaLangReflectConstructor : TypeReference.JavaLangReflectMethod; - } else { - assert false : "unknown constant " + o + ": " + o.getClass(); - return null; - } - } - - public boolean isNullType(TypeReference type) { - return type == null || type == TypeReference.Null; - } - - public TypeReference[] getArrayInterfaces() { - return new TypeReference[] { TypeReference.JavaIoSerializable, TypeReference.JavaLangCloneable }; - } - - public TypeName lookupPrimitiveType(String name) { - throw new UnsupportedOperationException(); - } - - /** - * @return Collection, set of exception types a call to a declared target might throw. - * @throws InvalidClassFileException - * @throws IllegalArgumentException if target is null - * @throws IllegalArgumentException if cha is null - */ - public Collection inferInvokeExceptions(MethodReference target, IClassHierarchy cha) - throws InvalidClassFileException { - - if (cha == null) { - throw new IllegalArgumentException("cha is null"); - } - if (target == null) { - throw new IllegalArgumentException("target is null"); - } - ArrayList set = new ArrayList(cha.getJavaLangRuntimeExceptionTypes()); - set.addAll(cha.getJavaLangErrorTypes()); - - IClass klass = cha.lookupClass(target.getDeclaringClass()); - if (klass == null) { - Warnings.add(MethodResolutionFailure.moderate(target)); - } - if (klass != null) { - IMethod M = klass.getMethod(target.getSelector()); - if (M == null) { - Warnings.add(MethodResolutionFailure.severe(target)); - } else { - TypeReference[] exceptionTypes = M.getDeclaredExceptions(); - if (exceptionTypes != null) { - set.addAll(Arrays.asList(exceptionTypes)); - } - } - } - return set; - } - - /** - * @param pei a potentially-excepting instruction - * @return the exception types that pei may throw, independent of the class hierarchy. null if none. - * - * Notes - *
          - *
        • this method will NOT return the exception type explicitly thrown by an athrow - *
        • this method will NOT return the exception types that a called method may throw - *
        • this method ignores OutOfMemoryError - *
        • this method ignores linkage errors - *
        • this method ignores IllegalMonitorState exceptions - *
        - * - * @throws IllegalArgumentException if pei is null - */ - public Collection getImplicitExceptionTypes(IInstruction pei) { - if (pei == null) { - throw new IllegalArgumentException("pei is null"); - } - switch (((Instruction) pei).getOpcode()) { - case OP_iaload: - case OP_laload: - case OP_faload: - case OP_daload: - case OP_aaload: - case OP_baload: - case OP_caload: - case OP_saload: - case OP_iastore: - case OP_lastore: - case OP_fastore: - case OP_dastore: - case OP_bastore: - case OP_castore: - case OP_sastore: - return getArrayAccessExceptions(); - case OP_aastore: - return getAaStoreExceptions(); - case OP_getfield: - case OP_putfield: - case OP_invokevirtual: - case OP_invokespecial: - case OP_invokeinterface: - return getNullPointerException(); - case OP_idiv: - case OP_irem: - case OP_ldiv: - case OP_lrem: - return getArithmeticException(); - case OP_new: - return newScalarExceptions; - case OP_newarray: - case OP_anewarray: - case OP_multianewarray: - return newArrayExceptions; - case OP_arraylength: - return getNullPointerException(); - case OP_athrow: - // N.B: the caller must handle the explicitly-thrown exception - return getNullPointerException(); - case OP_checkcast: - return getClassCastException(); - case OP_monitorenter: - case OP_monitorexit: - // we're currently ignoring MonitorStateExceptions, since J2EE stuff - // should be - // logically single-threaded - return getNullPointerException(); - case OP_ldc_w: - if (((ConstantInstruction) pei).getType().equals(TYPE_Class)) - return getClassNotFoundException(); - else - return null; - case OP_getstatic: - case OP_putstatic: - return getExceptionInInitializerError(); - default: - return Collections.emptySet(); - } - } - - public SSAInstructionFactory instructionFactory() { - return javaShrikeFactory; - } - - private final static SSAInstructionFactory javaShrikeFactory = new JavaInstructionFactory(); - - public boolean isDoubleType(TypeReference type) { - return type == TypeReference.Double; - } - - public boolean isFloatType(TypeReference type) { - return type == TypeReference.Float; - } - - public boolean isIntType(TypeReference type) { - return type == TypeReference.Int; - } - - public boolean isLongType(TypeReference type) { - return type == TypeReference.Long; - } - - public boolean isVoidType(TypeReference type) { - return type == TypeReference.Void; - } - - public boolean isMetadataType(TypeReference type) { - return type == TypeReference.JavaLangClass; - } - - public boolean isStringType(TypeReference type) { - return type == TypeReference.JavaLangString; - } - - public boolean isBooleanType(TypeReference type) { - return type == TypeReference.Boolean; - } - - public boolean isCharType(TypeReference type) { - return type == TypeReference.Char; - } - - public Object getMetadataToken(Object value) { - if (value instanceof ClassToken) { - return ShrikeUtil.makeTypeReference(ClassLoaderReference.Primordial, ((ClassToken) value).getTypeName()); - } else { - assert value instanceof TypeReference; - return value; - } - } - - public TypeReference getPointerType(TypeReference pointee) throws UnsupportedOperationException { - throw new UnsupportedOperationException("Java does not permit explicit pointers"); - } - - public TypeReference getMetadataType() { - return TypeReference.JavaLangClass; - } - - public TypeReference getStringType() { - return TypeReference.JavaLangString; - } - - { - JavaPrimitiveType.init(); - } - - @SuppressWarnings("static-access") - public PrimitiveType getPrimitive(TypeReference reference) { - return JavaPrimitiveType.getPrimitive(reference); - } -} +/******************************************************************************* + * Copyright (c) 2009 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 com.ibm.wala.analysis.typeInference.JavaPrimitiveType; +import com.ibm.wala.analysis.typeInference.PrimitiveType; +import com.ibm.wala.ipa.cha.IClassHierarchy; +import com.ibm.wala.shrikeBT.ConstantInstruction; +import com.ibm.wala.shrikeBT.ConstantInstruction.ClassToken; +import com.ibm.wala.shrikeBT.Constants; +import com.ibm.wala.shrikeBT.IBinaryOpInstruction; +import com.ibm.wala.shrikeBT.IComparisonInstruction; +import com.ibm.wala.shrikeBT.IConditionalBranchInstruction; +import com.ibm.wala.shrikeBT.IInstruction; +import com.ibm.wala.shrikeBT.IUnaryOpInstruction; +import com.ibm.wala.shrikeBT.Instruction; +import com.ibm.wala.shrikeCT.InvalidClassFileException; +import com.ibm.wala.ssa.SSAAddressOfInstruction; +import com.ibm.wala.ssa.SSAArrayLengthInstruction; +import com.ibm.wala.ssa.SSAArrayLoadInstruction; +import com.ibm.wala.ssa.SSAArrayStoreInstruction; +import com.ibm.wala.ssa.SSABinaryOpInstruction; +import com.ibm.wala.ssa.SSACheckCastInstruction; +import com.ibm.wala.ssa.SSAComparisonInstruction; +import com.ibm.wala.ssa.SSAConditionalBranchInstruction; +import com.ibm.wala.ssa.SSAConversionInstruction; +import com.ibm.wala.ssa.SSAGetCaughtExceptionInstruction; +import com.ibm.wala.ssa.SSAGetInstruction; +import com.ibm.wala.ssa.SSAGotoInstruction; +import com.ibm.wala.ssa.SSAInstanceofInstruction; +import com.ibm.wala.ssa.SSAInstruction; +import com.ibm.wala.ssa.SSAInstructionFactory; +import com.ibm.wala.ssa.SSAInvokeInstruction; +import com.ibm.wala.ssa.SSALoadIndirectInstruction; +import com.ibm.wala.ssa.SSALoadMetadataInstruction; +import com.ibm.wala.ssa.SSAMonitorInstruction; +import com.ibm.wala.ssa.SSANewInstruction; +import com.ibm.wala.ssa.SSAPhiInstruction; +import com.ibm.wala.ssa.SSAPiInstruction; +import com.ibm.wala.ssa.SSAPutInstruction; +import com.ibm.wala.ssa.SSAReturnInstruction; +import com.ibm.wala.ssa.SSAStoreIndirectInstruction; +import com.ibm.wala.ssa.SSASwitchInstruction; +import com.ibm.wala.ssa.SSAThrowInstruction; +import com.ibm.wala.ssa.SSAUnaryOpInstruction; +import com.ibm.wala.types.ClassLoaderReference; +import com.ibm.wala.types.FieldReference; +import com.ibm.wala.types.MethodReference; +import com.ibm.wala.types.TypeName; +import com.ibm.wala.types.TypeReference; +import com.ibm.wala.util.shrike.Exceptions.MethodResolutionFailure; +import com.ibm.wala.util.shrike.ShrikeUtil; +import com.ibm.wala.util.strings.Atom; +import com.ibm.wala.util.warnings.Warnings; + +/** + * The implementation of {@link Language} which defines Java semantics. + * + */ +public class JavaLanguage extends LanguageImpl implements BytecodeLanguage, Constants { + + public static class JavaInstructionFactory implements SSAInstructionFactory { + public SSAArrayLengthInstruction ArrayLengthInstruction(int result, int arrayref) { + return new SSAArrayLengthInstruction(result, arrayref) { + @Override + public Collection getExceptionTypes() { + return getNullPointerException(); + } + }; + } + + public SSAArrayLoadInstruction ArrayLoadInstruction(int result, int arrayref, int index, TypeReference declaredType) { + return new SSAArrayLoadInstruction(result, arrayref, index, declaredType) { + @Override + public Collection getExceptionTypes() { + return getArrayAccessExceptions(); + } + }; + } + + public SSAArrayStoreInstruction ArrayStoreInstruction(int arrayref, int index, int value, TypeReference declaredType) { + return new SSAArrayStoreInstruction(arrayref, index, value, declaredType) { + @Override + public Collection getExceptionTypes() { + if (typeIsPrimitive()) { + return getArrayAccessExceptions(); + } else { + return getAaStoreExceptions(); + } + } + }; + } + + public SSABinaryOpInstruction BinaryOpInstruction(IBinaryOpInstruction.IOperator operator, boolean overflow, boolean unsigned, + int result, int val1, int val2, boolean mayBeInteger) { + assert !overflow; + assert !unsigned; + return new SSABinaryOpInstruction(operator, result, val1, val2, mayBeInteger) { + + @Override + public SSAInstruction copyForSSA(SSAInstructionFactory insts, int[] defs, int[] uses) { + return insts.BinaryOpInstruction(getOperator(), false, false, defs == null || defs.length == 0 ? getDef(0) : defs[0], + uses == null ? getUse(0) : uses[0], uses == null ? getUse(1) : uses[1], mayBeIntegerOp()); + } + + @Override + public Collection getExceptionTypes() { + if (isPEI()) { + return getArithmeticException(); + } else { + return Collections.emptySet(); + } + } + }; + } + + public SSACheckCastInstruction CheckCastInstruction(int result, int val, int[] typeValues, boolean isPEI) { + throw new UnsupportedOperationException(); + } + + public SSACheckCastInstruction CheckCastInstruction(int result, int val, TypeReference[] types, boolean isPEI) { + assert types.length == 1; + assert isPEI; + return new SSACheckCastInstruction(result, val, types, true) { + @Override + public Collection getExceptionTypes() { + return getClassCastException(); + } + }; + } + + public SSACheckCastInstruction CheckCastInstruction(int result, int val, int typeValue, boolean isPEI) { + assert isPEI; + return CheckCastInstruction(result, val, new int[]{ typeValue }, true); + } + + public SSACheckCastInstruction CheckCastInstruction(int result, int val, TypeReference type, boolean isPEI) { + assert isPEI; + return CheckCastInstruction(result, val, new TypeReference[]{ type }, true); + } + + public SSAComparisonInstruction ComparisonInstruction(IComparisonInstruction.Operator operator, int result, int val1, int val2) { + return new SSAComparisonInstruction(operator, result, val1, val2); + } + + public SSAConditionalBranchInstruction ConditionalBranchInstruction(IConditionalBranchInstruction.IOperator operator, + TypeReference type, int val1, int val2) { + return new SSAConditionalBranchInstruction(operator, type, val1, val2); + } + + public SSAConversionInstruction ConversionInstruction(int result, int val, TypeReference fromType, TypeReference toType, + boolean overflow) { + assert !overflow; + return new SSAConversionInstruction(result, val, fromType, toType) { + @Override + public SSAInstruction copyForSSA(SSAInstructionFactory insts, int[] defs, int[] uses) throws IllegalArgumentException { + if (uses != null && uses.length == 0) { + throw new IllegalArgumentException("(uses != null) and (uses.length == 0)"); + } + return insts.ConversionInstruction(defs == null || defs.length == 0 ? getDef(0) : defs[0], uses == null ? getUse(0) + : uses[0], getFromType(), getToType(), false); + } + }; + } + + public SSAGetCaughtExceptionInstruction GetCaughtExceptionInstruction(int bbNumber, int exceptionValueNumber) { + return new SSAGetCaughtExceptionInstruction(bbNumber, exceptionValueNumber); + } + + public SSAGetInstruction GetInstruction(int result, FieldReference field) { + return new SSAGetInstruction(result, field) { + }; + } + + public SSAGetInstruction GetInstruction(int result, int ref, FieldReference field) { + return new SSAGetInstruction(result, ref, field) { + @Override + public Collection getExceptionTypes() { + return getNullPointerException(); + } + }; + } + + public SSAGotoInstruction GotoInstruction() { + return new SSAGotoInstruction(); + } + + public SSAInstanceofInstruction InstanceofInstruction(int result, int ref, TypeReference checkedType) { + return new SSAInstanceofInstruction(result, ref, checkedType); + } + + public SSAInvokeInstruction InvokeInstruction(int result, int[] params, int exception, CallSiteReference site) { + return new SSAInvokeInstruction(result, params, exception, site) { + @Override + public Collection getExceptionTypes() { + if (!isStatic()) { + return getNullPointerException(); + } else { + return Collections.emptySet(); + } + } + }; + } + + public SSAInvokeInstruction InvokeInstruction(int[] params, int exception, CallSiteReference site) { + return new SSAInvokeInstruction(params, exception, site) { + @Override + public Collection getExceptionTypes() { + if (!isStatic()) { + return getNullPointerException(); + } else { + return Collections.emptySet(); + } + } + }; + } + + public SSAMonitorInstruction MonitorInstruction(int ref, boolean isEnter) { + return new SSAMonitorInstruction(ref, isEnter) { + @Override + public Collection getExceptionTypes() { + return getNullPointerException(); + } + }; + } + + public SSANewInstruction NewInstruction(int result, NewSiteReference site) { + return new SSANewInstruction(result, site) { + @Override + public Collection getExceptionTypes() { + if (getNewSite().getDeclaredType().isArrayType()) { + return getNewArrayExceptions(); + } else { + return getNewScalarExceptions(); + } + } + }; + } + + public SSAPhiInstruction PhiInstruction(int result, int[] params) throws IllegalArgumentException { + return new SSAPhiInstruction(result, params) { + }; + } + + public SSAPutInstruction PutInstruction(int ref, int value, FieldReference field) { + return new SSAPutInstruction(ref, value, field) { + @Override + public Collection getExceptionTypes() { + return getNullPointerException(); + } + }; + } + + public SSAPutInstruction PutInstruction(int value, FieldReference field) { + return new SSAPutInstruction(value, field) { + }; + } + + public SSAReturnInstruction ReturnInstruction() { + return new SSAReturnInstruction(); + } + + public SSAReturnInstruction ReturnInstruction(int result, boolean isPrimitive) { + return new SSAReturnInstruction(result, isPrimitive); + } + + public SSASwitchInstruction SwitchInstruction(int val, int defaultLabel, int[] casesAndLabels) { + return new SSASwitchInstruction(val, defaultLabel, casesAndLabels); + } + + public SSAThrowInstruction ThrowInstruction(int exception) { + return new SSAThrowInstruction(exception) { + @Override + public Collection getExceptionTypes() { + return getNullPointerException(); + } + }; + } + + public SSAUnaryOpInstruction UnaryOpInstruction(IUnaryOpInstruction.IOperator operator, int result, int val) { + return new SSAUnaryOpInstruction(operator, result, val); + } + + public SSALoadMetadataInstruction LoadMetadataInstruction(int lval, TypeReference entityType, Object token) { + return new SSALoadMetadataInstruction(lval, entityType, token) { + @Override + public Collection getExceptionTypes() { + return loadClassExceptions; + } + }; + } + + public SSANewInstruction NewInstruction(int result, NewSiteReference site, int[] params) { + return new SSANewInstruction(result, site, params) { + @Override + public Collection getExceptionTypes() { + return getNewArrayExceptions(); + } + }; + } + + public SSAPiInstruction PiInstruction(int result, int val, int piBlock, int successorBlock, SSAInstruction cause) { + return new SSAPiInstruction(result, val, piBlock, successorBlock, cause); + } + + public SSAAddressOfInstruction AddressOfInstruction(int lval, int local, TypeReference pointeeType) { + throw new UnsupportedOperationException(); + } + + public SSAAddressOfInstruction AddressOfInstruction(int lval, int local, int indexVal, TypeReference pointeeType) { + throw new UnsupportedOperationException(); + } + + public SSAAddressOfInstruction AddressOfInstruction(int lval, int local, FieldReference field, TypeReference pointeeType) { + throw new UnsupportedOperationException(); + } + + public SSALoadIndirectInstruction LoadIndirectInstruction(int lval, TypeReference t, int addressVal) { + throw new UnsupportedOperationException(); + } + + public SSAStoreIndirectInstruction StoreIndirectInstruction(int addressVal, int rval, TypeReference pointeeType) { + throw new UnsupportedOperationException(); + } + } + + private static final Collection arrayAccessExceptions = Collections.unmodifiableCollection(Arrays + .asList(new TypeReference[] { TypeReference.JavaLangNullPointerException, + TypeReference.JavaLangArrayIndexOutOfBoundsException })); + + private static final Collection aaStoreExceptions = Collections.unmodifiableCollection(Arrays + .asList(new TypeReference[] { TypeReference.JavaLangNullPointerException, + TypeReference.JavaLangArrayIndexOutOfBoundsException, TypeReference.JavaLangArrayStoreException })); + + private static final Collection newScalarExceptions = Collections.unmodifiableCollection(Arrays + .asList(new TypeReference[] { TypeReference.JavaLangExceptionInInitializerError, TypeReference.JavaLangOutOfMemoryError })); + + private static final Collection newArrayExceptions = Collections.unmodifiableCollection(Arrays + .asList(new TypeReference[] { TypeReference.JavaLangOutOfMemoryError, TypeReference.JavaLangNegativeArraySizeException })); + + private static final Collection exceptionInInitializerError = Collections + .singleton(TypeReference.JavaLangExceptionInInitializerError); + + private static final Collection nullPointerException = Collections + .singleton(TypeReference.JavaLangNullPointerException); + + private static final Collection arithmeticException = Collections + .singleton(TypeReference.JavaLangArithmeticException); + + private static final Collection classCastException = Collections + .singleton(TypeReference.JavaLangClassCastException); + + private static final Collection classNotFoundException = Collections + .singleton(TypeReference.JavaLangClassNotFoundException); + + private static final Collection loadClassExceptions = Collections + .singleton(TypeReference.JavaLangClassNotFoundException); + + public static Collection getAaStoreExceptions() { + return aaStoreExceptions; + } + + public static Collection getArithmeticException() { + return arithmeticException; + } + + public static Collection getArrayAccessExceptions() { + return arrayAccessExceptions; + } + + public static Collection getClassCastException() { + return classCastException; + } + + public static Collection getClassNotFoundException() { + return classNotFoundException; + } + + public static Collection getNewArrayExceptions() { + return newArrayExceptions; + } + + public static Collection getNewScalarExceptions() { + return newScalarExceptions; + } + + public static Collection getNullPointerException() { + return nullPointerException; + } + + public static Collection getExceptionInInitializerError() { + return exceptionInInitializerError; + } + + public Atom getName() { + return ClassLoaderReference.Java; + } + + public TypeReference getRootType() { + return TypeReference.JavaLangObject; + } + + public TypeReference getThrowableType() { + return TypeReference.JavaLangThrowable; + } + + public TypeReference getConstantType(Object o) { + if (o == null) { + // TODO: do we really want null here instead of TypeReference.Null? + // lots of code seems to depend on this being null. + return null; + } else if (o instanceof Boolean) { + return TypeReference.Boolean; + } else if (o instanceof Long) { + return TypeReference.Long; + } else if (o instanceof Double) { + return TypeReference.Double; + } else if (o instanceof Float) { + return TypeReference.Float; + } else if (o instanceof Number) { + return TypeReference.Int; + } else if (o instanceof String) { + return TypeReference.JavaLangString; + } else if (o instanceof ClassToken || o instanceof TypeReference) { + return TypeReference.JavaLangClass; + } else if (o instanceof IMethod) { + IMethod m = (IMethod) o; + return m.isInit() ? TypeReference.JavaLangReflectConstructor : TypeReference.JavaLangReflectMethod; + } else { + assert false : "unknown constant " + o + ": " + o.getClass(); + return null; + } + } + + public boolean isNullType(TypeReference type) { + return type == null || type == TypeReference.Null; + } + + public TypeReference[] getArrayInterfaces() { + return new TypeReference[] { TypeReference.JavaIoSerializable, TypeReference.JavaLangCloneable }; + } + + public TypeName lookupPrimitiveType(String name) { + throw new UnsupportedOperationException(); + } + + /** + * @return Collection, set of exception types a call to a declared target might throw. + * @throws InvalidClassFileException + * @throws IllegalArgumentException if target is null + * @throws IllegalArgumentException if cha is null + */ + public Collection inferInvokeExceptions(MethodReference target, IClassHierarchy cha) + throws InvalidClassFileException { + + if (cha == null) { + throw new IllegalArgumentException("cha is null"); + } + if (target == null) { + throw new IllegalArgumentException("target is null"); + } + ArrayList set = new ArrayList(cha.getJavaLangRuntimeExceptionTypes()); + set.addAll(cha.getJavaLangErrorTypes()); + + IClass klass = cha.lookupClass(target.getDeclaringClass()); + if (klass == null) { + Warnings.add(MethodResolutionFailure.moderate(target)); + } + if (klass != null) { + IMethod M = klass.getMethod(target.getSelector()); + if (M == null) { + Warnings.add(MethodResolutionFailure.severe(target)); + } else { + TypeReference[] exceptionTypes = M.getDeclaredExceptions(); + if (exceptionTypes != null) { + set.addAll(Arrays.asList(exceptionTypes)); + } + } + } + return set; + } + + /** + * @param pei a potentially-excepting instruction + * @return the exception types that pei may throw, independent of the class hierarchy. null if none. + * + * Notes + *
          + *
        • this method will NOT return the exception type explicitly thrown by an athrow + *
        • this method will NOT return the exception types that a called method may throw + *
        • this method ignores OutOfMemoryError + *
        • this method ignores linkage errors + *
        • this method ignores IllegalMonitorState exceptions + *
        + * + * @throws IllegalArgumentException if pei is null + */ + public Collection getImplicitExceptionTypes(IInstruction pei) { + if (pei == null) { + throw new IllegalArgumentException("pei is null"); + } + switch (((Instruction) pei).getOpcode()) { + case OP_iaload: + case OP_laload: + case OP_faload: + case OP_daload: + case OP_aaload: + case OP_baload: + case OP_caload: + case OP_saload: + case OP_iastore: + case OP_lastore: + case OP_fastore: + case OP_dastore: + case OP_bastore: + case OP_castore: + case OP_sastore: + return getArrayAccessExceptions(); + case OP_aastore: + return getAaStoreExceptions(); + case OP_getfield: + case OP_putfield: + case OP_invokevirtual: + case OP_invokespecial: + case OP_invokeinterface: + return getNullPointerException(); + case OP_idiv: + case OP_irem: + case OP_ldiv: + case OP_lrem: + return getArithmeticException(); + case OP_new: + return newScalarExceptions; + case OP_newarray: + case OP_anewarray: + case OP_multianewarray: + return newArrayExceptions; + case OP_arraylength: + return getNullPointerException(); + case OP_athrow: + // N.B: the caller must handle the explicitly-thrown exception + return getNullPointerException(); + case OP_checkcast: + return getClassCastException(); + case OP_monitorenter: + case OP_monitorexit: + // we're currently ignoring MonitorStateExceptions, since J2EE stuff + // should be + // logically single-threaded + return getNullPointerException(); + case OP_ldc_w: + if (((ConstantInstruction) pei).getType().equals(TYPE_Class)) + return getClassNotFoundException(); + else + return null; + case OP_getstatic: + case OP_putstatic: + return getExceptionInInitializerError(); + default: + return Collections.emptySet(); + } + } + + public SSAInstructionFactory instructionFactory() { + return javaShrikeFactory; + } + + private final static SSAInstructionFactory javaShrikeFactory = new JavaInstructionFactory(); + + public boolean isDoubleType(TypeReference type) { + return type == TypeReference.Double; + } + + public boolean isFloatType(TypeReference type) { + return type == TypeReference.Float; + } + + public boolean isIntType(TypeReference type) { + return type == TypeReference.Int; + } + + public boolean isLongType(TypeReference type) { + return type == TypeReference.Long; + } + + public boolean isVoidType(TypeReference type) { + return type == TypeReference.Void; + } + + public boolean isMetadataType(TypeReference type) { + return type == TypeReference.JavaLangClass; + } + + public boolean isStringType(TypeReference type) { + return type == TypeReference.JavaLangString; + } + + public boolean isBooleanType(TypeReference type) { + return type == TypeReference.Boolean; + } + + public boolean isCharType(TypeReference type) { + return type == TypeReference.Char; + } + + public Object getMetadataToken(Object value) { + if (value instanceof ClassToken) { + return ShrikeUtil.makeTypeReference(ClassLoaderReference.Primordial, ((ClassToken) value).getTypeName()); + } else { + assert value instanceof TypeReference; + return value; + } + } + + public TypeReference getPointerType(TypeReference pointee) throws UnsupportedOperationException { + throw new UnsupportedOperationException("Java does not permit explicit pointers"); + } + + public TypeReference getMetadataType() { + return TypeReference.JavaLangClass; + } + + public TypeReference getStringType() { + return TypeReference.JavaLangString; + } + + { + JavaPrimitiveType.init(); + } + + @SuppressWarnings("static-access") + public PrimitiveType getPrimitive(TypeReference reference) { + return JavaPrimitiveType.getPrimitive(reference); + } +} diff --git a/com.ibm.wala.core/src/com/ibm/wala/classLoader/Language.java b/com.ibm.wala.core/src/com/ibm/wala/classLoader/Language.java index abdc578ea..84d2688d4 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/classLoader/Language.java +++ b/com.ibm.wala.core/src/com/ibm/wala/classLoader/Language.java @@ -1,137 +1,137 @@ -package com.ibm.wala.classLoader; - -import java.util.Collection; -import java.util.Set; - -import com.ibm.wala.analysis.typeInference.PrimitiveType; -import com.ibm.wala.analysis.typeInference.TypeInference; -import com.ibm.wala.ipa.cha.IClassHierarchy; -import com.ibm.wala.shrikeCT.InvalidClassFileException; -import com.ibm.wala.ssa.SSAInstructionFactory; -import com.ibm.wala.ssa.SSALoadMetadataInstruction; -import com.ibm.wala.types.MethodReference; -import com.ibm.wala.types.TypeName; -import com.ibm.wala.types.TypeReference; -import com.ibm.wala.util.strings.Atom; - -/** - * Main interface for language-specific information. This interface helps build - * analyses which can operate over multiple languages. - * - */ -public interface Language { - - /** - * The canonical {@link Language} implementation for Java - */ - public static JavaLanguage JAVA = new JavaLanguage(); - - /** - * What is the name of the language? - */ - Atom getName(); - - /** - * If this language is "derived" from some other langauge, which one? - */ - Language getBaseLanguage(); - - /** - * Yuck? Languages are mutable? - */ - void registerDerivedLanguage(Language l); - - Set getDerivedLanguages(); - - /** - * What is the root type in a type hierarchy for this language? e.g. - * java.lang.Object in Java. - */ - TypeReference getRootType(); - - /** - * What is the root type of exceptions in this language? e.g. - * java.lang.Throwable in Java - */ - TypeReference getThrowableType(); - - /** - * Given a Java constant o, return the appropriate language type to associate - * with the constant. Possible types for o can be language dependent, but - * typically include Boolean, String, Integer, Float, etc. - */ - TypeReference getConstantType(Object o); - - /** - * Is t the type of the language's null value? Should return true if - * t == null (?). - */ - boolean isNullType(TypeReference t); - - boolean isIntType(TypeReference t); - - boolean isLongType(TypeReference t); - - boolean isVoidType(TypeReference t); - - boolean isFloatType(TypeReference t); - - boolean isDoubleType(TypeReference t); - - boolean isStringType(TypeReference t); - - /** - * Is t a "metadata" type for the language, i.e., a type describing some other - * type (e.g., java.lang.Class for Java)? - */ - boolean isMetadataType(TypeReference t); - - boolean isCharType(TypeReference t); - - boolean isBooleanType(TypeReference t); - - /** - * Get the representation of the meta-data corresponding to value. For - * example, in Java, if value represents some type, the returned object should - * be the corresponding {@link TypeReference}. The returned object should be - * appropriate for use as the token in an {@link SSALoadMetadataInstruction} - * for the language - * - */ - Object getMetadataToken(Object value); - - /** - * get the interfaces implemented by all arrays in the language - */ - TypeReference[] getArrayInterfaces(); - - /** - * Given a source-level primitive type name, get the corresponding "low-level" - * type name, e.g., the corresponding character to use in a Java method - * descriptor - */ - TypeName lookupPrimitiveType(String name); - - SSAInstructionFactory instructionFactory(); - - /** - * determine the set of possible exception types a call to target may throw - */ - Collection inferInvokeExceptions(MethodReference target, IClassHierarchy cha) throws InvalidClassFileException; - - TypeReference getStringType(); - - /** - * get the metadata type for the language, e.g., java.lang.Class for Java - */ - TypeReference getMetadataType(); - - TypeReference getPointerType(TypeReference pointee); - - /** - * get the abstraction of a primitive type to be used for type inference - * - * @see TypeInference - */ - PrimitiveType getPrimitive(TypeReference reference); -} +package com.ibm.wala.classLoader; + +import java.util.Collection; +import java.util.Set; + +import com.ibm.wala.analysis.typeInference.PrimitiveType; +import com.ibm.wala.analysis.typeInference.TypeInference; +import com.ibm.wala.ipa.cha.IClassHierarchy; +import com.ibm.wala.shrikeCT.InvalidClassFileException; +import com.ibm.wala.ssa.SSAInstructionFactory; +import com.ibm.wala.ssa.SSALoadMetadataInstruction; +import com.ibm.wala.types.MethodReference; +import com.ibm.wala.types.TypeName; +import com.ibm.wala.types.TypeReference; +import com.ibm.wala.util.strings.Atom; + +/** + * Main interface for language-specific information. This interface helps build + * analyses which can operate over multiple languages. + * + */ +public interface Language { + + /** + * The canonical {@link Language} implementation for Java + */ + public static JavaLanguage JAVA = new JavaLanguage(); + + /** + * What is the name of the language? + */ + Atom getName(); + + /** + * If this language is "derived" from some other langauge, which one? + */ + Language getBaseLanguage(); + + /** + * Yuck? Languages are mutable? + */ + void registerDerivedLanguage(Language l); + + Set getDerivedLanguages(); + + /** + * What is the root type in a type hierarchy for this language? e.g. + * java.lang.Object in Java. + */ + TypeReference getRootType(); + + /** + * What is the root type of exceptions in this language? e.g. + * java.lang.Throwable in Java + */ + TypeReference getThrowableType(); + + /** + * Given a Java constant o, return the appropriate language type to associate + * with the constant. Possible types for o can be language dependent, but + * typically include Boolean, String, Integer, Float, etc. + */ + TypeReference getConstantType(Object o); + + /** + * Is t the type of the language's null value? Should return true if + * t == null (?). + */ + boolean isNullType(TypeReference t); + + boolean isIntType(TypeReference t); + + boolean isLongType(TypeReference t); + + boolean isVoidType(TypeReference t); + + boolean isFloatType(TypeReference t); + + boolean isDoubleType(TypeReference t); + + boolean isStringType(TypeReference t); + + /** + * Is t a "metadata" type for the language, i.e., a type describing some other + * type (e.g., java.lang.Class for Java)? + */ + boolean isMetadataType(TypeReference t); + + boolean isCharType(TypeReference t); + + boolean isBooleanType(TypeReference t); + + /** + * Get the representation of the meta-data corresponding to value. For + * example, in Java, if value represents some type, the returned object should + * be the corresponding {@link TypeReference}. The returned object should be + * appropriate for use as the token in an {@link SSALoadMetadataInstruction} + * for the language + * + */ + Object getMetadataToken(Object value); + + /** + * get the interfaces implemented by all arrays in the language + */ + TypeReference[] getArrayInterfaces(); + + /** + * Given a source-level primitive type name, get the corresponding "low-level" + * type name, e.g., the corresponding character to use in a Java method + * descriptor + */ + TypeName lookupPrimitiveType(String name); + + SSAInstructionFactory instructionFactory(); + + /** + * determine the set of possible exception types a call to target may throw + */ + Collection inferInvokeExceptions(MethodReference target, IClassHierarchy cha) throws InvalidClassFileException; + + TypeReference getStringType(); + + /** + * get the metadata type for the language, e.g., java.lang.Class for Java + */ + TypeReference getMetadataType(); + + TypeReference getPointerType(TypeReference pointee); + + /** + * get the abstraction of a primitive type to be used for type inference + * + * @see TypeInference + */ + PrimitiveType getPrimitive(TypeReference reference); +} diff --git a/com.ibm.wala.core/src/com/ibm/wala/classLoader/LanguageImpl.java b/com.ibm.wala.core/src/com/ibm/wala/classLoader/LanguageImpl.java index 98a9440da..267a2c2be 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/classLoader/LanguageImpl.java +++ b/com.ibm.wala.core/src/com/ibm/wala/classLoader/LanguageImpl.java @@ -1,65 +1,65 @@ -/******************************************************************************* - * Copyright (c) 2007 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.Set; - -import com.ibm.wala.util.collections.HashSetFactory; - -/** - * Common functionality for most {@link Language} implementations. - */ -public abstract class LanguageImpl implements Language { - - private Language baseLang; - - private Set derivedLangs= HashSetFactory.make(); - - public LanguageImpl() { } - - public LanguageImpl(Language base) { - baseLang= base; - base.registerDerivedLanguage(this); - } - - public Language getBaseLanguage() { - return baseLang; - } - - public Set getDerivedLanguages() { - return derivedLangs; - } - - public void registerDerivedLanguage(Language l) { - derivedLangs.add(l); - if (baseLang != null) - baseLang.registerDerivedLanguage(l); - } - - @Override - public int hashCode() { - return 1609 + 199 * getName().hashCode(); - } - - @Override - public boolean equals(Object o) { - if (!(o instanceof LanguageImpl)) - return false; - LanguageImpl other= (LanguageImpl) o; - - return getName().equals(other.getName()); - } - - @Override - public String toString() { - return getName().toString(); - } -} +/******************************************************************************* + * Copyright (c) 2007 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.Set; + +import com.ibm.wala.util.collections.HashSetFactory; + +/** + * Common functionality for most {@link Language} implementations. + */ +public abstract class LanguageImpl implements Language { + + private Language baseLang; + + private Set derivedLangs= HashSetFactory.make(); + + public LanguageImpl() { } + + public LanguageImpl(Language base) { + baseLang= base; + base.registerDerivedLanguage(this); + } + + public Language getBaseLanguage() { + return baseLang; + } + + public Set getDerivedLanguages() { + return derivedLangs; + } + + public void registerDerivedLanguage(Language l) { + derivedLangs.add(l); + if (baseLang != null) + baseLang.registerDerivedLanguage(l); + } + + @Override + public int hashCode() { + return 1609 + 199 * getName().hashCode(); + } + + @Override + public boolean equals(Object o) { + if (!(o instanceof LanguageImpl)) + return false; + LanguageImpl other= (LanguageImpl) o; + + return getName().equals(other.getName()); + } + + @Override + public String toString() { + return getName().toString(); + } +} diff --git a/com.ibm.wala.core/src/com/ibm/wala/classLoader/Module.java b/com.ibm.wala.core/src/com/ibm/wala/classLoader/Module.java index 2dbb987eb..73f871077 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/classLoader/Module.java +++ b/com.ibm.wala.core/src/com/ibm/wala/classLoader/Module.java @@ -1,27 +1,27 @@ -/******************************************************************************* - * Copyright (c) 2002 - 2006 IBM Corporation. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * IBM Corporation - initial API and implementation - *******************************************************************************/ - -package com.ibm.wala.classLoader; - -import java.util.Iterator; - -/** - * A {@link Module} represents a set of files to analyze. eg., a Jar file. - * These are persistent (hung onto by {@link ClassLoaderImpl}) .. so, - * a Module should not hold onto a lot of data. - */ -public interface Module { - - /** - * @return an Iterator of the ModuleEntries in this Module. - */ - Iterator getEntries(); -} +/******************************************************************************* + * 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 {@link Module} represents a set of files to analyze. eg., a Jar file. + * These are persistent (hung onto by {@link ClassLoaderImpl}) .. so, + * a Module should not hold onto a lot of data. + */ +public interface Module { + + /** + * @return an Iterator of the ModuleEntries in this Module. + */ + Iterator getEntries(); +} diff --git a/com.ibm.wala.core/src/com/ibm/wala/classLoader/ModuleEntry.java b/com.ibm.wala.core/src/com/ibm/wala/classLoader/ModuleEntry.java index afa0aa04b..ebcefaf28 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/classLoader/ModuleEntry.java +++ b/com.ibm.wala.core/src/com/ibm/wala/classLoader/ModuleEntry.java @@ -1,61 +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 {@link Module}. - */ -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(); - - /** - * @return an InputStream which provides the contents of this logical file. - */ - 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() and !isSourceFile() - */ - String getClassName(); - -} +/******************************************************************************* + * 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 {@link Module}. + */ +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(); + + /** + * @return an InputStream which provides the contents of this logical file. + */ + 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() and !isSourceFile() + */ + String getClassName(); + +} diff --git a/com.ibm.wala.core/src/com/ibm/wala/classLoader/NestedJarFileModule.java b/com.ibm.wala.core/src/com/ibm/wala/classLoader/NestedJarFileModule.java index 759422a39..046668242 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/classLoader/NestedJarFileModule.java +++ b/com.ibm.wala.core/src/com/ibm/wala/classLoader/NestedJarFileModule.java @@ -1,272 +1,272 @@ -/******************************************************************************* - * 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.util.collections.HashMapFactory; -import com.ibm.wala.util.debug.Assertions; -import com.ibm.wala.util.io.FileSuffixes; -import com.ibm.wala.util.warnings.Warning; -import com.ibm.wala.util.warnings.Warnings; - -/** - * A Jar file nested in a parent jar file - */ -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 cache = null; - - public NestedJarFileModule(JarFileModule parent, ZipEntry entry) { - this.parent = parent; - this.entry = entry; - if (parent == null) { - throw new IllegalArgumentException("null parent"); - } - if (entry == null) { - throw new IllegalArgumentException("null entry"); - } - } - - public InputStream getInputStream(String name) { - populateCache(); - byte[] b = cache.get(name); - return new ByteArrayInputStream(b); - } - - private void populateCache() { - if (cache != null) { - return; - } - cache = HashMapFactory.make(); - final byte[] b = parent.getContents(entry); - try { - final JarInputStream stream = new JarInputStream(new ByteArrayInputStream(b)); - for (ZipEntry z = stream.getNextEntry(); z != null; z = stream.getNextEntry()) { - final String name = z.getName(); - if (DEBUG) { - System.err.println(("got entry: " + name)); - } - if (FileSuffixes.isClassFile(name) || FileSuffixes.isSourceFile(name)) { - 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(); - cache.put(name, bb); - } - } - } catch (IOException e) { - // just go with what we have - Warnings.add(new Warning() { - - @Override - public String getMsg() { - return "could not read contents of nested jar file " + entry.getName() + ", parent " + parent.getAbsolutePath(); - } - }); - } - - } - - protected long getEntrySize(String name) { - populateCache(); - byte[] b = cache.get(name); - return b.length; - } - - /* - * @see com.ibm.wala.classLoader.Module#getEntries() - */ - public Iterator getEntries() { - populateCache(); - final Iterator it = cache.keySet().iterator(); - return new Iterator() { - 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; - } - - /* - * @see com.ibm.wala.classLoader.ModuleEntry#getName() - */ - public String getName() { - return name; - } - - /* - * @see com.ibm.wala.classLoader.ModuleEntry#isClassFile() - */ - public boolean isClassFile() { - return FileSuffixes.isClassFile(getName()); - } - - /* - * @see com.ibm.wala.classLoader.ModuleEntry#getInputStream() - */ - public InputStream getInputStream() { - return NestedJarFileModule.this.getInputStream(name); - } - - /* - * @see com.ibm.wala.classLoader.ModuleEntry#isModuleFile() - */ - public boolean isModuleFile() { - return false; - } - - /* - * @see com.ibm.wala.classLoader.ModuleEntry#asModule() - */ - public Module asModule() { - Assertions.UNREACHABLE(); - return null; - } - - @Override - public String toString() { - return "nested entry: " + name; - } - - /* - * @see com.ibm.wala.classLoader.ModuleEntry#getClassName() - */ - public String getClassName() { - return FileSuffixes.stripSuffix(getName()); - } - - /* - * @see com.ibm.wala.classLoader.ModuleEntry#isSourceFile() - */ - public boolean isSourceFile() { - return FileSuffixes.isSourceFile(getName()); - } - - @Override - public int hashCode() { - final int prime = 31; - int result = 1; - result = prime * result + getOuterType().hashCode(); - result = prime * result + ((name == null) ? 0 : name.hashCode()); - return result; - } - - @Override - public boolean equals(Object obj) { - if (this == obj) - return true; - if (obj == null) - return false; - if (getClass() != obj.getClass()) - return false; - Entry other = (Entry) obj; - if (!getOuterType().equals(other.getOuterType())) - return false; - if (name == null) { - if (other.name != null) - return false; - } else if (!name.equals(other.name)) - return false; - return true; - } - - private NestedJarFileModule getOuterType() { - return NestedJarFileModule.this; - } - - } - - @Override - public String toString() { - return "Nested Jar File:" + entry.getName(); - } - - @Override - public int hashCode() { - final int prime = 31; - int result = 1; - result = prime * result + ((parent == null) ? 0 : parent.hashCode()); - return result; - } - - @Override - public boolean equals(Object obj) { - if (this == obj) - return true; - if (obj == null) - return false; - if (getClass() != obj.getClass()) - return false; - NestedJarFileModule other = (NestedJarFileModule) obj; - if (parent == null) { - if (other.parent != null) - return false; - } else if (!parent.equals(other.parent)) - return false; - return true; - } - +/******************************************************************************* + * 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.util.collections.HashMapFactory; +import com.ibm.wala.util.debug.Assertions; +import com.ibm.wala.util.io.FileSuffixes; +import com.ibm.wala.util.warnings.Warning; +import com.ibm.wala.util.warnings.Warnings; + +/** + * A Jar file nested in a parent jar file + */ +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 cache = null; + + public NestedJarFileModule(JarFileModule parent, ZipEntry entry) { + this.parent = parent; + this.entry = entry; + if (parent == null) { + throw new IllegalArgumentException("null parent"); + } + if (entry == null) { + throw new IllegalArgumentException("null entry"); + } + } + + public InputStream getInputStream(String name) { + populateCache(); + byte[] b = cache.get(name); + return new ByteArrayInputStream(b); + } + + private void populateCache() { + if (cache != null) { + return; + } + cache = HashMapFactory.make(); + final byte[] b = parent.getContents(entry); + try { + final JarInputStream stream = new JarInputStream(new ByteArrayInputStream(b)); + for (ZipEntry z = stream.getNextEntry(); z != null; z = stream.getNextEntry()) { + final String name = z.getName(); + if (DEBUG) { + System.err.println(("got entry: " + name)); + } + if (FileSuffixes.isClassFile(name) || FileSuffixes.isSourceFile(name)) { + 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(); + cache.put(name, bb); + } + } + } catch (IOException e) { + // just go with what we have + Warnings.add(new Warning() { + + @Override + public String getMsg() { + return "could not read contents of nested jar file " + entry.getName() + ", parent " + parent.getAbsolutePath(); + } + }); + } + + } + + protected long getEntrySize(String name) { + populateCache(); + byte[] b = cache.get(name); + return b.length; + } + + /* + * @see com.ibm.wala.classLoader.Module#getEntries() + */ + public Iterator getEntries() { + populateCache(); + final Iterator it = cache.keySet().iterator(); + return new Iterator() { + 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; + } + + /* + * @see com.ibm.wala.classLoader.ModuleEntry#getName() + */ + public String getName() { + return name; + } + + /* + * @see com.ibm.wala.classLoader.ModuleEntry#isClassFile() + */ + public boolean isClassFile() { + return FileSuffixes.isClassFile(getName()); + } + + /* + * @see com.ibm.wala.classLoader.ModuleEntry#getInputStream() + */ + public InputStream getInputStream() { + return NestedJarFileModule.this.getInputStream(name); + } + + /* + * @see com.ibm.wala.classLoader.ModuleEntry#isModuleFile() + */ + public boolean isModuleFile() { + return false; + } + + /* + * @see com.ibm.wala.classLoader.ModuleEntry#asModule() + */ + public Module asModule() { + Assertions.UNREACHABLE(); + return null; + } + + @Override + public String toString() { + return "nested entry: " + name; + } + + /* + * @see com.ibm.wala.classLoader.ModuleEntry#getClassName() + */ + public String getClassName() { + return FileSuffixes.stripSuffix(getName()); + } + + /* + * @see com.ibm.wala.classLoader.ModuleEntry#isSourceFile() + */ + public boolean isSourceFile() { + return FileSuffixes.isSourceFile(getName()); + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + getOuterType().hashCode(); + result = prime * result + ((name == null) ? 0 : name.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + Entry other = (Entry) obj; + if (!getOuterType().equals(other.getOuterType())) + return false; + if (name == null) { + if (other.name != null) + return false; + } else if (!name.equals(other.name)) + return false; + return true; + } + + private NestedJarFileModule getOuterType() { + return NestedJarFileModule.this; + } + + } + + @Override + public String toString() { + return "Nested Jar File:" + entry.getName(); + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((parent == null) ? 0 : parent.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + NestedJarFileModule other = (NestedJarFileModule) obj; + if (parent == null) { + if (other.parent != null) + return false; + } else if (!parent.equals(other.parent)) + return false; + return true; + } + } \ No newline at end of file diff --git a/com.ibm.wala.core/src/com/ibm/wala/classLoader/NewSiteReference.java b/com.ibm.wala.core/src/com/ibm/wala/classLoader/NewSiteReference.java index 157ff1616..1d948e535 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/classLoader/NewSiteReference.java +++ b/com.ibm.wala.core/src/com/ibm/wala/classLoader/NewSiteReference.java @@ -1,53 +1,53 @@ -/******************************************************************************* - * Copyright (c) 2002 - 2006 IBM Corporation. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * IBM Corporation - initial API and implementation - *******************************************************************************/ - -package com.ibm.wala.classLoader; - -import com.ibm.wala.ssa.IR; -import com.ibm.wala.types.TypeReference; - -/** - * Represents a textual allocation site - * - * Note that the identity of a {@link NewSiteReference} depends on two things: the program counter, and the containing {@link IR}. Thus, it suffices - * to defines equals() and hashCode() from ProgramCounter, since this class does not maintain a pointer to the containing IR (or - * CGNode) anyway. If using a hashtable of NewSiteReference from different IRs, you probably want to use a wrapper which also holds - * a pointer to the governing CGNode. - */ -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); - } - - @Override - public String toString() { - return "NEW " + declaredType + "@" + getProgramCounter(); - } -} +/******************************************************************************* + * 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.ssa.IR; +import com.ibm.wala.types.TypeReference; + +/** + * Represents a textual allocation site + * + * Note that the identity of a {@link NewSiteReference} depends on two things: the program counter, and the containing {@link IR}. Thus, it suffices + * to defines equals() and hashCode() from ProgramCounter, since this class does not maintain a pointer to the containing IR (or + * CGNode) anyway. If using a hashtable of NewSiteReference from different IRs, you probably want to use a wrapper which also holds + * a pointer to the governing CGNode. + */ +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); + } + + @Override + public String toString() { + return "NEW " + declaredType + "@" + getProgramCounter(); + } +} diff --git a/com.ibm.wala.core/src/com/ibm/wala/classLoader/ProgramCounter.java b/com.ibm.wala.core/src/com/ibm/wala/classLoader/ProgramCounter.java index 830d02e1c..be62c4c55 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/classLoader/ProgramCounter.java +++ b/com.ibm.wala.core/src/com/ibm/wala/classLoader/ProgramCounter.java @@ -1,72 +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; - - -/** - * Simple object that represents a program counter value (i.e., an instruction in the bytecode) - */ -public class ProgramCounter { - - /** - * A constant indicating no source line number information is available. - */ - public static final int NO_SOURCE_LINE_NUMBER = -1; - - /** - * Index into bytecode describing this instruction - */ - private final int programCounter; - - /** - * @param programCounter Index into bytecode describing this instruction - */ - public ProgramCounter(final int programCounter) { - if (programCounter < 0) { - throw new IllegalArgumentException("illegal programCounter: " + programCounter); - } - 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) - */ - @Override - public boolean equals(Object obj) { - return (obj instanceof ProgramCounter) && ((ProgramCounter) obj).programCounter == programCounter; - } - - @Override - public int hashCode() { - return programCounter + 77; - } - - @Override - public String toString() { - return "PC@" + programCounter; - } -} +/******************************************************************************* + * 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; + + +/** + * Simple object that represents a program counter value (i.e., an instruction in the bytecode) + */ +public class ProgramCounter { + + /** + * A constant indicating no source line number information is available. + */ + public static final int NO_SOURCE_LINE_NUMBER = -1; + + /** + * Index into bytecode describing this instruction + */ + private final int programCounter; + + /** + * @param programCounter Index into bytecode describing this instruction + */ + public ProgramCounter(final int programCounter) { + if (programCounter < 0) { + throw new IllegalArgumentException("illegal programCounter: " + programCounter); + } + 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) + */ + @Override + public boolean equals(Object obj) { + return (obj instanceof ProgramCounter) && ((ProgramCounter) obj).programCounter == programCounter; + } + + @Override + public int hashCode() { + return programCounter + 77; + } + + @Override + public String toString() { + return "PC@" + programCounter; + } +} diff --git a/com.ibm.wala.core/src/com/ibm/wala/classLoader/ShrikeBTMethod.java b/com.ibm.wala.core/src/com/ibm/wala/classLoader/ShrikeBTMethod.java index bd4ac179c..a90afe618 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/classLoader/ShrikeBTMethod.java +++ b/com.ibm.wala.core/src/com/ibm/wala/classLoader/ShrikeBTMethod.java @@ -1,811 +1,811 @@ -/******************************************************************************* - * 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.lang.ref.SoftReference; -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.BytecodeConstants; -import com.ibm.wala.shrikeBT.Constants; -import com.ibm.wala.shrikeBT.Decoder; -import com.ibm.wala.shrikeBT.ExceptionHandler; -import com.ibm.wala.shrikeBT.IArrayLoadInstruction; -import com.ibm.wala.shrikeBT.IArrayStoreInstruction; -import com.ibm.wala.shrikeBT.IGetInstruction; -import com.ibm.wala.shrikeBT.IInstruction; -import com.ibm.wala.shrikeBT.IInvokeInstruction; -import com.ibm.wala.shrikeBT.IPutInstruction; -import com.ibm.wala.shrikeBT.ITypeTestInstruction; -import com.ibm.wala.shrikeBT.MonitorInstruction; -import com.ibm.wala.shrikeBT.NewInstruction; -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.bytecode.BytecodeStream; -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.shrike.ShrikeUtil; -import com.ibm.wala.util.strings.Atom; -import com.ibm.wala.util.strings.ImmutableByteArray; - -/** - * A wrapper around a Shrike object that represents a method - */ -public abstract class ShrikeBTMethod 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. - */ - private SoftReference bcInfo; - - public ShrikeBTMethod(IClass klass) { - this.declaringClass = klass; - } - - protected synchronized BytecodeInfo getBCInfo() throws InvalidClassFileException { - BytecodeInfo result = null; - if (bcInfo != null) { - result = bcInfo.get(); - } - if (result == null) { - result = computeBCInfo(); - bcInfo = new SoftReference(result); - } - return result; - } - - /** - * Return the program counter (bytecode index) for a particular Shrike instruction index. - * - * @throws InvalidClassFileException - */ - public int getBytecodeIndex(int instructionIndex) throws InvalidClassFileException { - return getBCInfo().pcMap[instructionIndex]; - } - - /** - * Return the number of Shrike instructions for this method. - * - * @throws InvalidClassFileException - */ - public int getNumShrikeInstructions() throws InvalidClassFileException { - return getBCInfo().pcMap.length; - } - - /** - * @throws InvalidClassFileException - */ - public Collection getCallSites() throws InvalidClassFileException { - Collection empty = Collections.emptySet(); - if (isNative()) { - return empty; - } - return (getBCInfo().callSites == null) ? empty : Collections.unmodifiableCollection(Arrays.asList(getBCInfo().callSites)); - } - - /** - * @throws InvalidClassFileException - */ - Collection getNewSites() throws InvalidClassFileException { - Collection empty = Collections.emptySet(); - if (isNative()) { - return empty; - } - - return (getBCInfo().newSites == null) ? empty : Collections.unmodifiableCollection(Arrays.asList(getBCInfo().newSites)); - } - - /** - * @return Set , the exceptions that statements in this method may throw, - * @throws InvalidClassFileException - */ - public Collection getImplicitExceptionTypes() throws InvalidClassFileException { - if (isNative()) { - return Collections.emptySet(); - } - return (getBCInfo().implicitExceptions == null) ? Arrays.asList(new TypeReference[0]) : Arrays - .asList(getBCInfo().implicitExceptions); - } - - /** - * 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 - */ - private BytecodeInfo computeBCInfo() throws InvalidClassFileException { - BytecodeInfo result = new BytecodeInfo(); - result.exceptionTypes = computeDeclaredExceptions(); - - if (isNative()) { - return result; - } - if (verbose) { - methodsParsed += 1; - if (methodsParsed % 100 == 0) { - System.out.println(methodsParsed + " methods processed..."); - } - } - - processBytecodesWithShrikeBT(result); - return result; - } - - /** - * @return true iff this method has a monitorenter or monitorexit - * @throws InvalidClassFileException - */ - public boolean hasMonitorOp() throws InvalidClassFileException { - if (isNative()) { - return false; - } - return getBCInfo().hasMonitorOp; - } - - /** - * @return Set of FieldReference - * @throws InvalidClassFileException - */ - public Iterator getFieldsWritten() throws InvalidClassFileException { - if (isNative()) { - return EmptyIterator.instance(); - } - if (getBCInfo().fieldsWritten == null) { - return EmptyIterator.instance(); - } else { - List l = Arrays.asList(getBCInfo().fieldsWritten); - return l.iterator(); - } - } - - /** - * @return Iterator of FieldReference - * @throws InvalidClassFileException - */ - public Iterator getFieldsRead() throws InvalidClassFileException { - if (isNative()) { - return EmptyIterator.instance(); - } - if (getBCInfo().fieldsRead == null) { - return EmptyIterator.instance(); - } else { - List l = Arrays.asList(getBCInfo().fieldsRead); - return l.iterator(); - } - } - - /** - * @return Iterator of TypeReference - * @throws InvalidClassFileException - */ - public Iterator getArraysRead() throws InvalidClassFileException { - if (isNative()) { - return EmptyIterator.instance(); - } - return (getBCInfo().arraysRead == null) ? EmptyIterator.instance() : Arrays.asList(getBCInfo().arraysRead).iterator(); - } - - /** - * @return Iterator of TypeReference - * @throws InvalidClassFileException - */ - public Iterator getArraysWritten() throws InvalidClassFileException { - if (isNative()) { - return EmptyIterator.instance(); - } - if (getBCInfo().fieldsRead == null) { - return EmptyIterator.instance(); - } else { - List list = Arrays.asList(getBCInfo().arraysWritten); - return list.iterator(); - } - } - - /** - * @return Iterator of TypeReference - * @throws InvalidClassFileException - */ - public Iterator getCastTypes() throws InvalidClassFileException { - if (isNative()) { - return EmptyIterator.instance(); - } - return (getBCInfo().castTypes == null) ? EmptyIterator.instance() : Arrays.asList(getBCInfo().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(declaringClass.getClassLoader().getLanguage(), 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 isBridge() { - return ((getModifiers() & Constants.ACC_VOLATILE) != 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(BytecodeInfo info) throws InvalidClassFileException { - info.decoder = makeDecoder(); - if (!isAbstract() && info.decoder == null) { - Assertions.UNREACHABLE("bad method " + getReference()); - } - if (info.decoder == null) { - return; - } - info.pcMap = info.decoder.getInstructionsToBytecodes(); - - processDebugInfo(info); - - SimpleVisitor simpleVisitor = new SimpleVisitor(info); - - BytecodeLanguage lang = (BytecodeLanguage) getDeclaringClass().getClassLoader().getLanguage(); - IInstruction[] instructions = info.decoder.getInstructions(); - for (int i = 0; i < instructions.length; i++) { - simpleVisitor.setInstructionIndex(i); - instructions[i].visit(simpleVisitor); - if (instructions[i].isPEI()) { - Collection t = lang.getImplicitExceptionTypes(instructions[i]); - if (t != null) { - simpleVisitor.implicitExceptions.addAll(t); - } - } - } - - // copy the Set results into arrays; will use less - // storage - copyVisitorSetsToArrays(simpleVisitor, info); - } - - private void copyVisitorSetsToArrays(SimpleVisitor simpleVisitor, BytecodeInfo info) { - info.newSites = new NewSiteReference[simpleVisitor.newSites.size()]; - int i = 0; - for (Iterator it = simpleVisitor.newSites.iterator(); it.hasNext();) { - info.newSites[i++] = it.next(); - } - - info.fieldsRead = new FieldReference[simpleVisitor.fieldsRead.size()]; - i = 0; - for (Iterator it = simpleVisitor.fieldsRead.iterator(); it.hasNext();) { - info.fieldsRead[i++] = it.next(); - } - - info.fieldsRead = new FieldReference[simpleVisitor.fieldsRead.size()]; - i = 0; - for (Iterator it = simpleVisitor.fieldsRead.iterator(); it.hasNext();) { - info.fieldsRead[i++] = it.next(); - } - - info.fieldsWritten = new FieldReference[simpleVisitor.fieldsWritten.size()]; - i = 0; - for (Iterator it = simpleVisitor.fieldsWritten.iterator(); it.hasNext();) { - info.fieldsWritten[i++] = it.next(); - } - - info.callSites = new CallSiteReference[simpleVisitor.callSites.size()]; - i = 0; - for (Iterator it = simpleVisitor.callSites.iterator(); it.hasNext();) { - info.callSites[i++] = it.next(); - } - - info.arraysRead = new TypeReference[simpleVisitor.arraysRead.size()]; - i = 0; - for (Iterator it = simpleVisitor.arraysRead.iterator(); it.hasNext();) { - info.arraysRead[i++] = it.next(); - } - - info.arraysWritten = new TypeReference[simpleVisitor.arraysWritten.size()]; - i = 0; - for (Iterator it = simpleVisitor.arraysWritten.iterator(); it.hasNext();) { - info.arraysWritten[i++] = it.next(); - } - - info.implicitExceptions = new TypeReference[simpleVisitor.implicitExceptions.size()]; - i = 0; - for (Iterator it = simpleVisitor.implicitExceptions.iterator(); it.hasNext();) { - info.implicitExceptions[i++] = (TypeReference) it.next(); - } - - info.castTypes = new TypeReference[simpleVisitor.castTypes.size()]; - i = 0; - for (Iterator it = simpleVisitor.castTypes.iterator(); it.hasNext();) { - info.castTypes[i++] = it.next(); - } - - info.hasMonitorOp = simpleVisitor.hasMonitorOp; - } - - /** - * @see java.lang.Object#toString() - */ - @Override - public String toString() { - return getReference().toString(); - } - - /** - * @see java.lang.Object#equals(Object) - */ - @Override - public boolean equals(Object obj) { - // instanceof is OK because this class is final. - // if (this.getClass().equals(obj.getClass())) { - if (obj instanceof ShrikeBTMethod) { - ShrikeBTMethod that = (ShrikeBTMethod) obj; - return (getDeclaringClass().equals(that.getDeclaringClass()) && getReference().equals(that.getReference())); - } else { - return false; - } - } - - /** - * @see java.lang.Object#hashCode() - */ - @Override - public int hashCode() { - return 9661 * getReference().hashCode(); - } - - /* - * @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(); - } - - /** - * - * A visitor used to process bytecodes - * - */ - private class SimpleVisitor extends IInstruction.Visitor { - - private final BytecodeInfo info; - - public SimpleVisitor(BytecodeInfo info) { - this.info = info; - } - - // TODO: make a better Set implementation for these. - final Set callSites = HashSetFactory.make(5); - - final Set fieldsWritten = HashSetFactory.make(5); - - final Set fieldsRead = HashSetFactory.make(5); - - final Set newSites = HashSetFactory.make(5); - - final Set arraysRead = HashSetFactory.make(5); - - final Set arraysWritten = HashSetFactory.make(5); - - final Set implicitExceptions = HashSetFactory.make(5); - - final Set castTypes = HashSetFactory.make(5); - - boolean hasMonitorOp; - - private int instructionIndex; - - public void setInstructionIndex(int i) { - instructionIndex = i; - } - - public int getProgramCounter() throws InvalidClassFileException { - return info.pcMap[instructionIndex]; - } - - @Override - public void visitMonitor(MonitorInstruction instruction) { - hasMonitorOp = true; - } - - @Override - 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(); - } - } - - @Override - public void visitGet(IGetInstruction instruction) { - ClassLoaderReference loader = getReference().getDeclaringClass().getClassLoader(); - FieldReference f = FieldReference.findOrCreate(loader, instruction.getClassType(), instruction.getFieldName(), instruction - .getFieldType()); - fieldsRead.add(f); - } - - @Override - public void visitPut(IPutInstruction instruction) { - ClassLoaderReference loader = getReference().getDeclaringClass().getClassLoader(); - FieldReference f = FieldReference.findOrCreate(loader, instruction.getClassType(), instruction.getFieldName(), instruction - .getFieldType()); - fieldsWritten.add(f); - } - - @Override - public void visitInvoke(IInvokeInstruction instruction) { - IClassLoader loader = getDeclaringClass().getClassLoader(); - MethodReference m = MethodReference.findOrCreate(loader.getLanguage(), loader.getReference(), instruction.getClassType(), - instruction.getMethodName(), instruction.getMethodSignature()); - int programCounter = 0; - try { - programCounter = getProgramCounter(); - } catch (InvalidClassFileException e) { - e.printStackTrace(); - Assertions.UNREACHABLE(); - } - CallSiteReference site = null; - site = CallSiteReference.make(programCounter, m, instruction.getInvocationCode()); - callSites.add(site); - } - - /* - * @see com.ibm.wala.shrikeBT.Instruction.Visitor#visitArrayLoad(com.ibm.wala.shrikeBT.ArrayLoadInstruction) - */ - @Override - public void visitArrayLoad(IArrayLoadInstruction instruction) { - arraysRead.add(ShrikeUtil.makeTypeReference(getDeclaringClass().getClassLoader().getReference(), instruction.getType())); - } - - /* - * @see com.ibm.wala.shrikeBT.Instruction.Visitor#visitArrayStore(com.ibm.wala.shrikeBT.ArrayStoreInstruction) - */ - @Override - public void visitArrayStore(IArrayStoreInstruction instruction) { - arraysWritten.add(ShrikeUtil.makeTypeReference(getDeclaringClass().getClassLoader().getReference(), instruction.getType())); - } - - @Override - public void visitCheckCast(ITypeTestInstruction instruction) { - for(String t : instruction.getTypes()) { - castTypes.add(ShrikeUtil.makeTypeReference(getDeclaringClass().getClassLoader().getReference(), t)); - } - } - } - - /** - */ - public IInstruction[] getInstructions() throws InvalidClassFileException { - if (getBCInfo().decoder == null) { - return null; - } else { - return getBCInfo().decoder.getInstructions(); - } - } - - public ExceptionHandler[][] getHandlers() throws InvalidClassFileException { - if (getBCInfo().decoder == null) { - return null; - } else { - return getBCInfo().decoder.getHandlers(); - } - } - - /** - * By convention, for a non-static method, getParameterType(0) is the this pointer - */ - 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; - } - } - - /* - * @see com.ibm.wala.classLoader.IMethod#hasExceptionHandler() - */ - public abstract boolean hasExceptionHandler(); - - /** - * Clients should not modify the returned array. TODO: clone to avoid the problem? - * - * @throws InvalidClassFileException - * - * @see com.ibm.wala.classLoader.IMethod#getDeclaredExceptions() - */ - public TypeReference[] getDeclaredExceptions() throws InvalidClassFileException { - return (getBCInfo().exceptionTypes == null) ? new TypeReference[0] : getBCInfo().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; - } - } - - /* - * @see com.ibm.wala.classLoader.IMethod#getLineNumber(int) - */ - public int getLineNumber(int bcIndex) { - try { - return (getBCInfo().lineNumberMap == null) ? -1 : getBCInfo().lineNumberMap[bcIndex]; - } catch (InvalidClassFileException e) { - return -1; - } - } - - /** - * @return Set - * @throws InvalidClassFileException - */ - public Set getCaughtExceptionTypes() throws InvalidClassFileException { - - ExceptionHandler[][] handlers = getHandlers(); - if (handlers == null) { - return Collections.emptySet(); - } - HashSet 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; - } - - /* - * @see com.ibm.wala.classLoader.IMethod#getSignature() - */ - public String getSignature() { - return getReference().getSignature(); - } - - /* - * @see com.ibm.wala.classLoader.IMethod#getSelector() - */ - public Selector getSelector() { - return getReference().getSelector(); - } - - /* - * @see com.ibm.wala.classLoader.IMethod#getLocalVariableName(int, int) - */ - public abstract String getLocalVariableName(int bcIndex, int localNumber); - - /* - * TODO: cache for efficiency? - * - * @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; - } -} +/******************************************************************************* + * 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.lang.ref.SoftReference; +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.BytecodeConstants; +import com.ibm.wala.shrikeBT.Constants; +import com.ibm.wala.shrikeBT.Decoder; +import com.ibm.wala.shrikeBT.ExceptionHandler; +import com.ibm.wala.shrikeBT.IArrayLoadInstruction; +import com.ibm.wala.shrikeBT.IArrayStoreInstruction; +import com.ibm.wala.shrikeBT.IGetInstruction; +import com.ibm.wala.shrikeBT.IInstruction; +import com.ibm.wala.shrikeBT.IInvokeInstruction; +import com.ibm.wala.shrikeBT.IPutInstruction; +import com.ibm.wala.shrikeBT.ITypeTestInstruction; +import com.ibm.wala.shrikeBT.MonitorInstruction; +import com.ibm.wala.shrikeBT.NewInstruction; +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.bytecode.BytecodeStream; +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.shrike.ShrikeUtil; +import com.ibm.wala.util.strings.Atom; +import com.ibm.wala.util.strings.ImmutableByteArray; + +/** + * A wrapper around a Shrike object that represents a method + */ +public abstract class ShrikeBTMethod 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. + */ + private SoftReference bcInfo; + + public ShrikeBTMethod(IClass klass) { + this.declaringClass = klass; + } + + protected synchronized BytecodeInfo getBCInfo() throws InvalidClassFileException { + BytecodeInfo result = null; + if (bcInfo != null) { + result = bcInfo.get(); + } + if (result == null) { + result = computeBCInfo(); + bcInfo = new SoftReference(result); + } + return result; + } + + /** + * Return the program counter (bytecode index) for a particular Shrike instruction index. + * + * @throws InvalidClassFileException + */ + public int getBytecodeIndex(int instructionIndex) throws InvalidClassFileException { + return getBCInfo().pcMap[instructionIndex]; + } + + /** + * Return the number of Shrike instructions for this method. + * + * @throws InvalidClassFileException + */ + public int getNumShrikeInstructions() throws InvalidClassFileException { + return getBCInfo().pcMap.length; + } + + /** + * @throws InvalidClassFileException + */ + public Collection getCallSites() throws InvalidClassFileException { + Collection empty = Collections.emptySet(); + if (isNative()) { + return empty; + } + return (getBCInfo().callSites == null) ? empty : Collections.unmodifiableCollection(Arrays.asList(getBCInfo().callSites)); + } + + /** + * @throws InvalidClassFileException + */ + Collection getNewSites() throws InvalidClassFileException { + Collection empty = Collections.emptySet(); + if (isNative()) { + return empty; + } + + return (getBCInfo().newSites == null) ? empty : Collections.unmodifiableCollection(Arrays.asList(getBCInfo().newSites)); + } + + /** + * @return Set , the exceptions that statements in this method may throw, + * @throws InvalidClassFileException + */ + public Collection getImplicitExceptionTypes() throws InvalidClassFileException { + if (isNative()) { + return Collections.emptySet(); + } + return (getBCInfo().implicitExceptions == null) ? Arrays.asList(new TypeReference[0]) : Arrays + .asList(getBCInfo().implicitExceptions); + } + + /** + * 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 + */ + private BytecodeInfo computeBCInfo() throws InvalidClassFileException { + BytecodeInfo result = new BytecodeInfo(); + result.exceptionTypes = computeDeclaredExceptions(); + + if (isNative()) { + return result; + } + if (verbose) { + methodsParsed += 1; + if (methodsParsed % 100 == 0) { + System.out.println(methodsParsed + " methods processed..."); + } + } + + processBytecodesWithShrikeBT(result); + return result; + } + + /** + * @return true iff this method has a monitorenter or monitorexit + * @throws InvalidClassFileException + */ + public boolean hasMonitorOp() throws InvalidClassFileException { + if (isNative()) { + return false; + } + return getBCInfo().hasMonitorOp; + } + + /** + * @return Set of FieldReference + * @throws InvalidClassFileException + */ + public Iterator getFieldsWritten() throws InvalidClassFileException { + if (isNative()) { + return EmptyIterator.instance(); + } + if (getBCInfo().fieldsWritten == null) { + return EmptyIterator.instance(); + } else { + List l = Arrays.asList(getBCInfo().fieldsWritten); + return l.iterator(); + } + } + + /** + * @return Iterator of FieldReference + * @throws InvalidClassFileException + */ + public Iterator getFieldsRead() throws InvalidClassFileException { + if (isNative()) { + return EmptyIterator.instance(); + } + if (getBCInfo().fieldsRead == null) { + return EmptyIterator.instance(); + } else { + List l = Arrays.asList(getBCInfo().fieldsRead); + return l.iterator(); + } + } + + /** + * @return Iterator of TypeReference + * @throws InvalidClassFileException + */ + public Iterator getArraysRead() throws InvalidClassFileException { + if (isNative()) { + return EmptyIterator.instance(); + } + return (getBCInfo().arraysRead == null) ? EmptyIterator.instance() : Arrays.asList(getBCInfo().arraysRead).iterator(); + } + + /** + * @return Iterator of TypeReference + * @throws InvalidClassFileException + */ + public Iterator getArraysWritten() throws InvalidClassFileException { + if (isNative()) { + return EmptyIterator.instance(); + } + if (getBCInfo().fieldsRead == null) { + return EmptyIterator.instance(); + } else { + List list = Arrays.asList(getBCInfo().arraysWritten); + return list.iterator(); + } + } + + /** + * @return Iterator of TypeReference + * @throws InvalidClassFileException + */ + public Iterator getCastTypes() throws InvalidClassFileException { + if (isNative()) { + return EmptyIterator.instance(); + } + return (getBCInfo().castTypes == null) ? EmptyIterator.instance() : Arrays.asList(getBCInfo().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(declaringClass.getClassLoader().getLanguage(), 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 isBridge() { + return ((getModifiers() & Constants.ACC_VOLATILE) != 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(BytecodeInfo info) throws InvalidClassFileException { + info.decoder = makeDecoder(); + if (!isAbstract() && info.decoder == null) { + Assertions.UNREACHABLE("bad method " + getReference()); + } + if (info.decoder == null) { + return; + } + info.pcMap = info.decoder.getInstructionsToBytecodes(); + + processDebugInfo(info); + + SimpleVisitor simpleVisitor = new SimpleVisitor(info); + + BytecodeLanguage lang = (BytecodeLanguage) getDeclaringClass().getClassLoader().getLanguage(); + IInstruction[] instructions = info.decoder.getInstructions(); + for (int i = 0; i < instructions.length; i++) { + simpleVisitor.setInstructionIndex(i); + instructions[i].visit(simpleVisitor); + if (instructions[i].isPEI()) { + Collection t = lang.getImplicitExceptionTypes(instructions[i]); + if (t != null) { + simpleVisitor.implicitExceptions.addAll(t); + } + } + } + + // copy the Set results into arrays; will use less + // storage + copyVisitorSetsToArrays(simpleVisitor, info); + } + + private void copyVisitorSetsToArrays(SimpleVisitor simpleVisitor, BytecodeInfo info) { + info.newSites = new NewSiteReference[simpleVisitor.newSites.size()]; + int i = 0; + for (Iterator it = simpleVisitor.newSites.iterator(); it.hasNext();) { + info.newSites[i++] = it.next(); + } + + info.fieldsRead = new FieldReference[simpleVisitor.fieldsRead.size()]; + i = 0; + for (Iterator it = simpleVisitor.fieldsRead.iterator(); it.hasNext();) { + info.fieldsRead[i++] = it.next(); + } + + info.fieldsRead = new FieldReference[simpleVisitor.fieldsRead.size()]; + i = 0; + for (Iterator it = simpleVisitor.fieldsRead.iterator(); it.hasNext();) { + info.fieldsRead[i++] = it.next(); + } + + info.fieldsWritten = new FieldReference[simpleVisitor.fieldsWritten.size()]; + i = 0; + for (Iterator it = simpleVisitor.fieldsWritten.iterator(); it.hasNext();) { + info.fieldsWritten[i++] = it.next(); + } + + info.callSites = new CallSiteReference[simpleVisitor.callSites.size()]; + i = 0; + for (Iterator it = simpleVisitor.callSites.iterator(); it.hasNext();) { + info.callSites[i++] = it.next(); + } + + info.arraysRead = new TypeReference[simpleVisitor.arraysRead.size()]; + i = 0; + for (Iterator it = simpleVisitor.arraysRead.iterator(); it.hasNext();) { + info.arraysRead[i++] = it.next(); + } + + info.arraysWritten = new TypeReference[simpleVisitor.arraysWritten.size()]; + i = 0; + for (Iterator it = simpleVisitor.arraysWritten.iterator(); it.hasNext();) { + info.arraysWritten[i++] = it.next(); + } + + info.implicitExceptions = new TypeReference[simpleVisitor.implicitExceptions.size()]; + i = 0; + for (Iterator it = simpleVisitor.implicitExceptions.iterator(); it.hasNext();) { + info.implicitExceptions[i++] = (TypeReference) it.next(); + } + + info.castTypes = new TypeReference[simpleVisitor.castTypes.size()]; + i = 0; + for (Iterator it = simpleVisitor.castTypes.iterator(); it.hasNext();) { + info.castTypes[i++] = it.next(); + } + + info.hasMonitorOp = simpleVisitor.hasMonitorOp; + } + + /** + * @see java.lang.Object#toString() + */ + @Override + public String toString() { + return getReference().toString(); + } + + /** + * @see java.lang.Object#equals(Object) + */ + @Override + public boolean equals(Object obj) { + // instanceof is OK because this class is final. + // if (this.getClass().equals(obj.getClass())) { + if (obj instanceof ShrikeBTMethod) { + ShrikeBTMethod that = (ShrikeBTMethod) obj; + return (getDeclaringClass().equals(that.getDeclaringClass()) && getReference().equals(that.getReference())); + } else { + return false; + } + } + + /** + * @see java.lang.Object#hashCode() + */ + @Override + public int hashCode() { + return 9661 * getReference().hashCode(); + } + + /* + * @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(); + } + + /** + * + * A visitor used to process bytecodes + * + */ + private class SimpleVisitor extends IInstruction.Visitor { + + private final BytecodeInfo info; + + public SimpleVisitor(BytecodeInfo info) { + this.info = info; + } + + // TODO: make a better Set implementation for these. + final Set callSites = HashSetFactory.make(5); + + final Set fieldsWritten = HashSetFactory.make(5); + + final Set fieldsRead = HashSetFactory.make(5); + + final Set newSites = HashSetFactory.make(5); + + final Set arraysRead = HashSetFactory.make(5); + + final Set arraysWritten = HashSetFactory.make(5); + + final Set implicitExceptions = HashSetFactory.make(5); + + final Set castTypes = HashSetFactory.make(5); + + boolean hasMonitorOp; + + private int instructionIndex; + + public void setInstructionIndex(int i) { + instructionIndex = i; + } + + public int getProgramCounter() throws InvalidClassFileException { + return info.pcMap[instructionIndex]; + } + + @Override + public void visitMonitor(MonitorInstruction instruction) { + hasMonitorOp = true; + } + + @Override + 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(); + } + } + + @Override + public void visitGet(IGetInstruction instruction) { + ClassLoaderReference loader = getReference().getDeclaringClass().getClassLoader(); + FieldReference f = FieldReference.findOrCreate(loader, instruction.getClassType(), instruction.getFieldName(), instruction + .getFieldType()); + fieldsRead.add(f); + } + + @Override + public void visitPut(IPutInstruction instruction) { + ClassLoaderReference loader = getReference().getDeclaringClass().getClassLoader(); + FieldReference f = FieldReference.findOrCreate(loader, instruction.getClassType(), instruction.getFieldName(), instruction + .getFieldType()); + fieldsWritten.add(f); + } + + @Override + public void visitInvoke(IInvokeInstruction instruction) { + IClassLoader loader = getDeclaringClass().getClassLoader(); + MethodReference m = MethodReference.findOrCreate(loader.getLanguage(), loader.getReference(), instruction.getClassType(), + instruction.getMethodName(), instruction.getMethodSignature()); + int programCounter = 0; + try { + programCounter = getProgramCounter(); + } catch (InvalidClassFileException e) { + e.printStackTrace(); + Assertions.UNREACHABLE(); + } + CallSiteReference site = null; + site = CallSiteReference.make(programCounter, m, instruction.getInvocationCode()); + callSites.add(site); + } + + /* + * @see com.ibm.wala.shrikeBT.Instruction.Visitor#visitArrayLoad(com.ibm.wala.shrikeBT.ArrayLoadInstruction) + */ + @Override + public void visitArrayLoad(IArrayLoadInstruction instruction) { + arraysRead.add(ShrikeUtil.makeTypeReference(getDeclaringClass().getClassLoader().getReference(), instruction.getType())); + } + + /* + * @see com.ibm.wala.shrikeBT.Instruction.Visitor#visitArrayStore(com.ibm.wala.shrikeBT.ArrayStoreInstruction) + */ + @Override + public void visitArrayStore(IArrayStoreInstruction instruction) { + arraysWritten.add(ShrikeUtil.makeTypeReference(getDeclaringClass().getClassLoader().getReference(), instruction.getType())); + } + + @Override + public void visitCheckCast(ITypeTestInstruction instruction) { + for(String t : instruction.getTypes()) { + castTypes.add(ShrikeUtil.makeTypeReference(getDeclaringClass().getClassLoader().getReference(), t)); + } + } + } + + /** + */ + public IInstruction[] getInstructions() throws InvalidClassFileException { + if (getBCInfo().decoder == null) { + return null; + } else { + return getBCInfo().decoder.getInstructions(); + } + } + + public ExceptionHandler[][] getHandlers() throws InvalidClassFileException { + if (getBCInfo().decoder == null) { + return null; + } else { + return getBCInfo().decoder.getHandlers(); + } + } + + /** + * By convention, for a non-static method, getParameterType(0) is the this pointer + */ + 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; + } + } + + /* + * @see com.ibm.wala.classLoader.IMethod#hasExceptionHandler() + */ + public abstract boolean hasExceptionHandler(); + + /** + * Clients should not modify the returned array. TODO: clone to avoid the problem? + * + * @throws InvalidClassFileException + * + * @see com.ibm.wala.classLoader.IMethod#getDeclaredExceptions() + */ + public TypeReference[] getDeclaredExceptions() throws InvalidClassFileException { + return (getBCInfo().exceptionTypes == null) ? new TypeReference[0] : getBCInfo().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; + } + } + + /* + * @see com.ibm.wala.classLoader.IMethod#getLineNumber(int) + */ + public int getLineNumber(int bcIndex) { + try { + return (getBCInfo().lineNumberMap == null) ? -1 : getBCInfo().lineNumberMap[bcIndex]; + } catch (InvalidClassFileException e) { + return -1; + } + } + + /** + * @return Set + * @throws InvalidClassFileException + */ + public Set getCaughtExceptionTypes() throws InvalidClassFileException { + + ExceptionHandler[][] handlers = getHandlers(); + if (handlers == null) { + return Collections.emptySet(); + } + HashSet 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; + } + + /* + * @see com.ibm.wala.classLoader.IMethod#getSignature() + */ + public String getSignature() { + return getReference().getSignature(); + } + + /* + * @see com.ibm.wala.classLoader.IMethod#getSelector() + */ + public Selector getSelector() { + return getReference().getSelector(); + } + + /* + * @see com.ibm.wala.classLoader.IMethod#getLocalVariableName(int, int) + */ + public abstract String getLocalVariableName(int bcIndex, int localNumber); + + /* + * TODO: cache for efficiency? + * + * @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; + } +} diff --git a/com.ibm.wala.core/src/com/ibm/wala/classLoader/ShrikeCTMethod.java b/com.ibm.wala.core/src/com/ibm/wala/classLoader/ShrikeCTMethod.java index 3257e66ec..4423e1254 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/classLoader/ShrikeCTMethod.java +++ b/com.ibm.wala.core/src/com/ibm/wala/classLoader/ShrikeCTMethod.java @@ -1,375 +1,375 @@ -/******************************************************************************* - * 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 com.ibm.wala.ipa.cha.IClassHierarchy; -import com.ibm.wala.shrikeBT.Decoder; -import com.ibm.wala.shrikeBT.IndirectionData; -import com.ibm.wala.shrikeBT.shrikeCT.CTDecoder; -import com.ibm.wala.shrikeCT.AnnotationsReader; -import com.ibm.wala.shrikeCT.ClassReader; -import com.ibm.wala.shrikeCT.ClassReader.AttrIterator; -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.RuntimeInvisibleAnnotationsReader; -import com.ibm.wala.shrikeCT.RuntimeVisibleAnnotationsReader; -import com.ibm.wala.shrikeCT.SignatureReader; -import com.ibm.wala.types.TypeReference; -import com.ibm.wala.types.annotations.Annotation; -import com.ibm.wala.types.generics.MethodTypeSignature; -import com.ibm.wala.util.debug.Assertions; - -/** - * A wrapper around a Shrike object that represents a method - */ -public final class ShrikeCTMethod extends ShrikeBTMethod implements IBytecodeMethod { - - /** - * The index of this method in the declaring class's method list according to Shrike CT. - */ - final private int shrikeMethodIndex; - - /** - * JVM-level modifiers for this method a value of -1 means "uninitialized" - */ - private int modifiers = -1; - - private final IClassHierarchy cha; - - public ShrikeCTMethod(IClass klass, int index) { - - super(klass); - if (klass == null) { - throw new IllegalArgumentException("klass is null"); - } - this.shrikeMethodIndex = index; - this.cha = klass.getClassHierarchy(); - } - - @Override - public byte[] getBytecodes() { - CodeReader code = getCodeReader(); - if (code == null) { - return null; - } else { - return code.getBytecode(); - } - } - - @Override - protected String getMethodName() throws InvalidClassFileException { - ClassReader reader = getClassReader(); - return reader.getMethodName(shrikeMethodIndex); - } - - @Override - protected String getMethodSignature() throws InvalidClassFileException { - ClassReader reader = getClassReader(); - return reader.getMethodType(shrikeMethodIndex); - } - - @Override - protected int getModifiers() { - if (modifiers == -1) { - modifiers = getClassReader().getMethodAccessFlags(shrikeMethodIndex); - } - return modifiers; - } - - @Override - 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; - } - - @Override - public int getMaxLocals() { - CodeReader reader = getCodeReader(); - return reader.getMaxLocals(); - } - - @Override - 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; - } - - @Override - public boolean hasExceptionHandler() { - CodeReader reader = getCodeReader(); - if (reader == null) - return false; - int[] handlers = reader.getRawHandlers(); - return handlers != null && handlers.length > 0; - } - - @Override - protected String[] getDeclaredExceptionTypeNames() throws InvalidClassFileException { - ExceptionsReader reader = getExceptionReader(); - if (reader == null) { - return null; - } else { - return reader.getClasses(); - } - } - - @Override - protected void processDebugInfo(BytecodeInfo bcInfo) throws InvalidClassFileException { - CodeReader cr = getCodeReader(); - bcInfo.lineNumberMap = LineNumberTableReader.makeBytecodeToSourceMap(cr); - bcInfo.localVariableMap = LocalVariableTableReader.makeVarMap(cr); - } - - @Override - public String getLocalVariableName(int bcIndex, int localNumber){ - int[][] map = null; - try { - map = getBCInfo().localVariableMap; - } catch (InvalidClassFileException e1) { - return null; - } - - 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? - * - * @see com.ibm.wala.classLoader.IMethod#hasLocalVariableTable() - */ - @Override - 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 ((ShrikeClass) 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().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().equals("Exceptions")) { - result = new ExceptionsReader(iter); - break; - } - } - } catch (InvalidClassFileException e) { - Assertions.UNREACHABLE(); - } - return result; - } - - private SignatureReader getSignatureReader() { - ClassReader.AttrIterator iter = new AttrIterator(); - getClassReader().initMethodAttributeIterator(shrikeMethodIndex, iter); - - // search for the desired attribute - SignatureReader result = null; - try { - for (; iter.isValid(); iter.advance()) { - if (iter.getName().equals("Signature")) { - result = new SignatureReader(iter); - break; - } - } - } catch (InvalidClassFileException e) { - Assertions.UNREACHABLE(); - } - return result; - } - - private AnnotationsReader getAnnotationsReader(boolean runtimeInvisible) { - ClassReader.AttrIterator iter = new AttrIterator(); - getClassReader().initMethodAttributeIterator(shrikeMethodIndex, iter); - - // search for the desired attribute - AnnotationsReader result = null; - try { - for (; iter.isValid(); iter.advance()) { - if (runtimeInvisible) { - if (iter.getName().equals(RuntimeInvisibleAnnotationsReader.attrName)) { - result = new RuntimeInvisibleAnnotationsReader(iter); - break; - } - } else { - if (iter.getName().equals(RuntimeVisibleAnnotationsReader.attrName)) { - result = new RuntimeVisibleAnnotationsReader(iter); - break; - } - } - } - } catch (InvalidClassFileException e) { - Assertions.UNREACHABLE(); - } - return result; - } - - private String computeGenericsSignature() throws InvalidClassFileException { - SignatureReader reader = getSignatureReader(); - if (reader == null) { - return null; - } else { - return reader.getSignature(); - } - } - - public TypeReference getReturnType() { - return getReference().getReturnType(); - } - - public IClassHierarchy getClassHierarchy() { - return cha; - } - - /** - * TODO: cache? - * - * @return raw "Signature" attribute from the bytecode - * @throws InvalidClassFileException - */ - private String getGenericsSignature() throws InvalidClassFileException { - return computeGenericsSignature(); - } - - /** - * UNDER CONSTRUCTION - * - * @throws InvalidClassFileException - */ - public MethodTypeSignature getMethodTypeSignature() throws InvalidClassFileException { - String sig = getGenericsSignature(); - return sig == null ? null : MethodTypeSignature.make(sig); - } - - /** - * read the runtime-invisible annotations from the class file - */ - public Collection getRuntimeInvisibleAnnotations() throws InvalidClassFileException { - return getAnnotations(true); - } - - /** - * read the runtime-visible annotations from the class file - */ - public Collection getRuntimeVisibleAnnotations() throws InvalidClassFileException { - return getAnnotations(false); - } - - public Collection getAnnotations(boolean runtimeInvisible) throws InvalidClassFileException { - AnnotationsReader r = getAnnotationsReader(runtimeInvisible); - return Annotation.getAnnotationsFromReader(r, getDeclaringClass().getClassLoader().getReference()); - } - - - private static final IndirectionData NO_INDIRECTIONS = new IndirectionData() { - - private final int[] NOTHING = new int[0]; - - public int[] indirectlyReadLocals(int instructionIndex) { - return NOTHING; - } - - public int[] indirectlyWrittenLocals(int instructionIndex) { - return NOTHING; - } - - }; - - public IndirectionData getIndirectionData() { - return NO_INDIRECTIONS; - } -} +/******************************************************************************* + * 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 com.ibm.wala.ipa.cha.IClassHierarchy; +import com.ibm.wala.shrikeBT.Decoder; +import com.ibm.wala.shrikeBT.IndirectionData; +import com.ibm.wala.shrikeBT.shrikeCT.CTDecoder; +import com.ibm.wala.shrikeCT.AnnotationsReader; +import com.ibm.wala.shrikeCT.ClassReader; +import com.ibm.wala.shrikeCT.ClassReader.AttrIterator; +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.RuntimeInvisibleAnnotationsReader; +import com.ibm.wala.shrikeCT.RuntimeVisibleAnnotationsReader; +import com.ibm.wala.shrikeCT.SignatureReader; +import com.ibm.wala.types.TypeReference; +import com.ibm.wala.types.annotations.Annotation; +import com.ibm.wala.types.generics.MethodTypeSignature; +import com.ibm.wala.util.debug.Assertions; + +/** + * A wrapper around a Shrike object that represents a method + */ +public final class ShrikeCTMethod extends ShrikeBTMethod implements IBytecodeMethod { + + /** + * The index of this method in the declaring class's method list according to Shrike CT. + */ + final private int shrikeMethodIndex; + + /** + * JVM-level modifiers for this method a value of -1 means "uninitialized" + */ + private int modifiers = -1; + + private final IClassHierarchy cha; + + public ShrikeCTMethod(IClass klass, int index) { + + super(klass); + if (klass == null) { + throw new IllegalArgumentException("klass is null"); + } + this.shrikeMethodIndex = index; + this.cha = klass.getClassHierarchy(); + } + + @Override + public byte[] getBytecodes() { + CodeReader code = getCodeReader(); + if (code == null) { + return null; + } else { + return code.getBytecode(); + } + } + + @Override + protected String getMethodName() throws InvalidClassFileException { + ClassReader reader = getClassReader(); + return reader.getMethodName(shrikeMethodIndex); + } + + @Override + protected String getMethodSignature() throws InvalidClassFileException { + ClassReader reader = getClassReader(); + return reader.getMethodType(shrikeMethodIndex); + } + + @Override + protected int getModifiers() { + if (modifiers == -1) { + modifiers = getClassReader().getMethodAccessFlags(shrikeMethodIndex); + } + return modifiers; + } + + @Override + 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; + } + + @Override + public int getMaxLocals() { + CodeReader reader = getCodeReader(); + return reader.getMaxLocals(); + } + + @Override + 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; + } + + @Override + public boolean hasExceptionHandler() { + CodeReader reader = getCodeReader(); + if (reader == null) + return false; + int[] handlers = reader.getRawHandlers(); + return handlers != null && handlers.length > 0; + } + + @Override + protected String[] getDeclaredExceptionTypeNames() throws InvalidClassFileException { + ExceptionsReader reader = getExceptionReader(); + if (reader == null) { + return null; + } else { + return reader.getClasses(); + } + } + + @Override + protected void processDebugInfo(BytecodeInfo bcInfo) throws InvalidClassFileException { + CodeReader cr = getCodeReader(); + bcInfo.lineNumberMap = LineNumberTableReader.makeBytecodeToSourceMap(cr); + bcInfo.localVariableMap = LocalVariableTableReader.makeVarMap(cr); + } + + @Override + public String getLocalVariableName(int bcIndex, int localNumber){ + int[][] map = null; + try { + map = getBCInfo().localVariableMap; + } catch (InvalidClassFileException e1) { + return null; + } + + 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? + * + * @see com.ibm.wala.classLoader.IMethod#hasLocalVariableTable() + */ + @Override + 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 ((ShrikeClass) 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().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().equals("Exceptions")) { + result = new ExceptionsReader(iter); + break; + } + } + } catch (InvalidClassFileException e) { + Assertions.UNREACHABLE(); + } + return result; + } + + private SignatureReader getSignatureReader() { + ClassReader.AttrIterator iter = new AttrIterator(); + getClassReader().initMethodAttributeIterator(shrikeMethodIndex, iter); + + // search for the desired attribute + SignatureReader result = null; + try { + for (; iter.isValid(); iter.advance()) { + if (iter.getName().equals("Signature")) { + result = new SignatureReader(iter); + break; + } + } + } catch (InvalidClassFileException e) { + Assertions.UNREACHABLE(); + } + return result; + } + + private AnnotationsReader getAnnotationsReader(boolean runtimeInvisible) { + ClassReader.AttrIterator iter = new AttrIterator(); + getClassReader().initMethodAttributeIterator(shrikeMethodIndex, iter); + + // search for the desired attribute + AnnotationsReader result = null; + try { + for (; iter.isValid(); iter.advance()) { + if (runtimeInvisible) { + if (iter.getName().equals(RuntimeInvisibleAnnotationsReader.attrName)) { + result = new RuntimeInvisibleAnnotationsReader(iter); + break; + } + } else { + if (iter.getName().equals(RuntimeVisibleAnnotationsReader.attrName)) { + result = new RuntimeVisibleAnnotationsReader(iter); + break; + } + } + } + } catch (InvalidClassFileException e) { + Assertions.UNREACHABLE(); + } + return result; + } + + private String computeGenericsSignature() throws InvalidClassFileException { + SignatureReader reader = getSignatureReader(); + if (reader == null) { + return null; + } else { + return reader.getSignature(); + } + } + + public TypeReference getReturnType() { + return getReference().getReturnType(); + } + + public IClassHierarchy getClassHierarchy() { + return cha; + } + + /** + * TODO: cache? + * + * @return raw "Signature" attribute from the bytecode + * @throws InvalidClassFileException + */ + private String getGenericsSignature() throws InvalidClassFileException { + return computeGenericsSignature(); + } + + /** + * UNDER CONSTRUCTION + * + * @throws InvalidClassFileException + */ + public MethodTypeSignature getMethodTypeSignature() throws InvalidClassFileException { + String sig = getGenericsSignature(); + return sig == null ? null : MethodTypeSignature.make(sig); + } + + /** + * read the runtime-invisible annotations from the class file + */ + public Collection getRuntimeInvisibleAnnotations() throws InvalidClassFileException { + return getAnnotations(true); + } + + /** + * read the runtime-visible annotations from the class file + */ + public Collection getRuntimeVisibleAnnotations() throws InvalidClassFileException { + return getAnnotations(false); + } + + public Collection getAnnotations(boolean runtimeInvisible) throws InvalidClassFileException { + AnnotationsReader r = getAnnotationsReader(runtimeInvisible); + return Annotation.getAnnotationsFromReader(r, getDeclaringClass().getClassLoader().getReference()); + } + + + private static final IndirectionData NO_INDIRECTIONS = new IndirectionData() { + + private final int[] NOTHING = new int[0]; + + public int[] indirectlyReadLocals(int instructionIndex) { + return NOTHING; + } + + public int[] indirectlyWrittenLocals(int instructionIndex) { + return NOTHING; + } + + }; + + public IndirectionData getIndirectionData() { + return NO_INDIRECTIONS; + } +} diff --git a/com.ibm.wala.core/src/com/ibm/wala/classLoader/ShrikeClass.java b/com.ibm.wala.core/src/com/ibm/wala/classLoader/ShrikeClass.java index 3d35b1585..1528778d7 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/classLoader/ShrikeClass.java +++ b/com.ibm.wala.core/src/com/ibm/wala/classLoader/ShrikeClass.java @@ -1,402 +1,402 @@ -/******************************************************************************* - * 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.Collection; -import java.util.Iterator; -import java.util.List; - -import com.ibm.wala.ipa.cha.IClassHierarchy; -import com.ibm.wala.shrikeBT.Constants; -import com.ibm.wala.shrikeCT.AnnotationsReader; -import com.ibm.wala.shrikeCT.ClassConstants; -import com.ibm.wala.shrikeCT.ClassReader; -import com.ibm.wala.shrikeCT.ClassReader.AttrIterator; -import com.ibm.wala.shrikeCT.InnerClassesReader; -import com.ibm.wala.shrikeCT.InvalidClassFileException; -import com.ibm.wala.shrikeCT.RuntimeInvisibleAnnotationsReader; -import com.ibm.wala.shrikeCT.RuntimeVisibleAnnotationsReader; -import com.ibm.wala.shrikeCT.SignatureReader; -import com.ibm.wala.types.TypeName; -import com.ibm.wala.types.TypeReference; -import com.ibm.wala.types.annotations.Annotation; -import com.ibm.wala.types.generics.ClassSignature; -import com.ibm.wala.util.debug.Assertions; -import com.ibm.wala.util.shrike.ShrikeClassReaderHandle; -import com.ibm.wala.util.strings.Atom; -import com.ibm.wala.util.strings.ImmutableByteArray; - -/** - * A class read from Shrike - */ -public final class ShrikeClass extends JVMClass { - - static final boolean DEBUG = false; - - /** - * The Shrike object that knows how to read the class file - */ - private final ShrikeClassReaderHandle reader; - - /** - * @throws IllegalArgumentException if reader is null - */ - public ShrikeClass(ShrikeClassReaderHandle reader, IClassLoader loader, IClassHierarchy cha) throws InvalidClassFileException { - super(loader, cha); - if (reader == null) { - throw new IllegalArgumentException("reader is null"); - } - this.reader = reader; - 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 instanceList = new ArrayList(fieldCount); - List staticList = new ArrayList(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)); - Collection annotations = null; - annotations = getRuntimeInvisibleAnnotations(i); - annotations = annotations.isEmpty() ? null : annotations; - - if ((accessFlags & ClassConstants.ACC_STATIC) == 0) { - addFieldToList(instanceList, name, b, accessFlags, annotations); - } else { - addFieldToList(staticList, name, b, accessFlags, annotations); - } - } - instanceFields = new IField[instanceList.size()]; - populateFieldArrayFromList(instanceList, instanceFields); - staticFields = new IField[staticList.size()]; - populateFieldArrayFromList(staticList, staticFields); - - } catch (InvalidClassFileException e) { - e.printStackTrace(); - Assertions.UNREACHABLE(); - } - } - - /** - * @throws InvalidClassFileException - */ - private void computeModifiers() throws InvalidClassFileException { - modifiers = reader.get().getAccessFlags(); - } - - /** - * 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(); - } - } - - /** - * 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(); - } - } - - /** - * initialize the declared methods array - * - * @throws InvalidClassFileException - */ - @Override - protected ShrikeCTMethod[] computeDeclaredMethods() throws InvalidClassFileException { - int methodCount = reader.get().getMethodCount(); - ShrikeCTMethod[] result = new ShrikeCTMethod[methodCount]; - for (int i = 0; i < methodCount; i++) { - ShrikeCTMethod m = new ShrikeCTMethod(this, i); - if (DEBUG) { - System.err.println(("Register method " + m + " for class " + this)); - } - result[i] = m; - } - return result; - } - - - /** - * 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)); - } - - - /** - * @see java.lang.Object#equals(Object) - */ - @Override - 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 ShrikeClass) { - return getReference().equals(((ShrikeClass) obj).getReference()); - } else { - return false; - } - } - - public ClassReader getReader() { - try { - return reader.get(); - } catch (InvalidClassFileException e) { - e.printStackTrace(); - Assertions.UNREACHABLE(); - return null; - } - } - - /** - * 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().iterator(); it.hasNext();) { - ShrikeCTMethod m = (ShrikeCTMethod) 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(); - } - - public Collection getRuntimeInvisibleAnnotations() throws InvalidClassFileException { - return getAnnotations(true); - } - - public Collection getRuntimeVisibleAnnotations() throws InvalidClassFileException { - return getAnnotations(false); - } - - public Collection getAnnotations(boolean runtimeInvisible) throws InvalidClassFileException { - AnnotationsReader r = getAnnotationsReader(runtimeInvisible); - return Annotation.getAnnotationsFromReader(r, getClassLoader().getReference()); - } - - private AnnotationsReader getAnnotationsReader(boolean runtimeInvisable) throws InvalidClassFileException { - ClassReader r = reader.get(); - ClassReader.AttrIterator attrs = new ClassReader.AttrIterator(); - r.initClassAttributeIterator(attrs); - - // search for the desired attribute - AnnotationsReader result = null; - try { - for (; attrs.isValid(); attrs.advance()) { - if (runtimeInvisable){ - if (attrs.getName().equals(RuntimeInvisibleAnnotationsReader.attrName)) { - result = new RuntimeInvisibleAnnotationsReader(attrs); - break; - } - } else { - if (attrs.getName().equals(RuntimeVisibleAnnotationsReader.attrName)) { - result = new RuntimeVisibleAnnotationsReader(attrs); - break; - } - } - } - } catch (InvalidClassFileException e) { - Assertions.UNREACHABLE(); - } - return result; - } - - - private InnerClassesReader getInnerClassesReader() throws InvalidClassFileException { - ClassReader r = reader.get(); - ClassReader.AttrIterator attrs = new ClassReader.AttrIterator(); - r.initClassAttributeIterator(attrs); - - // search for the desired attribute - InnerClassesReader result = null; - try { - for (; attrs.isValid(); attrs.advance()) { - if (attrs.getName().equals("InnerClasses")) { - result = new InnerClassesReader(attrs); - break; - } - } - } catch (InvalidClassFileException e) { - Assertions.UNREACHABLE(); - } - return result; - } - - private RuntimeInvisibleAnnotationsReader getRuntimeInvisibleAnnotationsReader(int fieldIndex) throws InvalidClassFileException { - ClassReader.AttrIterator iter = new AttrIterator(); - reader.get().initFieldAttributeIterator(fieldIndex, iter); - - // search for the desired attribute - RuntimeInvisibleAnnotationsReader result = null; - try { - for (; iter.isValid(); iter.advance()) { - if (iter.getName().toString().equals("RuntimeInvisibleAnnotations")) { - result = new RuntimeInvisibleAnnotationsReader(iter); - break; - } - } - } catch (InvalidClassFileException e) { - Assertions.UNREACHABLE(); - } - return result; - } - - /** - * read the runtime-invisible annotations from the class file - */ - public Collection getRuntimeInvisibleAnnotations(int fieldIndex) throws InvalidClassFileException { - RuntimeInvisibleAnnotationsReader r = getRuntimeInvisibleAnnotationsReader(fieldIndex); - return Annotation.getAnnotationsFromReader(r, getClassLoader().getReference()); - } - - private SignatureReader getSignatureReader() throws InvalidClassFileException { - ClassReader r = reader.get(); - ClassReader.AttrIterator attrs = new ClassReader.AttrIterator(); - r.initClassAttributeIterator(attrs); - - // search for the desired attribute - SignatureReader result = null; - try { - for (; attrs.isValid(); attrs.advance()) { - if (attrs.getName().toString().equals("Signature")) { - result = new SignatureReader(attrs); - break; - } - } - } catch (InvalidClassFileException e) { - Assertions.UNREACHABLE(); - } - return result; - } - - public ClassSignature getClassSignature() throws InvalidClassFileException { - // TODO: cache this later? - SignatureReader r = getSignatureReader(); - if (r == null) { - return null; - } else { - return ClassSignature.make(r.getSignature()); - } - } - - public ModuleEntry getModuleEntry() { - return reader.getModuleEntry(); - } - - /** - * Does the class file indicate that this class is a member of some other class? - * - * @throws InvalidClassFileException - */ - public boolean isInnerClass() throws InvalidClassFileException { - InnerClassesReader r = getInnerClassesReader(); - if (r != null) { - for (String s : r.getInnerClasses()) { - if (s.equals(getName().toString().substring(1))) { - String outer = r.getOuterClass(s); - return outer != null; - } - } - } - return false; - } - - /** - * Does the class file indicate that this class is a static inner class? - * - * @throws InvalidClassFileException - */ - public boolean isStaticInnerClass() throws InvalidClassFileException { - InnerClassesReader r = getInnerClassesReader(); - if (r != null) { - for (String s : r.getInnerClasses()) { - if (s.equals(getName().toString().substring(1))) { - String outer = r.getOuterClass(s); - if (outer != null) { - int modifiers = r.getAccessFlags(s); - boolean result = ((modifiers & Constants.ACC_STATIC) != 0); - return result; - } - } - } - } - return false; - } - - /** - * If this is an inner class, return the outer class. Else return null. - * @throws InvalidClassFileException - */ - public TypeReference getOuterClass() throws InvalidClassFileException { - if (!isInnerClass()) { - return null; - } - InnerClassesReader r = getInnerClassesReader(); - for (String s : r.getInnerClasses()) { - if (s.equals(getName().toString().substring(1))) { - String outer = r.getOuterClass(s); - if (outer != null) { - return TypeReference.findOrCreate(getClassLoader().getReference(), "L" + outer); - } - } - } - return null; - } +/******************************************************************************* + * 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.Collection; +import java.util.Iterator; +import java.util.List; + +import com.ibm.wala.ipa.cha.IClassHierarchy; +import com.ibm.wala.shrikeBT.Constants; +import com.ibm.wala.shrikeCT.AnnotationsReader; +import com.ibm.wala.shrikeCT.ClassConstants; +import com.ibm.wala.shrikeCT.ClassReader; +import com.ibm.wala.shrikeCT.ClassReader.AttrIterator; +import com.ibm.wala.shrikeCT.InnerClassesReader; +import com.ibm.wala.shrikeCT.InvalidClassFileException; +import com.ibm.wala.shrikeCT.RuntimeInvisibleAnnotationsReader; +import com.ibm.wala.shrikeCT.RuntimeVisibleAnnotationsReader; +import com.ibm.wala.shrikeCT.SignatureReader; +import com.ibm.wala.types.TypeName; +import com.ibm.wala.types.TypeReference; +import com.ibm.wala.types.annotations.Annotation; +import com.ibm.wala.types.generics.ClassSignature; +import com.ibm.wala.util.debug.Assertions; +import com.ibm.wala.util.shrike.ShrikeClassReaderHandle; +import com.ibm.wala.util.strings.Atom; +import com.ibm.wala.util.strings.ImmutableByteArray; + +/** + * A class read from Shrike + */ +public final class ShrikeClass extends JVMClass { + + static final boolean DEBUG = false; + + /** + * The Shrike object that knows how to read the class file + */ + private final ShrikeClassReaderHandle reader; + + /** + * @throws IllegalArgumentException if reader is null + */ + public ShrikeClass(ShrikeClassReaderHandle reader, IClassLoader loader, IClassHierarchy cha) throws InvalidClassFileException { + super(loader, cha); + if (reader == null) { + throw new IllegalArgumentException("reader is null"); + } + this.reader = reader; + 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 instanceList = new ArrayList(fieldCount); + List staticList = new ArrayList(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)); + Collection annotations = null; + annotations = getRuntimeInvisibleAnnotations(i); + annotations = annotations.isEmpty() ? null : annotations; + + if ((accessFlags & ClassConstants.ACC_STATIC) == 0) { + addFieldToList(instanceList, name, b, accessFlags, annotations); + } else { + addFieldToList(staticList, name, b, accessFlags, annotations); + } + } + instanceFields = new IField[instanceList.size()]; + populateFieldArrayFromList(instanceList, instanceFields); + staticFields = new IField[staticList.size()]; + populateFieldArrayFromList(staticList, staticFields); + + } catch (InvalidClassFileException e) { + e.printStackTrace(); + Assertions.UNREACHABLE(); + } + } + + /** + * @throws InvalidClassFileException + */ + private void computeModifiers() throws InvalidClassFileException { + modifiers = reader.get().getAccessFlags(); + } + + /** + * 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(); + } + } + + /** + * 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(); + } + } + + /** + * initialize the declared methods array + * + * @throws InvalidClassFileException + */ + @Override + protected ShrikeCTMethod[] computeDeclaredMethods() throws InvalidClassFileException { + int methodCount = reader.get().getMethodCount(); + ShrikeCTMethod[] result = new ShrikeCTMethod[methodCount]; + for (int i = 0; i < methodCount; i++) { + ShrikeCTMethod m = new ShrikeCTMethod(this, i); + if (DEBUG) { + System.err.println(("Register method " + m + " for class " + this)); + } + result[i] = m; + } + return result; + } + + + /** + * 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)); + } + + + /** + * @see java.lang.Object#equals(Object) + */ + @Override + 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 ShrikeClass) { + return getReference().equals(((ShrikeClass) obj).getReference()); + } else { + return false; + } + } + + public ClassReader getReader() { + try { + return reader.get(); + } catch (InvalidClassFileException e) { + e.printStackTrace(); + Assertions.UNREACHABLE(); + return null; + } + } + + /** + * 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().iterator(); it.hasNext();) { + ShrikeCTMethod m = (ShrikeCTMethod) 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(); + } + + public Collection getRuntimeInvisibleAnnotations() throws InvalidClassFileException { + return getAnnotations(true); + } + + public Collection getRuntimeVisibleAnnotations() throws InvalidClassFileException { + return getAnnotations(false); + } + + public Collection getAnnotations(boolean runtimeInvisible) throws InvalidClassFileException { + AnnotationsReader r = getAnnotationsReader(runtimeInvisible); + return Annotation.getAnnotationsFromReader(r, getClassLoader().getReference()); + } + + private AnnotationsReader getAnnotationsReader(boolean runtimeInvisable) throws InvalidClassFileException { + ClassReader r = reader.get(); + ClassReader.AttrIterator attrs = new ClassReader.AttrIterator(); + r.initClassAttributeIterator(attrs); + + // search for the desired attribute + AnnotationsReader result = null; + try { + for (; attrs.isValid(); attrs.advance()) { + if (runtimeInvisable){ + if (attrs.getName().equals(RuntimeInvisibleAnnotationsReader.attrName)) { + result = new RuntimeInvisibleAnnotationsReader(attrs); + break; + } + } else { + if (attrs.getName().equals(RuntimeVisibleAnnotationsReader.attrName)) { + result = new RuntimeVisibleAnnotationsReader(attrs); + break; + } + } + } + } catch (InvalidClassFileException e) { + Assertions.UNREACHABLE(); + } + return result; + } + + + private InnerClassesReader getInnerClassesReader() throws InvalidClassFileException { + ClassReader r = reader.get(); + ClassReader.AttrIterator attrs = new ClassReader.AttrIterator(); + r.initClassAttributeIterator(attrs); + + // search for the desired attribute + InnerClassesReader result = null; + try { + for (; attrs.isValid(); attrs.advance()) { + if (attrs.getName().equals("InnerClasses")) { + result = new InnerClassesReader(attrs); + break; + } + } + } catch (InvalidClassFileException e) { + Assertions.UNREACHABLE(); + } + return result; + } + + private RuntimeInvisibleAnnotationsReader getRuntimeInvisibleAnnotationsReader(int fieldIndex) throws InvalidClassFileException { + ClassReader.AttrIterator iter = new AttrIterator(); + reader.get().initFieldAttributeIterator(fieldIndex, iter); + + // search for the desired attribute + RuntimeInvisibleAnnotationsReader result = null; + try { + for (; iter.isValid(); iter.advance()) { + if (iter.getName().toString().equals("RuntimeInvisibleAnnotations")) { + result = new RuntimeInvisibleAnnotationsReader(iter); + break; + } + } + } catch (InvalidClassFileException e) { + Assertions.UNREACHABLE(); + } + return result; + } + + /** + * read the runtime-invisible annotations from the class file + */ + public Collection getRuntimeInvisibleAnnotations(int fieldIndex) throws InvalidClassFileException { + RuntimeInvisibleAnnotationsReader r = getRuntimeInvisibleAnnotationsReader(fieldIndex); + return Annotation.getAnnotationsFromReader(r, getClassLoader().getReference()); + } + + private SignatureReader getSignatureReader() throws InvalidClassFileException { + ClassReader r = reader.get(); + ClassReader.AttrIterator attrs = new ClassReader.AttrIterator(); + r.initClassAttributeIterator(attrs); + + // search for the desired attribute + SignatureReader result = null; + try { + for (; attrs.isValid(); attrs.advance()) { + if (attrs.getName().toString().equals("Signature")) { + result = new SignatureReader(attrs); + break; + } + } + } catch (InvalidClassFileException e) { + Assertions.UNREACHABLE(); + } + return result; + } + + public ClassSignature getClassSignature() throws InvalidClassFileException { + // TODO: cache this later? + SignatureReader r = getSignatureReader(); + if (r == null) { + return null; + } else { + return ClassSignature.make(r.getSignature()); + } + } + + public ModuleEntry getModuleEntry() { + return reader.getModuleEntry(); + } + + /** + * Does the class file indicate that this class is a member of some other class? + * + * @throws InvalidClassFileException + */ + public boolean isInnerClass() throws InvalidClassFileException { + InnerClassesReader r = getInnerClassesReader(); + if (r != null) { + for (String s : r.getInnerClasses()) { + if (s.equals(getName().toString().substring(1))) { + String outer = r.getOuterClass(s); + return outer != null; + } + } + } + return false; + } + + /** + * Does the class file indicate that this class is a static inner class? + * + * @throws InvalidClassFileException + */ + public boolean isStaticInnerClass() throws InvalidClassFileException { + InnerClassesReader r = getInnerClassesReader(); + if (r != null) { + for (String s : r.getInnerClasses()) { + if (s.equals(getName().toString().substring(1))) { + String outer = r.getOuterClass(s); + if (outer != null) { + int modifiers = r.getAccessFlags(s); + boolean result = ((modifiers & Constants.ACC_STATIC) != 0); + return result; + } + } + } + } + return false; + } + + /** + * If this is an inner class, return the outer class. Else return null. + * @throws InvalidClassFileException + */ + public TypeReference getOuterClass() throws InvalidClassFileException { + if (!isInnerClass()) { + return null; + } + InnerClassesReader r = getInnerClassesReader(); + for (String s : r.getInnerClasses()) { + if (s.equals(getName().toString().substring(1))) { + String outer = r.getOuterClass(s); + if (outer != null) { + return TypeReference.findOrCreate(getClassLoader().getReference(), "L" + outer); + } + } + } + return null; + } } \ No newline at end of file diff --git a/com.ibm.wala.core/src/com/ibm/wala/classLoader/ShrikeIRFactory.java b/com.ibm.wala.core/src/com/ibm/wala/classLoader/ShrikeIRFactory.java index 7cd119940..4b61fc23b 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/classLoader/ShrikeIRFactory.java +++ b/com.ibm.wala.core/src/com/ibm/wala/classLoader/ShrikeIRFactory.java @@ -1,121 +1,121 @@ -/******************************************************************************* - * 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.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.ShrikeIndirectionData; -import com.ibm.wala.ssa.SymbolTable; -import com.ibm.wala.ssa.analysis.DeadAssignmentElimination; -import com.ibm.wala.util.debug.Assertions; - -/** - * An {@link IRFactory} that for methods that originate from Shrike. - */ -public class ShrikeIRFactory implements IRFactory { - - public final static boolean buildLocalMap = true; - - public ControlFlowGraph makeCFG(final IBytecodeMethod method, Context C) { - return ShrikeCFG.make(method); - } - - public IR makeIR(final IBytecodeMethod method, Context C, final SSAOptions options) throws IllegalArgumentException { - - if (method == null) { - throw new IllegalArgumentException("null method"); - } - com.ibm.wala.shrikeBT.IInstruction[] shrikeInstructions = null; - try { - shrikeInstructions = method.getInstructions(); - } catch (InvalidClassFileException e) { - e.printStackTrace(); - Assertions.UNREACHABLE(); - } - final ShrikeCFG shrikeCFG = (ShrikeCFG) makeCFG(method, C); - - final SymbolTable symbolTable = new SymbolTable(method.getNumberOfParameters()); - final SSAInstruction[] newInstrs = new SSAInstruction[shrikeInstructions.length]; - - final SSACFG newCfg = new SSACFG(method, shrikeCFG, newInstrs); - - return new IR(method, newInstrs, symbolTable, newCfg, options) { - private final SSA2LocalMap localMap; - - private final ShrikeIndirectionData indirectionData; - - /** - * Remove any phis that are dead assignments. - * - * TODO: move this elsewhere? - */ - private void eliminateDeadPhis() { - DeadAssignmentElimination.perform(this); - } - - @Override - protected String instructionPosition(int instructionIndex) { - try { - int bcIndex = method.getBytecodeIndex(instructionIndex); - int lineNumber = method.getLineNumber(bcIndex); - - if (lineNumber == -1) { - return ""; - } else { - return "(line " + lineNumber + ")"; - } - } catch (InvalidClassFileException e) { - return ""; - } - } - - @Override - public SSA2LocalMap getLocalMap() { - return localMap; - } - - { - SSABuilder builder = SSABuilder.make(method, newCfg, shrikeCFG, newInstrs, symbolTable, buildLocalMap, options - .getPiNodePolicy()); - builder.build(); - if (buildLocalMap) - localMap = builder.getLocalMap(); - else - localMap = null; - - indirectionData = builder.getIndirectionData(); - - eliminateDeadPhis(); - - setupLocationMap(); - } - - @SuppressWarnings("unchecked") - @Override - protected ShrikeIndirectionData getIndirectionData() { - return indirectionData; - } - }; - } - - public boolean contextIsIrrelevant(IBytecodeMethod method) { - // this factory always returns the same IR for a method - return true; - } -} +/******************************************************************************* + * 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.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.ShrikeIndirectionData; +import com.ibm.wala.ssa.SymbolTable; +import com.ibm.wala.ssa.analysis.DeadAssignmentElimination; +import com.ibm.wala.util.debug.Assertions; + +/** + * An {@link IRFactory} that for methods that originate from Shrike. + */ +public class ShrikeIRFactory implements IRFactory { + + public final static boolean buildLocalMap = true; + + public ControlFlowGraph makeCFG(final IBytecodeMethod method, Context C) { + return ShrikeCFG.make(method); + } + + public IR makeIR(final IBytecodeMethod method, Context C, final SSAOptions options) throws IllegalArgumentException { + + if (method == null) { + throw new IllegalArgumentException("null method"); + } + com.ibm.wala.shrikeBT.IInstruction[] shrikeInstructions = null; + try { + shrikeInstructions = method.getInstructions(); + } catch (InvalidClassFileException e) { + e.printStackTrace(); + Assertions.UNREACHABLE(); + } + final ShrikeCFG shrikeCFG = (ShrikeCFG) makeCFG(method, C); + + final SymbolTable symbolTable = new SymbolTable(method.getNumberOfParameters()); + final SSAInstruction[] newInstrs = new SSAInstruction[shrikeInstructions.length]; + + final SSACFG newCfg = new SSACFG(method, shrikeCFG, newInstrs); + + return new IR(method, newInstrs, symbolTable, newCfg, options) { + private final SSA2LocalMap localMap; + + private final ShrikeIndirectionData indirectionData; + + /** + * Remove any phis that are dead assignments. + * + * TODO: move this elsewhere? + */ + private void eliminateDeadPhis() { + DeadAssignmentElimination.perform(this); + } + + @Override + protected String instructionPosition(int instructionIndex) { + try { + int bcIndex = method.getBytecodeIndex(instructionIndex); + int lineNumber = method.getLineNumber(bcIndex); + + if (lineNumber == -1) { + return ""; + } else { + return "(line " + lineNumber + ")"; + } + } catch (InvalidClassFileException e) { + return ""; + } + } + + @Override + public SSA2LocalMap getLocalMap() { + return localMap; + } + + { + SSABuilder builder = SSABuilder.make(method, newCfg, shrikeCFG, newInstrs, symbolTable, buildLocalMap, options + .getPiNodePolicy()); + builder.build(); + if (buildLocalMap) + localMap = builder.getLocalMap(); + else + localMap = null; + + indirectionData = builder.getIndirectionData(); + + eliminateDeadPhis(); + + setupLocationMap(); + } + + @SuppressWarnings("unchecked") + @Override + protected ShrikeIndirectionData getIndirectionData() { + return indirectionData; + } + }; + } + + public boolean contextIsIrrelevant(IBytecodeMethod method) { + // this factory always returns the same IR for a method + return true; + } +} diff --git a/com.ibm.wala.core/src/com/ibm/wala/classLoader/SourceDirectoryTreeModule.java b/com.ibm.wala.core/src/com/ibm/wala/classLoader/SourceDirectoryTreeModule.java index 44975144b..a0ceb9596 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/classLoader/SourceDirectoryTreeModule.java +++ b/com.ibm.wala.core/src/com/ibm/wala/classLoader/SourceDirectoryTreeModule.java @@ -1,59 +1,59 @@ -/******************************************************************************* - * 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; - -/** - * a module representing a directory tree of source files. - */ -public class SourceDirectoryTreeModule extends DirectoryTreeModule { - - /** - * file extension of source files in directory tree (defaults to "java" for Java source files) - */ - String fileExt = "java"; - - public SourceDirectoryTreeModule(File root) { - super(root); - } - - public SourceDirectoryTreeModule(File root, String fileExt) { - super(root); - if (fileExt != null) - this.fileExt = fileExt; - } - - @Override - protected boolean includeFile(File file) { - return file.getName().endsWith(fileExt); - } - - @Override - protected FileModule makeFile(File file) { - String rootPath = root.getAbsolutePath(); - if (!rootPath.endsWith(File.separator)) { - rootPath = rootPath + File.separator; - } - - String filePath = file.getAbsolutePath(); - - assert filePath.startsWith(rootPath); - - return new SourceFileModule(file, filePath.substring(rootPath.length())); - } - - @Override - public String toString() { - return "SourceDirectoryTreeModule:" + getPath(); - } - -} +/******************************************************************************* + * 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; + +/** + * a module representing a directory tree of source files. + */ +public class SourceDirectoryTreeModule extends DirectoryTreeModule { + + /** + * file extension of source files in directory tree (defaults to "java" for Java source files) + */ + String fileExt = "java"; + + public SourceDirectoryTreeModule(File root) { + super(root); + } + + public SourceDirectoryTreeModule(File root, String fileExt) { + super(root); + if (fileExt != null) + this.fileExt = fileExt; + } + + @Override + protected boolean includeFile(File file) { + return file.getName().endsWith(fileExt); + } + + @Override + protected FileModule makeFile(File file) { + String rootPath = root.getAbsolutePath(); + if (!rootPath.endsWith(File.separator)) { + rootPath = rootPath + File.separator; + } + + String filePath = file.getAbsolutePath(); + + assert filePath.startsWith(rootPath); + + return new SourceFileModule(file, filePath.substring(rootPath.length())); + } + + @Override + public String toString() { + return "SourceDirectoryTreeModule:" + getPath(); + } + +} diff --git a/com.ibm.wala.core/src/com/ibm/wala/classLoader/SourceFileModule.java b/com.ibm.wala.core/src/com/ibm/wala/classLoader/SourceFileModule.java index b84266a0d..7ea57b9c6 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/classLoader/SourceFileModule.java +++ b/com.ibm.wala.core/src/com/ibm/wala/classLoader/SourceFileModule.java @@ -1,78 +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 java.io.InputStreamReader; -import java.io.Reader; -import java.net.MalformedURLException; -import java.net.URL; - -import com.ibm.wala.util.io.FileSuffixes; - -/** - * A {@link Module} which is a wrapper around a .java file - */ -public class SourceFileModule extends FileModule implements Module, ModuleEntry, SourceModule { - - private final String fileName; - public SourceFileModule(File f, String fileName) { - super(f); - this.fileName = fileName; - } - - public SourceFileModule(File f, SourceFileModule clonedFrom) { - - super(f); - if (clonedFrom == null) { - throw new IllegalArgumentException("clonedFrom is null"); - } - this.fileName = clonedFrom.fileName; - } - - @Override - public String toString() { - return "SourceFileModule:" + getFile().toString(); - } - - /* - * @see com.ibm.wala.classLoader.ModuleEntry#isClassFile() - */ - public boolean isClassFile() { - return false; - } - - /* - * @see com.ibm.wala.classLoader.ModuleEntry#getClassName() - */ - public String getClassName() { - return FileSuffixes.stripSuffix(fileName).replace(File.separator.charAt(0), '/'); - } - - /* - * @see com.ibm.wala.classLoader.ModuleEntry#isSourceFile() - */ - public boolean isSourceFile() { - return true; - } - - public Reader getInputReader() { - return new InputStreamReader(getInputStream()); - } - - public URL getURL() { - try { - return getFile().toURI().toURL(); - } catch (MalformedURLException e) { - throw new Error("error making URL for " + getFile()); - } - } -} +/******************************************************************************* + * 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.InputStreamReader; +import java.io.Reader; +import java.net.MalformedURLException; +import java.net.URL; + +import com.ibm.wala.util.io.FileSuffixes; + +/** + * A {@link Module} which is a wrapper around a .java file + */ +public class SourceFileModule extends FileModule implements Module, ModuleEntry, SourceModule { + + private final String fileName; + public SourceFileModule(File f, String fileName) { + super(f); + this.fileName = fileName; + } + + public SourceFileModule(File f, SourceFileModule clonedFrom) { + + super(f); + if (clonedFrom == null) { + throw new IllegalArgumentException("clonedFrom is null"); + } + this.fileName = clonedFrom.fileName; + } + + @Override + public String toString() { + return "SourceFileModule:" + getFile().toString(); + } + + /* + * @see com.ibm.wala.classLoader.ModuleEntry#isClassFile() + */ + public boolean isClassFile() { + return false; + } + + /* + * @see com.ibm.wala.classLoader.ModuleEntry#getClassName() + */ + public String getClassName() { + return FileSuffixes.stripSuffix(fileName).replace(File.separator.charAt(0), '/'); + } + + /* + * @see com.ibm.wala.classLoader.ModuleEntry#isSourceFile() + */ + public boolean isSourceFile() { + return true; + } + + public Reader getInputReader() { + return new InputStreamReader(getInputStream()); + } + + public URL getURL() { + try { + return getFile().toURI().toURL(); + } catch (MalformedURLException e) { + throw new Error("error making URL for " + getFile()); + } + } +} diff --git a/com.ibm.wala.core/src/com/ibm/wala/classLoader/SourceURLModule.java b/com.ibm.wala.core/src/com/ibm/wala/classLoader/SourceURLModule.java index e603b6d59..e30faea0c 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/classLoader/SourceURLModule.java +++ b/com.ibm.wala.core/src/com/ibm/wala/classLoader/SourceURLModule.java @@ -1,35 +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; - -import java.io.InputStreamReader; -import java.io.Reader; -import java.net.URL; - -public class SourceURLModule extends AbstractURLModule implements SourceModule { - - public SourceURLModule(URL url) { - super(url); - } - - public boolean isClassFile() { - return false; - } - - public boolean isSourceFile() { - return true; - } - - public Reader getInputReader() { - return new InputStreamReader(getInputStream()); - } - -} +/******************************************************************************* + * 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.InputStreamReader; +import java.io.Reader; +import java.net.URL; + +public class SourceURLModule extends AbstractURLModule implements SourceModule { + + public SourceURLModule(URL url) { + super(url); + } + + public boolean isClassFile() { + return false; + } + + public boolean isSourceFile() { + return true; + } + + public Reader getInputReader() { + return new InputStreamReader(getInputStream()); + } + +} diff --git a/com.ibm.wala.core/src/com/ibm/wala/classLoader/SyntheticClass.java b/com.ibm.wala.core/src/com/ibm/wala/classLoader/SyntheticClass.java index fa81c54bf..b3d018818 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/classLoader/SyntheticClass.java +++ b/com.ibm.wala.core/src/com/ibm/wala/classLoader/SyntheticClass.java @@ -1,132 +1,132 @@ -/******************************************************************************* - * 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 com.ibm.wala.ipa.cha.IClassHierarchy; -import com.ibm.wala.types.ClassLoaderReference; -import com.ibm.wala.types.TypeName; -import com.ibm.wala.types.TypeReference; -import com.ibm.wala.util.strings.Atom; - -/** - * An {@link IClass} that exists nowhere in bytecode. - */ -public abstract class SyntheticClass implements IClass { - - private final TypeReference T; - - private final IClassHierarchy cha; - /** - * @param T type reference describing this class - */ - public SyntheticClass(TypeReference T, IClassHierarchy cha) { - super(); - this.T = T; - this.cha = cha; - } - - @Override - public int hashCode() { - final int prime = 31; - int result = 1; - result = prime * result + ((T == null) ? 0 : T.hashCode()); - result = prime * result + ((cha == null) ? 0 : cha.hashCode()); - return result; - } - - @Override - public boolean equals(Object obj) { - if (this == obj) - return true; - if (obj == null) - return false; - if (!(obj instanceof SyntheticClass)) - return false; - final SyntheticClass other = (SyntheticClass) obj; - if (T == null) { - if (other.T != null) - return false; - } else if (!T.equals(other.T)) - return false; - if (cha == null) { - if (other.cha != null) - return false; - } else if (!cha.equals(other.cha)) - return false; - return true; - } - - /** - * 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); - } - - /* - * @see com.ibm.wala.classLoader.IClass#isInterface() - */ - public boolean isInterface() { - return false; - } - - /* - * @see com.ibm.wala.classLoader.IClass#isAbstract() - */ - public boolean isAbstract() { - return false; - } - - /* - * @see com.ibm.wala.classLoader.IClass#getReference() - */ - public TypeReference getReference() { - return T; - } - - /* - * @see com.ibm.wala.classLoader.IClass#getSourceFileName() - */ - public String getSourceFileName() { - return null; - } - - public InputStream getSource() { - return null; - } - - /* - * @see com.ibm.wala.classLoader.IClass#isArrayClass() - */ - public boolean isArrayClass() { - return false; - } - - public IClassHierarchy getClassHierarchy() { - return cha; - } - - public TypeName getName() { - return getReference().getName(); - } - - /** - * we assume synthetic classes do not need to have multiple fields with the same name. - */ - public IField getField(Atom name, TypeName typeName) { - return getField(name); - } -} +/******************************************************************************* + * 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 com.ibm.wala.ipa.cha.IClassHierarchy; +import com.ibm.wala.types.ClassLoaderReference; +import com.ibm.wala.types.TypeName; +import com.ibm.wala.types.TypeReference; +import com.ibm.wala.util.strings.Atom; + +/** + * An {@link IClass} that exists nowhere in bytecode. + */ +public abstract class SyntheticClass implements IClass { + + private final TypeReference T; + + private final IClassHierarchy cha; + /** + * @param T type reference describing this class + */ + public SyntheticClass(TypeReference T, IClassHierarchy cha) { + super(); + this.T = T; + this.cha = cha; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((T == null) ? 0 : T.hashCode()); + result = prime * result + ((cha == null) ? 0 : cha.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (!(obj instanceof SyntheticClass)) + return false; + final SyntheticClass other = (SyntheticClass) obj; + if (T == null) { + if (other.T != null) + return false; + } else if (!T.equals(other.T)) + return false; + if (cha == null) { + if (other.cha != null) + return false; + } else if (!cha.equals(other.cha)) + return false; + return true; + } + + /** + * 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); + } + + /* + * @see com.ibm.wala.classLoader.IClass#isInterface() + */ + public boolean isInterface() { + return false; + } + + /* + * @see com.ibm.wala.classLoader.IClass#isAbstract() + */ + public boolean isAbstract() { + return false; + } + + /* + * @see com.ibm.wala.classLoader.IClass#getReference() + */ + public TypeReference getReference() { + return T; + } + + /* + * @see com.ibm.wala.classLoader.IClass#getSourceFileName() + */ + public String getSourceFileName() { + return null; + } + + public InputStream getSource() { + return null; + } + + /* + * @see com.ibm.wala.classLoader.IClass#isArrayClass() + */ + public boolean isArrayClass() { + return false; + } + + public IClassHierarchy getClassHierarchy() { + return cha; + } + + public TypeName getName() { + return getReference().getName(); + } + + /** + * we assume synthetic classes do not need to have multiple fields with the same name. + */ + public IField getField(Atom name, TypeName typeName) { + return getField(name); + } +} diff --git a/com.ibm.wala.core/src/com/ibm/wala/classLoader/SyntheticMethod.java b/com.ibm.wala.core/src/com/ibm/wala/classLoader/SyntheticMethod.java index ad3c7463b..d8dbce220 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/classLoader/SyntheticMethod.java +++ b/com.ibm.wala.core/src/com/ibm/wala/classLoader/SyntheticMethod.java @@ -1,367 +1,367 @@ -/******************************************************************************* - * 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.Context; -import com.ibm.wala.ipa.callgraph.impl.Everywhere; -import com.ibm.wala.ipa.cha.IClassHierarchy; -import com.ibm.wala.shrikeCT.InvalidClassFileException; -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.bytecode.BytecodeStream; -import com.ibm.wala.util.debug.UnimplementedError; -import com.ibm.wala.util.strings.Atom; - -/** - * An implementation of {@link IMethod}, usually for a synthesized method that is not read directly from any source {@link Module}. - */ -public class SyntheticMethod implements IMethod { - - public final static SSAInstruction[] NO_STATEMENTS = new SSAInstruction[0]; - - private final MethodReference method; - - protected final IMethod resolvedMethod; - - protected final IClass declaringClass; - - private final boolean isStatic; - - private final boolean isFactory; - - public SyntheticMethod(MethodReference method, IClass declaringClass, boolean isStatic, boolean isFactory) { - super(); - if (method == null) { - throw new IllegalArgumentException("null method"); - } - 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(); - if (method == null) { - throw new IllegalArgumentException("null method"); - } - 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#isBridge() - */ - public boolean isBridge() { - 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; - } - - /** - * Create an {@link InducedCFG} from an instruction array. - * - * NOTE: SIDE EFFECT!!! ... nulls out phi instructions in the instruction array! - */ - public InducedCFG makeControlFlowGraph(SSAInstruction[] instructions) { - return new InducedCFG(instructions, this, Everywhere.EVERYWHERE); - } - - public BytecodeStream getBytecodeStream() throws UnsupportedOperationException { - throw new UnsupportedOperationException(); - } - - /* - * TODO: why isn't this abstract? - * - * @see com.ibm.wala.classLoader.IMethod#getMaxLocals() - * - * @throws UnsupportedOperationException unconditionally - */ - public int getMaxLocals() throws UnsupportedOperationException { - throw new UnsupportedOperationException(); - } - - /* - * TODO: why isn't this abstract? - * - * @see com.ibm.wala.classLoader.IMethod#getMaxStackHeight() - */ - public int getMaxStackHeight() throws UnsupportedOperationException { - throw new UnsupportedOperationException(); - } - - public IClass getDeclaringClass() { - return declaringClass; - } - - @Override - public String toString() { - StringBuffer s = new StringBuffer("synthetic "); - if (isFactoryMethod()) { - s.append(" factory "); - } - s.append(method.toString()); - return s.toString(); - } - - @Override - public int hashCode() { - final int prime = 31; - int result = 1; - result = prime * result + ((declaringClass == null) ? 0 : declaringClass.hashCode()); - result = prime * result + ((method == null) ? 0 : method.hashCode()); - return result; - } - - @Override - public boolean equals(Object obj) { - if (this == obj) - return true; - if (obj == null) - return false; - if (getClass() != obj.getClass()) - return false; - final SyntheticMethod other = (SyntheticMethod) obj; - if (declaringClass == null) { - if (other.declaringClass != null) - return false; - } else if (!declaringClass.equals(other.declaringClass)) - return false; - if (method == null) { - if (other.method != null) - return false; - } else if (!method.equals(other.method)) - return false; - return true; - } - - public boolean hasExceptionHandler() { - return false; - } - - public boolean hasPoison() { - return false; - } - - public String getPoison() { - return null; - } - - public byte getPoisonLevel() { - return -1; - } - - /* - * TODO: why isn't this abstract? - * - * @param options options governing SSA construction - */ - @Deprecated - public SSAInstruction[] getStatements(SSAOptions options) { - return NO_STATEMENTS; - } - - /** - * Most subclasses should override this. - * - * @param context TODO - * @param options options governing IR conversion - */ - public IR makeIR(Context context, SSAOptions options) throws UnimplementedError { - throw new UnimplementedError("haven't implemented IR yet for class " + getClass()); - } - - /* - * @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; - } - - /* - * @see com.ibm.wala.classLoader.IMethod#getDeclaredExceptions() - */ - public TypeReference[] getDeclaredExceptions() throws InvalidClassFileException { - if (resolvedMethod == null) { - return null; - } else { - return resolvedMethod.getDeclaredExceptions(); - } - } - - public Atom getName() { - return method.getSelector().getName(); - } - - public Descriptor getDescriptor() { - return method.getSelector().getDescriptor(); - } - - /* - * @see com.ibm.wala.classLoader.IMethod#getLineNumber(int) - */ - public int getLineNumber(int bcIndex) { - return -1; - } - - public boolean isFactoryMethod() { - return isFactory; - } - - /* - * @see com.ibm.wala.classLoader.IMethod#getSignature() - */ - public String getSignature() { - return getReference().getSignature(); - } - - /* - * @see com.ibm.wala.classLoader.IMethod#getSelector() - */ - public Selector getSelector() { - return getReference().getSelector(); - } - - /* - * @see com.ibm.wala.classLoader.IMethod#getLocalVariableName(int, int) - */ - public String getLocalVariableName(int bcIndex, int localNumber) { - // no information is available - return null; - } - - /* - * @see com.ibm.wala.classLoader.IMethod#hasLocalVariableTable() - */ - public boolean hasLocalVariableTable() { - return false; - } - - public SSAInstruction[] getStatements() { - return getStatements(SSAOptions.defaultOptions()); - } - - /* - * @see com.ibm.wala.classLoader.IMethod#getReturnType() - */ - public TypeReference getReturnType() { - return getReference().getReturnType(); - } - - public IClassHierarchy getClassHierarchy() { - return getDeclaringClass().getClassHierarchy(); - } - -} +/******************************************************************************* + * 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.Context; +import com.ibm.wala.ipa.callgraph.impl.Everywhere; +import com.ibm.wala.ipa.cha.IClassHierarchy; +import com.ibm.wala.shrikeCT.InvalidClassFileException; +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.bytecode.BytecodeStream; +import com.ibm.wala.util.debug.UnimplementedError; +import com.ibm.wala.util.strings.Atom; + +/** + * An implementation of {@link IMethod}, usually for a synthesized method that is not read directly from any source {@link Module}. + */ +public class SyntheticMethod implements IMethod { + + public final static SSAInstruction[] NO_STATEMENTS = new SSAInstruction[0]; + + private final MethodReference method; + + protected final IMethod resolvedMethod; + + protected final IClass declaringClass; + + private final boolean isStatic; + + private final boolean isFactory; + + public SyntheticMethod(MethodReference method, IClass declaringClass, boolean isStatic, boolean isFactory) { + super(); + if (method == null) { + throw new IllegalArgumentException("null method"); + } + 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(); + if (method == null) { + throw new IllegalArgumentException("null method"); + } + 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#isBridge() + */ + public boolean isBridge() { + 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; + } + + /** + * Create an {@link InducedCFG} from an instruction array. + * + * NOTE: SIDE EFFECT!!! ... nulls out phi instructions in the instruction array! + */ + public InducedCFG makeControlFlowGraph(SSAInstruction[] instructions) { + return new InducedCFG(instructions, this, Everywhere.EVERYWHERE); + } + + public BytecodeStream getBytecodeStream() throws UnsupportedOperationException { + throw new UnsupportedOperationException(); + } + + /* + * TODO: why isn't this abstract? + * + * @see com.ibm.wala.classLoader.IMethod#getMaxLocals() + * + * @throws UnsupportedOperationException unconditionally + */ + public int getMaxLocals() throws UnsupportedOperationException { + throw new UnsupportedOperationException(); + } + + /* + * TODO: why isn't this abstract? + * + * @see com.ibm.wala.classLoader.IMethod#getMaxStackHeight() + */ + public int getMaxStackHeight() throws UnsupportedOperationException { + throw new UnsupportedOperationException(); + } + + public IClass getDeclaringClass() { + return declaringClass; + } + + @Override + public String toString() { + StringBuffer s = new StringBuffer("synthetic "); + if (isFactoryMethod()) { + s.append(" factory "); + } + s.append(method.toString()); + return s.toString(); + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((declaringClass == null) ? 0 : declaringClass.hashCode()); + result = prime * result + ((method == null) ? 0 : method.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + final SyntheticMethod other = (SyntheticMethod) obj; + if (declaringClass == null) { + if (other.declaringClass != null) + return false; + } else if (!declaringClass.equals(other.declaringClass)) + return false; + if (method == null) { + if (other.method != null) + return false; + } else if (!method.equals(other.method)) + return false; + return true; + } + + public boolean hasExceptionHandler() { + return false; + } + + public boolean hasPoison() { + return false; + } + + public String getPoison() { + return null; + } + + public byte getPoisonLevel() { + return -1; + } + + /* + * TODO: why isn't this abstract? + * + * @param options options governing SSA construction + */ + @Deprecated + public SSAInstruction[] getStatements(SSAOptions options) { + return NO_STATEMENTS; + } + + /** + * Most subclasses should override this. + * + * @param context TODO + * @param options options governing IR conversion + */ + public IR makeIR(Context context, SSAOptions options) throws UnimplementedError { + throw new UnimplementedError("haven't implemented IR yet for class " + getClass()); + } + + /* + * @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; + } + + /* + * @see com.ibm.wala.classLoader.IMethod#getDeclaredExceptions() + */ + public TypeReference[] getDeclaredExceptions() throws InvalidClassFileException { + if (resolvedMethod == null) { + return null; + } else { + return resolvedMethod.getDeclaredExceptions(); + } + } + + public Atom getName() { + return method.getSelector().getName(); + } + + public Descriptor getDescriptor() { + return method.getSelector().getDescriptor(); + } + + /* + * @see com.ibm.wala.classLoader.IMethod#getLineNumber(int) + */ + public int getLineNumber(int bcIndex) { + return -1; + } + + public boolean isFactoryMethod() { + return isFactory; + } + + /* + * @see com.ibm.wala.classLoader.IMethod#getSignature() + */ + public String getSignature() { + return getReference().getSignature(); + } + + /* + * @see com.ibm.wala.classLoader.IMethod#getSelector() + */ + public Selector getSelector() { + return getReference().getSelector(); + } + + /* + * @see com.ibm.wala.classLoader.IMethod#getLocalVariableName(int, int) + */ + public String getLocalVariableName(int bcIndex, int localNumber) { + // no information is available + return null; + } + + /* + * @see com.ibm.wala.classLoader.IMethod#hasLocalVariableTable() + */ + public boolean hasLocalVariableTable() { + return false; + } + + public SSAInstruction[] getStatements() { + return getStatements(SSAOptions.defaultOptions()); + } + + /* + * @see com.ibm.wala.classLoader.IMethod#getReturnType() + */ + public TypeReference getReturnType() { + return getReference().getReturnType(); + } + + public IClassHierarchy getClassHierarchy() { + return getDeclaringClass().getClassHierarchy(); + } + +} diff --git a/com.ibm.wala.core/src/com/ibm/wala/client/AbstractAnalysisEngine.java b/com.ibm.wala.core/src/com/ibm/wala/client/AbstractAnalysisEngine.java index 806380ccc..d4d848d8d 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/client/AbstractAnalysisEngine.java +++ b/com.ibm.wala.core/src/com/ibm/wala/client/AbstractAnalysisEngine.java @@ -1,317 +1,317 @@ -/******************************************************************************* - * 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 java.io.IOException; -import java.util.Collection; -import java.util.Iterator; -import java.util.jar.JarFile; - -import com.ibm.wala.analysis.pointers.BasicHeapGraph; -import com.ibm.wala.analysis.pointers.HeapGraph; -import com.ibm.wala.classLoader.ClassLoaderFactory; -import com.ibm.wala.classLoader.ClassLoaderFactoryImpl; -import com.ibm.wala.classLoader.JarFileModule; -import com.ibm.wala.classLoader.Module; -import com.ibm.wala.ipa.callgraph.AnalysisCache; -import com.ibm.wala.ipa.callgraph.AnalysisOptions; -import com.ibm.wala.ipa.callgraph.AnalysisScope; -import com.ibm.wala.ipa.callgraph.CallGraph; -import com.ibm.wala.ipa.callgraph.CallGraphBuilder; -import com.ibm.wala.ipa.callgraph.Entrypoint; -import com.ibm.wala.ipa.callgraph.impl.SetOfClasses; -import com.ibm.wala.ipa.callgraph.impl.Util; -import com.ibm.wala.ipa.callgraph.propagation.PointerAnalysis; -import com.ibm.wala.ipa.cha.ClassHierarchy; -import com.ibm.wala.ipa.cha.ClassHierarchyException; -import com.ibm.wala.ipa.cha.IClassHierarchy; -import com.ibm.wala.ssa.DefaultIRFactory; -import com.ibm.wala.types.ClassLoaderReference; -import com.ibm.wala.util.CancelException; -import com.ibm.wala.util.MonitorUtil.IProgressMonitor; -import com.ibm.wala.util.config.AnalysisScopeReader; -import com.ibm.wala.util.debug.Assertions; -import com.ibm.wala.util.io.FileProvider; - -/** - * Abstract base class for analysis engine implementations - * - * Some clients choose to build on this, but many don't. I usually don't in new code; I usually don't find the re-use enabled by - * this class compelling. I would probably nuke this except for some legacy code that uses it. - */ -public abstract class AbstractAnalysisEngine implements AnalysisEngine { - - public interface EntrypointBuilder { - Iterable createEntrypoints(AnalysisScope scope, IClassHierarchy cha); - } - - public final static String SYNTHETIC_J2SE_MODEL = "SyntheticJ2SEModel.txt"; - - /** - * DEBUG_LEVEL: - *
          - *
        • 0 No output - *
        • 1 Print some simple stats and warning information - *
        • 2 Detailed debugging - *
        - */ - protected static final int DEBUG_LEVEL = 1; - - /** - * Name of the file which holds the class hierarchy exclusions directives for this analysis. - */ - private String exclusionsFile = "J2SEClassHierarchyExclusions.txt"; - - /** - * The modules to analyze - */ - protected Collection moduleFiles; - - /** - * A representation of the analysis scope - */ - protected AnalysisScope scope; - - /** - * A representation of the analysis options - */ - private AnalysisOptions options; - - /** - * A cache of IRs and stuff - */ - private AnalysisCache cache = makeDefaultCache(); - - /** - * The standard J2SE libraries to analyze - */ - protected Module[] j2seLibs; - - /** - * Whether to perform closed-world analysis of an application - */ - private boolean closedWorld = false; - - /** - * Governing class hierarchy - */ - private IClassHierarchy cha; - - /** - * Governing call graph - */ - protected CallGraph cg; - - /** - * Results of pointer analysis - */ - protected PointerAnalysis pointerAnalysis; - - /** - * Graph view of flow of pointers between heap abstractions - */ - private HeapGraph heapGraph; - - private EntrypointBuilder entrypointBuilder = new EntrypointBuilder() { - public Iterable createEntrypoints(AnalysisScope scope, IClassHierarchy cha) { - return makeDefaultEntrypoints(scope, cha); - } - }; - - protected abstract CallGraphBuilder getCallGraphBuilder(IClassHierarchy cha, AnalysisOptions options, AnalysisCache cache); - - protected CallGraphBuilder buildCallGraph(IClassHierarchy cha, AnalysisOptions options, boolean savePointerAnalysis, - IProgressMonitor monitor) throws IllegalArgumentException, CancelException { - CallGraphBuilder builder = getCallGraphBuilder(cha, options, cache); - - cg = builder.makeCallGraph(options, monitor); - - if (savePointerAnalysis) { - pointerAnalysis = builder.getPointerAnalysis(); - } - - return builder; - } - - public void setModuleFiles(Collection moduleFiles) { - this.moduleFiles = moduleFiles; - } - - /** - * Set up the AnalysisScope object - * - * @throws IOException - */ - public void buildAnalysisScope() throws IOException { - if (j2seLibs == null) { - Assertions.UNREACHABLE("no j2selibs specified. You probably did not call AppAnalysisEngine.setJ2SELibrary."); - } - - scope = AnalysisScopeReader.readJavaScope(SYNTHETIC_J2SE_MODEL, (new FileProvider()).getFile(getExclusionsFile()), getClass() - .getClassLoader()); - - // add standard libraries - for (int i = 0; i < j2seLibs.length; i++) { - scope.addToScope(scope.getPrimordialLoader(), j2seLibs[i]); - } - - // add user stuff - addApplicationModulesToScope(); - } - - - /** - * @return a IClassHierarchy object for this analysis scope - */ - public IClassHierarchy buildClassHierarchy() { - IClassHierarchy cha = null; - ClassLoaderFactory factory = makeClassLoaderFactory(getScope().getExclusions()); - try { - cha = ClassHierarchy.make(getScope(), factory); - } catch (ClassHierarchyException e) { - System.err.println("Class Hierarchy construction failed"); - System.err.println(e.toString()); - e.printStackTrace(); - } - return cha; - } - - protected ClassLoaderFactory makeClassLoaderFactory(SetOfClasses exclusions) { - return new ClassLoaderFactoryImpl(exclusions); - } - - public IClassHierarchy getClassHierarchy() { - return cha; - } - - protected void setClassHierarchy(IClassHierarchy cha) { - this.cha = cha; - } - - /** - * @return Returns the call graph - */ - protected CallGraph getCallGraph() { - return cg; - } - - /** - * Add the application modules to the analysis scope. - */ - protected void addApplicationModulesToScope() { - ClassLoaderReference app = scope.getApplicationLoader(); - for (Iterator it = moduleFiles.iterator(); it.hasNext();) { - Object o = it.next(); - if (!(o instanceof Module)) { - Assertions.UNREACHABLE("Unexpected type: " + o.getClass()); - } - Module M = (Module) o; - scope.addToScope(app, M); - } - } - - public void setJ2SELibraries(JarFile[] libs) { - if (libs == null) { - throw new IllegalArgumentException("libs is null"); - } - this.j2seLibs = new Module[libs.length]; - for (int i = 0; i < libs.length; i++) { - j2seLibs[i] = new JarFileModule(libs[i]); - } - } - - public void setJ2SELibraries(Module[] libs) { - if (libs == null) { - throw new IllegalArgumentException("libs is null"); - } - this.j2seLibs = new Module[libs.length]; - for (int i = 0; i < libs.length; i++) { - j2seLibs[i] = libs[i]; - } - } - - public void setClosedWorld(boolean b) { - this.closedWorld = b; - } - - public boolean isClosedWorld() { - return closedWorld; - } - - protected AnalysisScope getScope() { - return scope; - } - - public PointerAnalysis getPointerAnalysis() { - return pointerAnalysis; - } - - public HeapGraph getHeapGraph() { - if (heapGraph == null) { - heapGraph = new BasicHeapGraph(getPointerAnalysis(), cg); - } - return heapGraph; - } - - public String getExclusionsFile() { - return exclusionsFile; - } - - public void setExclusionsFile(String exclusionsFile) { - this.exclusionsFile = exclusionsFile; - } - - public AnalysisOptions getDefaultOptions(Iterable entrypoints) { - return new AnalysisOptions(getScope(), entrypoints); - } - - public AnalysisCache makeDefaultCache() { - return new AnalysisCache(new DefaultIRFactory()); - } - - protected Iterable makeDefaultEntrypoints(AnalysisScope scope, IClassHierarchy cha) { - return Util.makeMainEntrypoints(scope, cha); - } - - public void setEntrypointBuilder(EntrypointBuilder builder) { - entrypointBuilder = builder; - } - - /** - * Builds the call graph for the analysis scope in effect, using all of the given entry points. - * - * @throws CancelException - * @throws IllegalArgumentException - * @throws IOException - */ - public CallGraphBuilder defaultCallGraphBuilder() throws IllegalArgumentException, CancelException, IOException { - buildAnalysisScope(); - IClassHierarchy cha = buildClassHierarchy(); - setClassHierarchy(cha); - Iterable eps = entrypointBuilder.createEntrypoints(scope, cha); - options = getDefaultOptions(eps); - cache = makeDefaultCache(); - return buildCallGraph(cha, options, true, null); - } - - public CallGraph buildDefaultCallGraph() throws IllegalArgumentException, CancelException, IOException { - return defaultCallGraphBuilder().makeCallGraph(options, null); - } - - public AnalysisCache getCache() { - return cache; - } - - public AnalysisOptions getOptions() { - return options; - } - -} +/******************************************************************************* + * 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 java.io.IOException; +import java.util.Collection; +import java.util.Iterator; +import java.util.jar.JarFile; + +import com.ibm.wala.analysis.pointers.BasicHeapGraph; +import com.ibm.wala.analysis.pointers.HeapGraph; +import com.ibm.wala.classLoader.ClassLoaderFactory; +import com.ibm.wala.classLoader.ClassLoaderFactoryImpl; +import com.ibm.wala.classLoader.JarFileModule; +import com.ibm.wala.classLoader.Module; +import com.ibm.wala.ipa.callgraph.AnalysisCache; +import com.ibm.wala.ipa.callgraph.AnalysisOptions; +import com.ibm.wala.ipa.callgraph.AnalysisScope; +import com.ibm.wala.ipa.callgraph.CallGraph; +import com.ibm.wala.ipa.callgraph.CallGraphBuilder; +import com.ibm.wala.ipa.callgraph.Entrypoint; +import com.ibm.wala.ipa.callgraph.impl.SetOfClasses; +import com.ibm.wala.ipa.callgraph.impl.Util; +import com.ibm.wala.ipa.callgraph.propagation.PointerAnalysis; +import com.ibm.wala.ipa.cha.ClassHierarchy; +import com.ibm.wala.ipa.cha.ClassHierarchyException; +import com.ibm.wala.ipa.cha.IClassHierarchy; +import com.ibm.wala.ssa.DefaultIRFactory; +import com.ibm.wala.types.ClassLoaderReference; +import com.ibm.wala.util.CancelException; +import com.ibm.wala.util.MonitorUtil.IProgressMonitor; +import com.ibm.wala.util.config.AnalysisScopeReader; +import com.ibm.wala.util.debug.Assertions; +import com.ibm.wala.util.io.FileProvider; + +/** + * Abstract base class for analysis engine implementations + * + * Some clients choose to build on this, but many don't. I usually don't in new code; I usually don't find the re-use enabled by + * this class compelling. I would probably nuke this except for some legacy code that uses it. + */ +public abstract class AbstractAnalysisEngine implements AnalysisEngine { + + public interface EntrypointBuilder { + Iterable createEntrypoints(AnalysisScope scope, IClassHierarchy cha); + } + + public final static String SYNTHETIC_J2SE_MODEL = "SyntheticJ2SEModel.txt"; + + /** + * DEBUG_LEVEL: + *
          + *
        • 0 No output + *
        • 1 Print some simple stats and warning information + *
        • 2 Detailed debugging + *
        + */ + protected static final int DEBUG_LEVEL = 1; + + /** + * Name of the file which holds the class hierarchy exclusions directives for this analysis. + */ + private String exclusionsFile = "J2SEClassHierarchyExclusions.txt"; + + /** + * The modules to analyze + */ + protected Collection moduleFiles; + + /** + * A representation of the analysis scope + */ + protected AnalysisScope scope; + + /** + * A representation of the analysis options + */ + private AnalysisOptions options; + + /** + * A cache of IRs and stuff + */ + private AnalysisCache cache = makeDefaultCache(); + + /** + * The standard J2SE libraries to analyze + */ + protected Module[] j2seLibs; + + /** + * Whether to perform closed-world analysis of an application + */ + private boolean closedWorld = false; + + /** + * Governing class hierarchy + */ + private IClassHierarchy cha; + + /** + * Governing call graph + */ + protected CallGraph cg; + + /** + * Results of pointer analysis + */ + protected PointerAnalysis pointerAnalysis; + + /** + * Graph view of flow of pointers between heap abstractions + */ + private HeapGraph heapGraph; + + private EntrypointBuilder entrypointBuilder = new EntrypointBuilder() { + public Iterable createEntrypoints(AnalysisScope scope, IClassHierarchy cha) { + return makeDefaultEntrypoints(scope, cha); + } + }; + + protected abstract CallGraphBuilder getCallGraphBuilder(IClassHierarchy cha, AnalysisOptions options, AnalysisCache cache); + + protected CallGraphBuilder buildCallGraph(IClassHierarchy cha, AnalysisOptions options, boolean savePointerAnalysis, + IProgressMonitor monitor) throws IllegalArgumentException, CancelException { + CallGraphBuilder builder = getCallGraphBuilder(cha, options, cache); + + cg = builder.makeCallGraph(options, monitor); + + if (savePointerAnalysis) { + pointerAnalysis = builder.getPointerAnalysis(); + } + + return builder; + } + + public void setModuleFiles(Collection moduleFiles) { + this.moduleFiles = moduleFiles; + } + + /** + * Set up the AnalysisScope object + * + * @throws IOException + */ + public void buildAnalysisScope() throws IOException { + if (j2seLibs == null) { + Assertions.UNREACHABLE("no j2selibs specified. You probably did not call AppAnalysisEngine.setJ2SELibrary."); + } + + scope = AnalysisScopeReader.readJavaScope(SYNTHETIC_J2SE_MODEL, (new FileProvider()).getFile(getExclusionsFile()), getClass() + .getClassLoader()); + + // add standard libraries + for (int i = 0; i < j2seLibs.length; i++) { + scope.addToScope(scope.getPrimordialLoader(), j2seLibs[i]); + } + + // add user stuff + addApplicationModulesToScope(); + } + + + /** + * @return a IClassHierarchy object for this analysis scope + */ + public IClassHierarchy buildClassHierarchy() { + IClassHierarchy cha = null; + ClassLoaderFactory factory = makeClassLoaderFactory(getScope().getExclusions()); + try { + cha = ClassHierarchy.make(getScope(), factory); + } catch (ClassHierarchyException e) { + System.err.println("Class Hierarchy construction failed"); + System.err.println(e.toString()); + e.printStackTrace(); + } + return cha; + } + + protected ClassLoaderFactory makeClassLoaderFactory(SetOfClasses exclusions) { + return new ClassLoaderFactoryImpl(exclusions); + } + + public IClassHierarchy getClassHierarchy() { + return cha; + } + + protected void setClassHierarchy(IClassHierarchy cha) { + this.cha = cha; + } + + /** + * @return Returns the call graph + */ + protected CallGraph getCallGraph() { + return cg; + } + + /** + * Add the application modules to the analysis scope. + */ + protected void addApplicationModulesToScope() { + ClassLoaderReference app = scope.getApplicationLoader(); + for (Iterator it = moduleFiles.iterator(); it.hasNext();) { + Object o = it.next(); + if (!(o instanceof Module)) { + Assertions.UNREACHABLE("Unexpected type: " + o.getClass()); + } + Module M = (Module) o; + scope.addToScope(app, M); + } + } + + public void setJ2SELibraries(JarFile[] libs) { + if (libs == null) { + throw new IllegalArgumentException("libs is null"); + } + this.j2seLibs = new Module[libs.length]; + for (int i = 0; i < libs.length; i++) { + j2seLibs[i] = new JarFileModule(libs[i]); + } + } + + public void setJ2SELibraries(Module[] libs) { + if (libs == null) { + throw new IllegalArgumentException("libs is null"); + } + this.j2seLibs = new Module[libs.length]; + for (int i = 0; i < libs.length; i++) { + j2seLibs[i] = libs[i]; + } + } + + public void setClosedWorld(boolean b) { + this.closedWorld = b; + } + + public boolean isClosedWorld() { + return closedWorld; + } + + protected AnalysisScope getScope() { + return scope; + } + + public PointerAnalysis getPointerAnalysis() { + return pointerAnalysis; + } + + public HeapGraph getHeapGraph() { + if (heapGraph == null) { + heapGraph = new BasicHeapGraph(getPointerAnalysis(), cg); + } + return heapGraph; + } + + public String getExclusionsFile() { + return exclusionsFile; + } + + public void setExclusionsFile(String exclusionsFile) { + this.exclusionsFile = exclusionsFile; + } + + public AnalysisOptions getDefaultOptions(Iterable entrypoints) { + return new AnalysisOptions(getScope(), entrypoints); + } + + public AnalysisCache makeDefaultCache() { + return new AnalysisCache(new DefaultIRFactory()); + } + + protected Iterable makeDefaultEntrypoints(AnalysisScope scope, IClassHierarchy cha) { + return Util.makeMainEntrypoints(scope, cha); + } + + public void setEntrypointBuilder(EntrypointBuilder builder) { + entrypointBuilder = builder; + } + + /** + * Builds the call graph for the analysis scope in effect, using all of the given entry points. + * + * @throws CancelException + * @throws IllegalArgumentException + * @throws IOException + */ + public CallGraphBuilder defaultCallGraphBuilder() throws IllegalArgumentException, CancelException, IOException { + buildAnalysisScope(); + IClassHierarchy cha = buildClassHierarchy(); + setClassHierarchy(cha); + Iterable eps = entrypointBuilder.createEntrypoints(scope, cha); + options = getDefaultOptions(eps); + cache = makeDefaultCache(); + return buildCallGraph(cha, options, true, null); + } + + public CallGraph buildDefaultCallGraph() throws IllegalArgumentException, CancelException, IOException { + return defaultCallGraphBuilder().makeCallGraph(options, null); + } + + public AnalysisCache getCache() { + return cache; + } + + public AnalysisOptions getOptions() { + return options; + } + +} diff --git a/com.ibm.wala.core/src/com/ibm/wala/client/AbstractEngineStopwatch.java b/com.ibm.wala.core/src/com/ibm/wala/client/AbstractEngineStopwatch.java index 2997818e4..b245ed7e7 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/client/AbstractEngineStopwatch.java +++ b/com.ibm.wala.core/src/com/ibm/wala/client/AbstractEngineStopwatch.java @@ -1,68 +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.client; - -import com.ibm.wala.util.perf.StopwatchGC; - -/** - * An object to track performance of an analysis engine - */ -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 StopwatchGC[] stopwatch; - - protected AbstractEngineStopwatch() { - stopwatch = new StopwatchGC[getNumberOfCategories()]; - for (int i = 0; i < getNumberOfCategories(); i++) { - stopwatch[i] = new StopwatchGC(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 StopwatchGC getTimer(byte category) { - return stopwatch[category]; - } - -} +/******************************************************************************* + * 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.perf.StopwatchGC; + +/** + * An object to track performance of an analysis engine + */ +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 StopwatchGC[] stopwatch; + + protected AbstractEngineStopwatch() { + stopwatch = new StopwatchGC[getNumberOfCategories()]; + for (int i = 0; i < getNumberOfCategories(); i++) { + stopwatch[i] = new StopwatchGC(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 StopwatchGC getTimer(byte category) { + return stopwatch[category]; + } + +} diff --git a/com.ibm.wala.core/src/com/ibm/wala/client/AnalysisEngine.java b/com.ibm.wala.core/src/com/ibm/wala/client/AnalysisEngine.java index fa0518a07..cbf965dea 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/client/AnalysisEngine.java +++ b/com.ibm.wala.core/src/com/ibm/wala/client/AnalysisEngine.java @@ -1,63 +1,63 @@ -/******************************************************************************* - * 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 java.util.Collection; -import java.util.jar.JarFile; - -import com.ibm.wala.classLoader.Module; -import com.ibm.wala.ipa.callgraph.AnalysisOptions; -import com.ibm.wala.ipa.callgraph.Entrypoint; - -public interface AnalysisEngine { - - /** - * Specify the list of modules that should be analyzed. If an EARFile is included in the list, all of its contained modules should - * be examined. Multiple ear files can be specified for cross-app invocations, which will become increasingly common in the 5.1 - * release. - * - * @param moduleFiles A non-null Collection of module files: (EARFile, WARFile, ApplicationClientFile, EJBJarFile). - */ - void setModuleFiles(Collection moduleFiles); - - /** - * Specify the jar files that represent the standard J2SE libraries - * - * @param libs an array of jar files; usually rt.jar for vanilla JDK core.jar, server.jar, and xml.jar for some WAS runtimes - */ - void setJ2SELibraries(JarFile[] libs); - - /** - * Specify the mdoules that represent the standard J2SE libraries - * - * @param libs an array of Modules; usually rt.jar for vanilla JDK core.jar, server.jar, and xml.jar for some WAS runtimes - */ - void setJ2SELibraries(Module[] libs); - - /** - * Specify whether the engine should or should not employ "closed-world" analysis. - * - * In a closed-world analysis, the engine considers only application client main methods and servlet entrypoints to the - * application. - * - * In an open-world analysis, the engine additionally considers all EJB local and remote interface methods as entrypoints. - * - * By default, this property is false; the default analysis is open-world - * - * @param b whether to use closed-world analysis - */ - void setClosedWorld(boolean b); - - /** - * Get the default analysis options appropriate for this engine - */ - AnalysisOptions getDefaultOptions(Iterable entrypoints); -} +/******************************************************************************* + * 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 java.util.Collection; +import java.util.jar.JarFile; + +import com.ibm.wala.classLoader.Module; +import com.ibm.wala.ipa.callgraph.AnalysisOptions; +import com.ibm.wala.ipa.callgraph.Entrypoint; + +public interface AnalysisEngine { + + /** + * Specify the list of modules that should be analyzed. If an EARFile is included in the list, all of its contained modules should + * be examined. Multiple ear files can be specified for cross-app invocations, which will become increasingly common in the 5.1 + * release. + * + * @param moduleFiles A non-null Collection of module files: (EARFile, WARFile, ApplicationClientFile, EJBJarFile). + */ + void setModuleFiles(Collection moduleFiles); + + /** + * Specify the jar files that represent the standard J2SE libraries + * + * @param libs an array of jar files; usually rt.jar for vanilla JDK core.jar, server.jar, and xml.jar for some WAS runtimes + */ + void setJ2SELibraries(JarFile[] libs); + + /** + * Specify the mdoules that represent the standard J2SE libraries + * + * @param libs an array of Modules; usually rt.jar for vanilla JDK core.jar, server.jar, and xml.jar for some WAS runtimes + */ + void setJ2SELibraries(Module[] libs); + + /** + * Specify whether the engine should or should not employ "closed-world" analysis. + * + * In a closed-world analysis, the engine considers only application client main methods and servlet entrypoints to the + * application. + * + * In an open-world analysis, the engine additionally considers all EJB local and remote interface methods as entrypoints. + * + * By default, this property is false; the default analysis is open-world + * + * @param b whether to use closed-world analysis + */ + void setClosedWorld(boolean b); + + /** + * Get the default analysis options appropriate for this engine + */ + AnalysisOptions getDefaultOptions(Iterable entrypoints); +} diff --git a/com.ibm.wala.core/src/com/ibm/wala/client/EngineStopwatch.java b/com.ibm.wala.core/src/com/ibm/wala/client/EngineStopwatch.java index 5ec1e8d63..9223b0913 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/client/EngineStopwatch.java +++ b/com.ibm.wala.core/src/com/ibm/wala/client/EngineStopwatch.java @@ -1,40 +1,40 @@ -/******************************************************************************* - * Copyright (c) 2002 - 2006 IBM Corporation. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * IBM Corporation - initial API and implementation - *******************************************************************************/ -package com.ibm.wala.client; - -import com.ibm.wala.util.perf.StopwatchGC; - - -/** - * An object to track performance of analysis engine - */ -public interface EngineStopwatch { - - /** - * @return a String representation of the information in this object - */ - public String report(); - - /** - * start timing for some category - */ - public void start(byte category); - - /** - * stop timing for some category - */ - public void stop(byte category); - - /** - * Returns access to class encapsulating time events results, related to the given category. - */ - public StopwatchGC getTimer(byte category); -} +/******************************************************************************* + * 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.perf.StopwatchGC; + + +/** + * An object to track performance of analysis engine + */ +public interface EngineStopwatch { + + /** + * @return a String representation of the information in this object + */ + public String report(); + + /** + * start timing for some category + */ + public void start(byte category); + + /** + * stop timing for some category + */ + public void stop(byte category); + + /** + * Returns access to class encapsulating time events results, related to the given category. + */ + public StopwatchGC getTimer(byte category); +} diff --git a/com.ibm.wala.core/src/com/ibm/wala/dataflow/IFDS/BackwardsSupergraph.java b/com.ibm.wala.core/src/com/ibm/wala/dataflow/IFDS/BackwardsSupergraph.java index a8f4dd8e3..010774a66 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/dataflow/IFDS/BackwardsSupergraph.java +++ b/com.ibm.wala.core/src/com/ibm/wala/dataflow/IFDS/BackwardsSupergraph.java @@ -1,350 +1,350 @@ -/******************************************************************************* - * 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.dataflow.IFDS; - -import java.util.Iterator; - -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.debug.Assertions; -import com.ibm.wala.util.debug.UnimplementedError; -import com.ibm.wala.util.graph.Graph; -import com.ibm.wala.util.intset.IntSet; - -/** - * A "reversed" supergraph for backwards analysis. - * - * In this view, a return is treated like a call, and vice-versa. All normal edges are reversed. - */ -public class BackwardsSupergraph implements ISupergraph { - - /** - * DEBUG_LEVEL: - *
          - *
        • 0 No output - *
        • 1 Print some simple stats and warning information - *
        • 2 Detailed debugging - *
        - */ - static final int DEBUG_LEVEL = 0; - - private final ISupergraph delegate; - - private final ExitFilter exitFilter = new ExitFilter(); - - /** - * @param forwardGraph the graph to ``reverse'' - */ - protected BackwardsSupergraph(ISupergraph forwardGraph) { - if (forwardGraph == null) { - throw new IllegalArgumentException("null forwardGraph"); - } - this.delegate = forwardGraph; - } - - public static BackwardsSupergraph make(ISupergraph forwardGraph) { - return new BackwardsSupergraph(forwardGraph); - } - - /** - * TODO: for now, this is not inverted. - * - * @see com.ibm.wala.dataflow.IFDS.ISupergraph#getProcedureGraph() - */ - public Graph getProcedureGraph() { - return delegate.getProcedureGraph(); - } - - /* - * @see com.ibm.wala.dataflow.IFDS.ISupergraph#isCall(java.lang.Object) - */ - public boolean isCall(T n) { - return delegate.isReturn(n); - } - - /** - * a filter that accepts only exit nodes from the original graph. - */ - private class ExitFilter implements Filter { - /* - * @see com.ibm.wala.util.Filter#accepts(java.lang.Object) - */ - @SuppressWarnings("unchecked") - public boolean accepts(Object o) { - return delegate.isExit((T) o); - } - } - - /** - * get the "called" (sic) nodes for a return site; i.e., the exit nodes that flow directly to this return site. - * - * @see com.ibm.wala.dataflow.IFDS.ISupergraph#getCalledNodes(java.lang.Object) - */ - public Iterator getCalledNodes(T ret) { - if (DEBUG_LEVEL > 1) { - System.err.println(getClass() + " getCalledNodes " + ret); - System.err.println("called nodes: " - + Iterator2Collection.toSet(new FilterIterator(getSuccNodes(ret), exitFilter))); - } - return new FilterIterator(getSuccNodes(ret), exitFilter); - } - - /** - * get the "normal" successors (sic) for a return site; i.e., the "normal" CFG predecessors that are not call nodes. - * - * @see com.ibm.wala.dataflow.IFDS.ISupergraph#getCalledNodes(java.lang.Object) - */ - public Iterator getNormalSuccessors(final T ret) { - Iterator allPreds = delegate.getPredNodes(ret); - Filter sameProc = new Filter() { - public boolean accepts(T o) { - // throw out the exit node, which can be a predecessor due to tail recursion. - return getProcOf(ret).equals(getProcOf(o)) && !delegate.isExit(o); - } - }; - Iterator sameProcPreds = new FilterIterator(allPreds, sameProc); - Filter notCall = new Filter() { - public boolean accepts(T o) { - return !delegate.isCall(o); - } - }; - return new FilterIterator(sameProcPreds, notCall); - } - - /* - * @see com.ibm.wala.dataflow.IFDS.ISupergraph#getReturnSites(java.lang.Object) - */ - public Iterator getReturnSites(T c, P callee) { - return delegate.getCallSites(c, callee); - } - - /* - * @see com.ibm.wala.dataflow.IFDS.ISupergraph#isExit(java.lang.Object) - */ - public boolean isExit(T n) { - return delegate.isEntry(n); - } - - /* - * @see com.ibm.wala.dataflow.IFDS.ISupergraph#getProcOf(java.lang.Object) - */ - public P getProcOf(T n) { - return delegate.getProcOf(n); - } - - /* - * @see com.ibm.wala.util.graph.Graph#removeNodeAndEdges(java.lang.Object) - */ - public void removeNodeAndEdges(Object N) throws UnsupportedOperationException { - throw new UnsupportedOperationException(); - - } - - public Iterator iterator() { - return delegate.iterator(); - } - - /* - * @see com.ibm.wala.util.graph.NodeManager#getNumberOfNodes() - */ - public int getNumberOfNodes() { - return delegate.getNumberOfNodes(); - } - - /* - * @see com.ibm.wala.util.graph.NodeManager#addNode(java.lang.Object) - */ - public void addNode(Object n) throws UnsupportedOperationException { - throw new UnsupportedOperationException(); - } - - /* - * @see com.ibm.wala.util.graph.NodeManager#removeNode(java.lang.Object) - */ - public void removeNode(Object n) throws UnsupportedOperationException { - throw new UnsupportedOperationException(); - - } - - /* - * @see com.ibm.wala.util.graph.NodeManager#containsNode(java.lang.Object) - */ - public boolean containsNode(T N) { - return delegate.containsNode(N); - } - - /* - * @see com.ibm.wala.util.graph.EdgeManager#getPredNodes(java.lang.Object) - */ - public Iterator getPredNodes(T N) { - return delegate.getSuccNodes(N); - } - - /* - * @see com.ibm.wala.util.graph.EdgeManager#getPredNodeCount(java.lang.Object) - */ - public int getPredNodeCount(T N) { - return delegate.getSuccNodeCount(N); - } - - /* - * @see com.ibm.wala.util.graph.EdgeManager#getSuccNodes(java.lang.Object) - */ - public Iterator getSuccNodes(T N) { - return delegate.getPredNodes(N); - } - - public boolean hasEdge(T src, T dst) { - return delegate.hasEdge(dst, src); - } - - /* - * @see com.ibm.wala.util.graph.EdgeManager#getSuccNodeCount(java.lang.Object) - */ - public int getSuccNodeCount(T N) { - return delegate.getPredNodeCount(N); - } - - /* - * @see com.ibm.wala.util.graph.EdgeManager#addEdge(java.lang.Object, java.lang.Object) - */ - public void addEdge(Object src, Object dst) throws UnsupportedOperationException { - throw new UnsupportedOperationException(); - } - - public void removeEdge(Object src, Object dst) throws UnsupportedOperationException { - throw new UnsupportedOperationException(); - } - - /* - * @see com.ibm.wala.util.graph.EdgeManager#removeEdges(java.lang.Object) - */ - public void removeAllIncidentEdges(Object node) throws UnsupportedOperationException { - throw new UnsupportedOperationException(); - } - - /* - * @see com.ibm.wala.dataflow.IFDS.ISupergraph#getEntriesForProcedure(java.lang.Object) - */ - public T[] getEntriesForProcedure(P object) { - return delegate.getExitsForProcedure(object); - } - - /* - * @see com.ibm.wala.dataflow.IFDS.ISupergraph#getEntriesForProcedure(java.lang.Object) - */ - public T[] getExitsForProcedure(P object) { - return delegate.getEntriesForProcedure(object); - } - - /* - * @see com.ibm.wala.dataflow.IFDS.ISupergraph#isReturn(java.lang.Object) - */ - public boolean isReturn(T n) throws UnimplementedError { - return delegate.isCall(n); - } - - /* - * @see com.ibm.wala.dataflow.IFDS.ISupergraph#getCallSites(java.lang.Object) - */ - public Iterator getCallSites(T r, P callee) { - return delegate.getReturnSites(r, callee); - } - - /* - * @see com.ibm.wala.dataflow.IFDS.ISupergraph#isEntry(java.lang.Object) - */ - public boolean isEntry(T n) { - return delegate.isExit(n); - } - - /* - * @see com.ibm.wala.dataflow.IFDS.ISupergraph#classifyEdge(java.lang.Object, java.lang.Object) - */ - public byte classifyEdge(T src, T dest) { - byte d = delegate.classifyEdge(dest, src); - switch (d) { - case CALL_EDGE: - return RETURN_EDGE; - case RETURN_EDGE: - return CALL_EDGE; - case OTHER: - return OTHER; - case CALL_TO_RETURN_EDGE: - return CALL_TO_RETURN_EDGE; - default: - Assertions.UNREACHABLE(); - return -1; - } - } - - @Override - public String toString() { - return "Backwards of delegate\n" + delegate; - } - - public void removeIncomingEdges(Object node) throws UnsupportedOperationException { - throw new UnsupportedOperationException(); - - } - - public void removeOutgoingEdges(T node) throws UnsupportedOperationException { - throw new UnsupportedOperationException(); - } - - /* - * @see com.ibm.wala.dataflow.IFDS.ISupergraph#getNumberOfBlocks(java.lang.Object) - */ - public int getNumberOfBlocks(P procedure) { - return delegate.getNumberOfBlocks(procedure); - } - - /* - * @see com.ibm.wala.dataflow.IFDS.ISupergraph#getLocalBlockNumber(java.lang.Object) - */ - public int getLocalBlockNumber(T n) { - return delegate.getLocalBlockNumber(n); - } - - /* - * @see com.ibm.wala.dataflow.IFDS.ISupergraph#getLocalBlock(java.lang.Object, int) - */ - public T getLocalBlock(P procedure, int i) { - return delegate.getLocalBlock(procedure, i); - } - - public int getNumber(T N) { - return delegate.getNumber(N); - } - - public T getNode(int number) { - return delegate.getNode(number); - } - - public int getMaxNumber() { - return delegate.getMaxNumber(); - } - - public Iterator iterateNodes(IntSet s) throws UnimplementedError { - Assertions.UNREACHABLE(); - return null; - } - - public IntSet getSuccNodeNumbers(T node) { - return delegate.getPredNodeNumbers(node); - } - - public IntSet getPredNodeNumbers(Object node) throws UnimplementedError { - Assertions.UNREACHABLE(); - return null; - } +/******************************************************************************* + * 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.dataflow.IFDS; + +import java.util.Iterator; + +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.debug.Assertions; +import com.ibm.wala.util.debug.UnimplementedError; +import com.ibm.wala.util.graph.Graph; +import com.ibm.wala.util.intset.IntSet; + +/** + * A "reversed" supergraph for backwards analysis. + * + * In this view, a return is treated like a call, and vice-versa. All normal edges are reversed. + */ +public class BackwardsSupergraph implements ISupergraph { + + /** + * DEBUG_LEVEL: + *
          + *
        • 0 No output + *
        • 1 Print some simple stats and warning information + *
        • 2 Detailed debugging + *
        + */ + static final int DEBUG_LEVEL = 0; + + private final ISupergraph delegate; + + private final ExitFilter exitFilter = new ExitFilter(); + + /** + * @param forwardGraph the graph to ``reverse'' + */ + protected BackwardsSupergraph(ISupergraph forwardGraph) { + if (forwardGraph == null) { + throw new IllegalArgumentException("null forwardGraph"); + } + this.delegate = forwardGraph; + } + + public static BackwardsSupergraph make(ISupergraph forwardGraph) { + return new BackwardsSupergraph(forwardGraph); + } + + /** + * TODO: for now, this is not inverted. + * + * @see com.ibm.wala.dataflow.IFDS.ISupergraph#getProcedureGraph() + */ + public Graph getProcedureGraph() { + return delegate.getProcedureGraph(); + } + + /* + * @see com.ibm.wala.dataflow.IFDS.ISupergraph#isCall(java.lang.Object) + */ + public boolean isCall(T n) { + return delegate.isReturn(n); + } + + /** + * a filter that accepts only exit nodes from the original graph. + */ + private class ExitFilter implements Filter { + /* + * @see com.ibm.wala.util.Filter#accepts(java.lang.Object) + */ + @SuppressWarnings("unchecked") + public boolean accepts(Object o) { + return delegate.isExit((T) o); + } + } + + /** + * get the "called" (sic) nodes for a return site; i.e., the exit nodes that flow directly to this return site. + * + * @see com.ibm.wala.dataflow.IFDS.ISupergraph#getCalledNodes(java.lang.Object) + */ + public Iterator getCalledNodes(T ret) { + if (DEBUG_LEVEL > 1) { + System.err.println(getClass() + " getCalledNodes " + ret); + System.err.println("called nodes: " + + Iterator2Collection.toSet(new FilterIterator(getSuccNodes(ret), exitFilter))); + } + return new FilterIterator(getSuccNodes(ret), exitFilter); + } + + /** + * get the "normal" successors (sic) for a return site; i.e., the "normal" CFG predecessors that are not call nodes. + * + * @see com.ibm.wala.dataflow.IFDS.ISupergraph#getCalledNodes(java.lang.Object) + */ + public Iterator getNormalSuccessors(final T ret) { + Iterator allPreds = delegate.getPredNodes(ret); + Filter sameProc = new Filter() { + public boolean accepts(T o) { + // throw out the exit node, which can be a predecessor due to tail recursion. + return getProcOf(ret).equals(getProcOf(o)) && !delegate.isExit(o); + } + }; + Iterator sameProcPreds = new FilterIterator(allPreds, sameProc); + Filter notCall = new Filter() { + public boolean accepts(T o) { + return !delegate.isCall(o); + } + }; + return new FilterIterator(sameProcPreds, notCall); + } + + /* + * @see com.ibm.wala.dataflow.IFDS.ISupergraph#getReturnSites(java.lang.Object) + */ + public Iterator getReturnSites(T c, P callee) { + return delegate.getCallSites(c, callee); + } + + /* + * @see com.ibm.wala.dataflow.IFDS.ISupergraph#isExit(java.lang.Object) + */ + public boolean isExit(T n) { + return delegate.isEntry(n); + } + + /* + * @see com.ibm.wala.dataflow.IFDS.ISupergraph#getProcOf(java.lang.Object) + */ + public P getProcOf(T n) { + return delegate.getProcOf(n); + } + + /* + * @see com.ibm.wala.util.graph.Graph#removeNodeAndEdges(java.lang.Object) + */ + public void removeNodeAndEdges(Object N) throws UnsupportedOperationException { + throw new UnsupportedOperationException(); + + } + + public Iterator iterator() { + return delegate.iterator(); + } + + /* + * @see com.ibm.wala.util.graph.NodeManager#getNumberOfNodes() + */ + public int getNumberOfNodes() { + return delegate.getNumberOfNodes(); + } + + /* + * @see com.ibm.wala.util.graph.NodeManager#addNode(java.lang.Object) + */ + public void addNode(Object n) throws UnsupportedOperationException { + throw new UnsupportedOperationException(); + } + + /* + * @see com.ibm.wala.util.graph.NodeManager#removeNode(java.lang.Object) + */ + public void removeNode(Object n) throws UnsupportedOperationException { + throw new UnsupportedOperationException(); + + } + + /* + * @see com.ibm.wala.util.graph.NodeManager#containsNode(java.lang.Object) + */ + public boolean containsNode(T N) { + return delegate.containsNode(N); + } + + /* + * @see com.ibm.wala.util.graph.EdgeManager#getPredNodes(java.lang.Object) + */ + public Iterator getPredNodes(T N) { + return delegate.getSuccNodes(N); + } + + /* + * @see com.ibm.wala.util.graph.EdgeManager#getPredNodeCount(java.lang.Object) + */ + public int getPredNodeCount(T N) { + return delegate.getSuccNodeCount(N); + } + + /* + * @see com.ibm.wala.util.graph.EdgeManager#getSuccNodes(java.lang.Object) + */ + public Iterator getSuccNodes(T N) { + return delegate.getPredNodes(N); + } + + public boolean hasEdge(T src, T dst) { + return delegate.hasEdge(dst, src); + } + + /* + * @see com.ibm.wala.util.graph.EdgeManager#getSuccNodeCount(java.lang.Object) + */ + public int getSuccNodeCount(T N) { + return delegate.getPredNodeCount(N); + } + + /* + * @see com.ibm.wala.util.graph.EdgeManager#addEdge(java.lang.Object, java.lang.Object) + */ + public void addEdge(Object src, Object dst) throws UnsupportedOperationException { + throw new UnsupportedOperationException(); + } + + public void removeEdge(Object src, Object dst) throws UnsupportedOperationException { + throw new UnsupportedOperationException(); + } + + /* + * @see com.ibm.wala.util.graph.EdgeManager#removeEdges(java.lang.Object) + */ + public void removeAllIncidentEdges(Object node) throws UnsupportedOperationException { + throw new UnsupportedOperationException(); + } + + /* + * @see com.ibm.wala.dataflow.IFDS.ISupergraph#getEntriesForProcedure(java.lang.Object) + */ + public T[] getEntriesForProcedure(P object) { + return delegate.getExitsForProcedure(object); + } + + /* + * @see com.ibm.wala.dataflow.IFDS.ISupergraph#getEntriesForProcedure(java.lang.Object) + */ + public T[] getExitsForProcedure(P object) { + return delegate.getEntriesForProcedure(object); + } + + /* + * @see com.ibm.wala.dataflow.IFDS.ISupergraph#isReturn(java.lang.Object) + */ + public boolean isReturn(T n) throws UnimplementedError { + return delegate.isCall(n); + } + + /* + * @see com.ibm.wala.dataflow.IFDS.ISupergraph#getCallSites(java.lang.Object) + */ + public Iterator getCallSites(T r, P callee) { + return delegate.getReturnSites(r, callee); + } + + /* + * @see com.ibm.wala.dataflow.IFDS.ISupergraph#isEntry(java.lang.Object) + */ + public boolean isEntry(T n) { + return delegate.isExit(n); + } + + /* + * @see com.ibm.wala.dataflow.IFDS.ISupergraph#classifyEdge(java.lang.Object, java.lang.Object) + */ + public byte classifyEdge(T src, T dest) { + byte d = delegate.classifyEdge(dest, src); + switch (d) { + case CALL_EDGE: + return RETURN_EDGE; + case RETURN_EDGE: + return CALL_EDGE; + case OTHER: + return OTHER; + case CALL_TO_RETURN_EDGE: + return CALL_TO_RETURN_EDGE; + default: + Assertions.UNREACHABLE(); + return -1; + } + } + + @Override + public String toString() { + return "Backwards of delegate\n" + delegate; + } + + public void removeIncomingEdges(Object node) throws UnsupportedOperationException { + throw new UnsupportedOperationException(); + + } + + public void removeOutgoingEdges(T node) throws UnsupportedOperationException { + throw new UnsupportedOperationException(); + } + + /* + * @see com.ibm.wala.dataflow.IFDS.ISupergraph#getNumberOfBlocks(java.lang.Object) + */ + public int getNumberOfBlocks(P procedure) { + return delegate.getNumberOfBlocks(procedure); + } + + /* + * @see com.ibm.wala.dataflow.IFDS.ISupergraph#getLocalBlockNumber(java.lang.Object) + */ + public int getLocalBlockNumber(T n) { + return delegate.getLocalBlockNumber(n); + } + + /* + * @see com.ibm.wala.dataflow.IFDS.ISupergraph#getLocalBlock(java.lang.Object, int) + */ + public T getLocalBlock(P procedure, int i) { + return delegate.getLocalBlock(procedure, i); + } + + public int getNumber(T N) { + return delegate.getNumber(N); + } + + public T getNode(int number) { + return delegate.getNode(number); + } + + public int getMaxNumber() { + return delegate.getMaxNumber(); + } + + public Iterator iterateNodes(IntSet s) throws UnimplementedError { + Assertions.UNREACHABLE(); + return null; + } + + public IntSet getSuccNodeNumbers(T node) { + return delegate.getPredNodeNumbers(node); + } + + public IntSet getPredNodeNumbers(Object node) throws UnimplementedError { + Assertions.UNREACHABLE(); + return null; + } } \ No newline at end of file diff --git a/com.ibm.wala.core/src/com/ibm/wala/dataflow/IFDS/BoundedPartiallyBalancedSolver.java b/com.ibm.wala.core/src/com/ibm/wala/dataflow/IFDS/BoundedPartiallyBalancedSolver.java index 7055d1aed..e82ed2ca5 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/dataflow/IFDS/BoundedPartiallyBalancedSolver.java +++ b/com.ibm.wala.core/src/com/ibm/wala/dataflow/IFDS/BoundedPartiallyBalancedSolver.java @@ -1,64 +1,64 @@ -/******************************************************************************* - * Copyright (c) 2008 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.dataflow.IFDS; - -import com.ibm.wala.util.MonitorUtil.IProgressMonitor; - - - -/** - * A {@link TabulationSolver} that gives up after a finite bound. - * - * @param type of node in the supergraph - * @param

        type of a procedure (like a box in an RSM) - * @param type of factoids propagated when solving this problem - * - */ -public class BoundedPartiallyBalancedSolver extends PartiallyBalancedTabulationSolver { - - private final static boolean VERBOSE = false; - - public static BoundedPartiallyBalancedSolver createdBoundedPartiallyBalancedSolver(PartiallyBalancedTabulationProblem p, int bound, - IProgressMonitor monitor) { - return new BoundedPartiallyBalancedSolver(p, bound, monitor); - } - - private final int bound; - - private int numSteps = 0; - - protected BoundedPartiallyBalancedSolver(PartiallyBalancedTabulationProblem p, int bound, IProgressMonitor monitor) { - super(p, monitor); - this.bound = bound; - } - - @Override - protected boolean propagate(T s_p, int i,T n, int j) { - if (numSteps < bound) { - numSteps++; - return super.propagate(s_p, i, n, j); - } else { - if (VERBOSE) { - System.err.println("Suppressing propagation; reached bound " + s_p + " " + i + " " + n + " " + j); - } - return false; - } - } - - public int getNumSteps() { - return numSteps; - } - - public void resetBound() { - numSteps = 0; - } - -} +/******************************************************************************* + * Copyright (c) 2008 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.dataflow.IFDS; + +import com.ibm.wala.util.MonitorUtil.IProgressMonitor; + + + +/** + * A {@link TabulationSolver} that gives up after a finite bound. + * + * @param type of node in the supergraph + * @param

        type of a procedure (like a box in an RSM) + * @param type of factoids propagated when solving this problem + * + */ +public class BoundedPartiallyBalancedSolver extends PartiallyBalancedTabulationSolver { + + private final static boolean VERBOSE = false; + + public static BoundedPartiallyBalancedSolver createdBoundedPartiallyBalancedSolver(PartiallyBalancedTabulationProblem p, int bound, + IProgressMonitor monitor) { + return new BoundedPartiallyBalancedSolver(p, bound, monitor); + } + + private final int bound; + + private int numSteps = 0; + + protected BoundedPartiallyBalancedSolver(PartiallyBalancedTabulationProblem p, int bound, IProgressMonitor monitor) { + super(p, monitor); + this.bound = bound; + } + + @Override + protected boolean propagate(T s_p, int i,T n, int j) { + if (numSteps < bound) { + numSteps++; + return super.propagate(s_p, i, n, j); + } else { + if (VERBOSE) { + System.err.println("Suppressing propagation; reached bound " + s_p + " " + i + " " + n + " " + j); + } + return false; + } + } + + public int getNumSteps() { + return numSteps; + } + + public void resetBound() { + numSteps = 0; + } + +} diff --git a/com.ibm.wala.core/src/com/ibm/wala/dataflow/IFDS/BoundedTabulationSolver.java b/com.ibm.wala.core/src/com/ibm/wala/dataflow/IFDS/BoundedTabulationSolver.java index 3fdd9f6bd..3a7216b5a 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/dataflow/IFDS/BoundedTabulationSolver.java +++ b/com.ibm.wala.core/src/com/ibm/wala/dataflow/IFDS/BoundedTabulationSolver.java @@ -1,58 +1,58 @@ -/******************************************************************************* - * Copyright (c) 2008 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.dataflow.IFDS; - -import com.ibm.wala.util.MonitorUtil.IProgressMonitor; - - - -/** - * A {@link TabulationSolver} that gives up after a finite bound. - * - * @param type of node in the supergraph - * @param

        type of a procedure (like a box in an RSM) - * @param type of factoids propagated when solving this problem - * - */ -public class BoundedTabulationSolver extends TabulationSolver { - - public static BoundedTabulationSolver createBoundedTabulationSolver(TabulationProblem p, int bound, - IProgressMonitor monitor) { - return new BoundedTabulationSolver(p, bound, monitor); - } - - private final int bound; - - private int numSteps = 0; - - protected BoundedTabulationSolver(TabulationProblem p, int bound, IProgressMonitor monitor) { - super(p, monitor); - this.bound = bound; - } - - @Override - protected boolean propagate(T s_p, int i,T n, int j) { - if (numSteps < bound) { - numSteps++; - return super.propagate(s_p, i, n, j); - } - return false; - } - - public int getNumSteps() { - return numSteps; - } - - public void resetBound() { - numSteps = 0; - } - -} +/******************************************************************************* + * Copyright (c) 2008 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.dataflow.IFDS; + +import com.ibm.wala.util.MonitorUtil.IProgressMonitor; + + + +/** + * A {@link TabulationSolver} that gives up after a finite bound. + * + * @param type of node in the supergraph + * @param

        type of a procedure (like a box in an RSM) + * @param type of factoids propagated when solving this problem + * + */ +public class BoundedTabulationSolver extends TabulationSolver { + + public static BoundedTabulationSolver createBoundedTabulationSolver(TabulationProblem p, int bound, + IProgressMonitor monitor) { + return new BoundedTabulationSolver(p, bound, monitor); + } + + private final int bound; + + private int numSteps = 0; + + protected BoundedTabulationSolver(TabulationProblem p, int bound, IProgressMonitor monitor) { + super(p, monitor); + this.bound = bound; + } + + @Override + protected boolean propagate(T s_p, int i,T n, int j) { + if (numSteps < bound) { + numSteps++; + return super.propagate(s_p, i, n, j); + } + return false; + } + + public int getNumSteps() { + return numSteps; + } + + public void resetBound() { + numSteps = 0; + } + +} diff --git a/com.ibm.wala.core/src/com/ibm/wala/dataflow/IFDS/CallFlowEdges.java b/com.ibm.wala.core/src/com/ibm/wala/dataflow/IFDS/CallFlowEdges.java index 80c6678ff..accc93ce0 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/dataflow/IFDS/CallFlowEdges.java +++ b/com.ibm.wala.core/src/com/ibm/wala/dataflow/IFDS/CallFlowEdges.java @@ -1,159 +1,159 @@ -/******************************************************************************* - * 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.dataflow.IFDS; - -import com.ibm.wala.util.collections.SparseVector; -import com.ibm.wala.util.intset.BasicNaturalRelation; -import com.ibm.wala.util.intset.BimodalMutableIntSet; -import com.ibm.wala.util.intset.IBinaryNaturalRelation; -import com.ibm.wala.util.intset.IntSet; -import com.ibm.wala.util.intset.MutableIntSet; -import com.ibm.wala.util.intset.MutableSparseIntSet; -import com.ibm.wala.util.intset.SparseIntSet; - -/** - * A set of call flow edges which lead to a particular procedure entry s_p. - */ -public class CallFlowEdges { - - /** - * A map from integer -> (IBinaryNonNegativeIntRelation) - * - * For a fact d2, edges[d2] gives a relation R=(c,d1) s.t. ( -> ) was recorded as a call flow edge. - * - * Note that we handle paths of the form -> specially, below. - * - * TODO: more representation optimization. A special representation for triples? sparse representations for CFG? exploit shorts - * for ints? - */ - private final SparseVector edges = new SparseVector(1, 1.1f); - - /** - * a map from integer d1 -> int set. - * - * for fact d1, identityPaths[d1] gives the set of block numbers C s.t. for c \in C, -> is an edge. - */ - private final SparseVector identityEdges = new SparseVector(1, 1.1f); - - public CallFlowEdges() { - } - - /** - * Record that we've discovered a call edge -> - * - * @param c global number identifying the call site node - * @param d1 source fact at the call edge - * @param d2 result fact (result of the call flow function) - */ - public void addCallEdge(int c, int d1, int d2) { - if (TabulationSolver.DEBUG_LEVEL > 0) { - System.err.println("addCallEdge " + c + " " + d1 + " " + d2); - } - if (d1 == d2) { - BimodalMutableIntSet s = (BimodalMutableIntSet) identityEdges.get(d1); - if (s == null) { - s = new BimodalMutableIntSet(); - identityEdges.set(d1, s); - } - s.add(c); - } else { - IBinaryNaturalRelation R = edges.get(d2); - if (R == null) { - // we expect the first dimension of R to be dense, the second sparse - R = new BasicNaturalRelation(new byte[] { BasicNaturalRelation.TWO_LEVEL }, BasicNaturalRelation.TWO_LEVEL); - edges.set(d2, R); - } - R.add(c, d1); - } - } - - /** - * @param c - * @param d2 - * @return set of d1 s.t. -> was recorded as call flow, or null if none found. - */ - public IntSet getCallFlowSources(int c, int d2) { - if (c < 0) { - throw new IllegalArgumentException("invalid c : " + c); - } - if (d2 < 0) { - throw new IllegalArgumentException("invalid d2: " + d2); - } - IntSet s = identityEdges.get(d2); - IBinaryNaturalRelation R = edges.get(d2); - IntSet result = null; - if (R == null) { - if (s != null) { - result = s.contains(c) ? SparseIntSet.singleton(d2) : null; - } - } else { - if (s == null) { - result = R.getRelated(c); - } else { - if (s.contains(c)) { - if (R.getRelated(c) == null) { - result = SparseIntSet.singleton(d2); - } else { - result = MutableSparseIntSet.make(R.getRelated(c)); - ((MutableSparseIntSet) result).add(d2); - } - } else { - result = R.getRelated(c); - } - } - } - if (TabulationSolver.DEBUG_LEVEL > 0) { - System.err.println("getCallFlowSources " + c + " " + d2 + " " + result); - } - return result; - } - - /** - * - * @param d2 - * @return set of c s.t. -> was recorded as call flow (for some d1), or null if none found. - */ - public IntSet getCallFlowSourceNodes(int d2) { - IntSet s = identityEdges.get(d2); - IBinaryNaturalRelation R = edges.get(d2); - IntSet result = null; - if (R == null) { - if (s != null) { - result = s; - } - } else { - if (s == null) { - result = getDomain(R); - } else { - result = MutableSparseIntSet.make(s); - ((MutableSparseIntSet) result).addAll(getDomain(R)); - } - } - if (TabulationSolver.DEBUG_LEVEL > 0) { - System.err.println("getCallFlowSources " + d2 + " " + result); - } - return result; - - } - - // TODO optimize - private IntSet getDomain(IBinaryNaturalRelation r) { - MutableIntSet result = MutableSparseIntSet.makeEmpty(); - int maxKeyValue = r.maxKeyValue(); - for (int i = 0; i <= maxKeyValue; i++) { - if (r.getRelated(i) != null) { - result.add(i); - } - } - return result; - } - +/******************************************************************************* + * 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.dataflow.IFDS; + +import com.ibm.wala.util.collections.SparseVector; +import com.ibm.wala.util.intset.BasicNaturalRelation; +import com.ibm.wala.util.intset.BimodalMutableIntSet; +import com.ibm.wala.util.intset.IBinaryNaturalRelation; +import com.ibm.wala.util.intset.IntSet; +import com.ibm.wala.util.intset.MutableIntSet; +import com.ibm.wala.util.intset.MutableSparseIntSet; +import com.ibm.wala.util.intset.SparseIntSet; + +/** + * A set of call flow edges which lead to a particular procedure entry s_p. + */ +public class CallFlowEdges { + + /** + * A map from integer -> (IBinaryNonNegativeIntRelation) + * + * For a fact d2, edges[d2] gives a relation R=(c,d1) s.t. ( -> ) was recorded as a call flow edge. + * + * Note that we handle paths of the form -> specially, below. + * + * TODO: more representation optimization. A special representation for triples? sparse representations for CFG? exploit shorts + * for ints? + */ + private final SparseVector edges = new SparseVector(1, 1.1f); + + /** + * a map from integer d1 -> int set. + * + * for fact d1, identityPaths[d1] gives the set of block numbers C s.t. for c \in C, -> is an edge. + */ + private final SparseVector identityEdges = new SparseVector(1, 1.1f); + + public CallFlowEdges() { + } + + /** + * Record that we've discovered a call edge -> + * + * @param c global number identifying the call site node + * @param d1 source fact at the call edge + * @param d2 result fact (result of the call flow function) + */ + public void addCallEdge(int c, int d1, int d2) { + if (TabulationSolver.DEBUG_LEVEL > 0) { + System.err.println("addCallEdge " + c + " " + d1 + " " + d2); + } + if (d1 == d2) { + BimodalMutableIntSet s = (BimodalMutableIntSet) identityEdges.get(d1); + if (s == null) { + s = new BimodalMutableIntSet(); + identityEdges.set(d1, s); + } + s.add(c); + } else { + IBinaryNaturalRelation R = edges.get(d2); + if (R == null) { + // we expect the first dimension of R to be dense, the second sparse + R = new BasicNaturalRelation(new byte[] { BasicNaturalRelation.TWO_LEVEL }, BasicNaturalRelation.TWO_LEVEL); + edges.set(d2, R); + } + R.add(c, d1); + } + } + + /** + * @param c + * @param d2 + * @return set of d1 s.t. -> was recorded as call flow, or null if none found. + */ + public IntSet getCallFlowSources(int c, int d2) { + if (c < 0) { + throw new IllegalArgumentException("invalid c : " + c); + } + if (d2 < 0) { + throw new IllegalArgumentException("invalid d2: " + d2); + } + IntSet s = identityEdges.get(d2); + IBinaryNaturalRelation R = edges.get(d2); + IntSet result = null; + if (R == null) { + if (s != null) { + result = s.contains(c) ? SparseIntSet.singleton(d2) : null; + } + } else { + if (s == null) { + result = R.getRelated(c); + } else { + if (s.contains(c)) { + if (R.getRelated(c) == null) { + result = SparseIntSet.singleton(d2); + } else { + result = MutableSparseIntSet.make(R.getRelated(c)); + ((MutableSparseIntSet) result).add(d2); + } + } else { + result = R.getRelated(c); + } + } + } + if (TabulationSolver.DEBUG_LEVEL > 0) { + System.err.println("getCallFlowSources " + c + " " + d2 + " " + result); + } + return result; + } + + /** + * + * @param d2 + * @return set of c s.t. -> was recorded as call flow (for some d1), or null if none found. + */ + public IntSet getCallFlowSourceNodes(int d2) { + IntSet s = identityEdges.get(d2); + IBinaryNaturalRelation R = edges.get(d2); + IntSet result = null; + if (R == null) { + if (s != null) { + result = s; + } + } else { + if (s == null) { + result = getDomain(R); + } else { + result = MutableSparseIntSet.make(s); + ((MutableSparseIntSet) result).addAll(getDomain(R)); + } + } + if (TabulationSolver.DEBUG_LEVEL > 0) { + System.err.println("getCallFlowSources " + d2 + " " + result); + } + return result; + + } + + // TODO optimize + private IntSet getDomain(IBinaryNaturalRelation r) { + MutableIntSet result = MutableSparseIntSet.makeEmpty(); + int maxKeyValue = r.maxKeyValue(); + for (int i = 0; i <= maxKeyValue; i++) { + if (r.getRelated(i) != null) { + result.add(i); + } + } + return result; + } + } \ No newline at end of file diff --git a/com.ibm.wala.core/src/com/ibm/wala/dataflow/IFDS/IBinaryReturnFlowFunction.java b/com.ibm.wala.core/src/com/ibm/wala/dataflow/IFDS/IBinaryReturnFlowFunction.java index 6a5ae8d00..b270cc12a 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/dataflow/IFDS/IBinaryReturnFlowFunction.java +++ b/com.ibm.wala.core/src/com/ibm/wala/dataflow/IFDS/IBinaryReturnFlowFunction.java @@ -1,32 +1,32 @@ -/******************************************************************************* - * 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.dataflow.IFDS; - -import com.ibm.wala.util.intset.SparseIntSet; - -/** - * A binary flow function corresponding to a return statements combining information from the call site and the exit site. - * - * This function should be pairwise distributive for use with the Tabulation algorithm. - * - * SJF: I have made this extend IFlowFunction to minimize damage to the extant class hierarchy. But calling super.getTargets() will - * be a problem, so be very careful in how you implement and use this. The Tabulation solver will do the right thing. - */ -public interface IBinaryReturnFlowFunction extends IFlowFunction { - - /** - * @param call_d factoid of the caller at the call site - * @param exit_d factoid of the callee at the exit site - * @return set of ret_d such that (, ret_d) is an edge in this distributive function's graph representation, or - * null if there are none - */ - public SparseIntSet getTargets(int call_d, int exit_d); -} +/******************************************************************************* + * 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.dataflow.IFDS; + +import com.ibm.wala.util.intset.SparseIntSet; + +/** + * A binary flow function corresponding to a return statements combining information from the call site and the exit site. + * + * This function should be pairwise distributive for use with the Tabulation algorithm. + * + * SJF: I have made this extend IFlowFunction to minimize damage to the extant class hierarchy. But calling super.getTargets() will + * be a problem, so be very careful in how you implement and use this. The Tabulation solver will do the right thing. + */ +public interface IBinaryReturnFlowFunction extends IFlowFunction { + + /** + * @param call_d factoid of the caller at the call site + * @param exit_d factoid of the callee at the exit site + * @return set of ret_d such that (, ret_d) is an edge in this distributive function's graph representation, or + * null if there are none + */ + public SparseIntSet getTargets(int call_d, int exit_d); +} diff --git a/com.ibm.wala.core/src/com/ibm/wala/dataflow/IFDS/IFlowFunction.java b/com.ibm.wala.core/src/com/ibm/wala/dataflow/IFDS/IFlowFunction.java index f10f68f25..8e2f8da04 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/dataflow/IFDS/IFlowFunction.java +++ b/com.ibm.wala.core/src/com/ibm/wala/dataflow/IFDS/IFlowFunction.java @@ -1,19 +1,19 @@ -/******************************************************************************* - * 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.dataflow.IFDS; - -/** - * A flow function corresponding to an edge in the supergraph. - * - * This function should be distributive for use with the Tabulation algorithm. - */ -public interface IFlowFunction { -} +/******************************************************************************* + * 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.dataflow.IFDS; + +/** + * A flow function corresponding to an edge in the supergraph. + * + * This function should be distributive for use with the Tabulation algorithm. + */ +public interface IFlowFunction { +} diff --git a/com.ibm.wala.core/src/com/ibm/wala/dataflow/IFDS/IFlowFunctionMap.java b/com.ibm.wala.core/src/com/ibm/wala/dataflow/IFDS/IFlowFunctionMap.java index 12fb6edec..6871f223a 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/dataflow/IFDS/IFlowFunctionMap.java +++ b/com.ibm.wala.core/src/com/ibm/wala/dataflow/IFDS/IFlowFunctionMap.java @@ -1,58 +1,58 @@ -/******************************************************************************* - * Copyright (c) 2002 - 2006 IBM Corporation. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * IBM Corporation - initial API and implementation - *******************************************************************************/ -package com.ibm.wala.dataflow.IFDS; - -/** - * A map from an edge in a supergraph to a flow function - * - * @param type of node in the supergraph - */ -public interface IFlowFunctionMap { - - /** - * @param src - * @param dest - * @return the flow function for a "normal" edge in the supergraph from src->dest - */ - public IUnaryFlowFunction getNormalFlowFunction(T src, T dest); - - /** - * @param src the call block - * @param dest the entry of the callee - * @param ret the block that will be returned to, in the caller. This can be null .. signifying that facts can flow - * into the callee but not return - * @return the flow function for a "call" edge in the supergraph from src->dest - */ - public IUnaryFlowFunction getCallFlowFunction(T src, T dest, T ret); - - /** - * @param call supergraph node of the call instruction for this return edge. - * @param src - * @param dest - * @return the flow function for a "return" edge in the supergraph from src->dest - */ - public IFlowFunction getReturnFlowFunction(T call, T src, T dest); - - /** - * @param src - * @param dest - * @return the flow function for a "call-to-return" edge in the supergraph from src->dest - */ - public IUnaryFlowFunction getCallToReturnFlowFunction(T src, T dest); - - /** - * @param src - * @param dest - * @return the flow function for a "call-to-return" edge in the supergraph from src->dest, when the supergraph does - * not contain any callees of src. This happens via, e.g., slicing. - */ - public IUnaryFlowFunction getCallNoneToReturnFlowFunction(T src, T dest); -} +/******************************************************************************* + * 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.dataflow.IFDS; + +/** + * A map from an edge in a supergraph to a flow function + * + * @param type of node in the supergraph + */ +public interface IFlowFunctionMap { + + /** + * @param src + * @param dest + * @return the flow function for a "normal" edge in the supergraph from src->dest + */ + public IUnaryFlowFunction getNormalFlowFunction(T src, T dest); + + /** + * @param src the call block + * @param dest the entry of the callee + * @param ret the block that will be returned to, in the caller. This can be null .. signifying that facts can flow + * into the callee but not return + * @return the flow function for a "call" edge in the supergraph from src->dest + */ + public IUnaryFlowFunction getCallFlowFunction(T src, T dest, T ret); + + /** + * @param call supergraph node of the call instruction for this return edge. + * @param src + * @param dest + * @return the flow function for a "return" edge in the supergraph from src->dest + */ + public IFlowFunction getReturnFlowFunction(T call, T src, T dest); + + /** + * @param src + * @param dest + * @return the flow function for a "call-to-return" edge in the supergraph from src->dest + */ + public IUnaryFlowFunction getCallToReturnFlowFunction(T src, T dest); + + /** + * @param src + * @param dest + * @return the flow function for a "call-to-return" edge in the supergraph from src->dest, when the supergraph does + * not contain any callees of src. This happens via, e.g., slicing. + */ + public IUnaryFlowFunction getCallNoneToReturnFlowFunction(T src, T dest); +} diff --git a/com.ibm.wala.core/src/com/ibm/wala/dataflow/IFDS/IMergeFunction.java b/com.ibm.wala.core/src/com/ibm/wala/dataflow/IFDS/IMergeFunction.java index 824a07ac2..2395cdf3d 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/dataflow/IFDS/IMergeFunction.java +++ b/com.ibm.wala.core/src/com/ibm/wala/dataflow/IFDS/IMergeFunction.java @@ -1,30 +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.dataflow.IFDS; - -import com.ibm.wala.util.intset.IntSet; - -/** - * Special case: if supportsMerge(), then the problem is not really IFDS anymore. (TODO: rename it?). Instead, we perform a merge - * operation before propagating at every program point. This way, we can implement standard interprocedural dataflow and ESP-style - * property simulation, and various other things. - */ -public interface IMergeFunction { - - /** - * @param x set of factoid numbers that previously have been established to hold at a program point - * @param j a new factoid number which has been discovered to hold at a program point - * @return the factoid number z which should actually be propagated, based on a merge of the new fact j into the old state - * represented by x. return -1 if no fact should be propagated. - */ - int merge(IntSet x, int j); - -} +/******************************************************************************* + * 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.dataflow.IFDS; + +import com.ibm.wala.util.intset.IntSet; + +/** + * Special case: if supportsMerge(), then the problem is not really IFDS anymore. (TODO: rename it?). Instead, we perform a merge + * operation before propagating at every program point. This way, we can implement standard interprocedural dataflow and ESP-style + * property simulation, and various other things. + */ +public interface IMergeFunction { + + /** + * @param x set of factoid numbers that previously have been established to hold at a program point + * @param j a new factoid number which has been discovered to hold at a program point + * @return the factoid number z which should actually be propagated, based on a merge of the new fact j into the old state + * represented by x. return -1 if no fact should be propagated. + */ + int merge(IntSet x, int j); + +} diff --git a/com.ibm.wala.core/src/com/ibm/wala/dataflow/IFDS/IReversibleFlowFunction.java b/com.ibm.wala.core/src/com/ibm/wala/dataflow/IFDS/IReversibleFlowFunction.java index a190352c9..4e7725f08 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/dataflow/IFDS/IReversibleFlowFunction.java +++ b/com.ibm.wala.core/src/com/ibm/wala/dataflow/IFDS/IReversibleFlowFunction.java @@ -1,28 +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.dataflow.IFDS; - -import com.ibm.wala.util.intset.IntSet; - -/** - * A flow function corresponding to an edge in the supergraph. A reversible flow-function supports a getSources operation that - * allows computing backwards flow. At the very least, this is required in IFDS by call functions for which sources need to be found - * to handle insertion of summary edges. - */ -public interface IReversibleFlowFunction extends IUnaryFlowFunction { - - /** - * @param d2 - * @return set of d1 such that (d1,d2) is an edge in this distributive function's graph representation, or null if there are none - */ - public IntSet getSources(int d2); - -} +/******************************************************************************* + * 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.dataflow.IFDS; + +import com.ibm.wala.util.intset.IntSet; + +/** + * A flow function corresponding to an edge in the supergraph. A reversible flow-function supports a getSources operation that + * allows computing backwards flow. At the very least, this is required in IFDS by call functions for which sources need to be found + * to handle insertion of summary edges. + */ +public interface IReversibleFlowFunction extends IUnaryFlowFunction { + + /** + * @param d2 + * @return set of d1 such that (d1,d2) is an edge in this distributive function's graph representation, or null if there are none + */ + public IntSet getSources(int d2); + +} diff --git a/com.ibm.wala.core/src/com/ibm/wala/dataflow/IFDS/ISupergraph.java b/com.ibm.wala.core/src/com/ibm/wala/dataflow/IFDS/ISupergraph.java index 64daf7691..56de92c91 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/dataflow/IFDS/ISupergraph.java +++ b/com.ibm.wala.core/src/com/ibm/wala/dataflow/IFDS/ISupergraph.java @@ -1,136 +1,136 @@ -/******************************************************************************* - * 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.dataflow.IFDS; - -import java.util.Iterator; - -import com.ibm.wala.util.graph.Graph; -import com.ibm.wala.util.graph.NumberedGraph; - -/** - * - * A supergraph as defined by Reps, Horwitz, and Sagiv POPL95 - *

        - * In our implementation we don't require explicit entry and exit nodes. So, the first basic block in a method is implicitly the - * entry node, but might also be a call node too. Similarly for exit nodes. The solver is coded to deal with this appropriately. - *

        - * Additionally, due to exceptional control flow, each method might have multiple exits or multiple entries. - * - * T type of node in the supergraph P type of a procedure (like a box in an RSM) - */ -public interface ISupergraph extends NumberedGraph { - - public static final byte CALL_EDGE = 0; - - public static final byte RETURN_EDGE = 1; - - public static final byte CALL_TO_RETURN_EDGE = 2; - - public static final byte OTHER = 3; - - /** - * @return the graph of procedures (e.g. a call graph) over which this supergraph is induced. - */ - Graph getProcedureGraph(); - - /** - * @param n a node in this supergraph - * @return true iff this node includes a call. - */ - boolean isCall(T n); - - /** - * @param call a "call" node in the supergraph - * @return an Iterator of nodes that are targets of this call. - */ - Iterator getCalledNodes(T call); - - /** - * @param call a "call" node in the supergraph - * @return an Iterator of nodes that are normal (non-call) successors of this call. This should only apply to backwards problems, - * where we might have, say, a call and a goto flow into a return site. - */ - Iterator getNormalSuccessors(T call); - - /** - * @param call a "call" node in the supergraph - * @param callee a "called" "procedure" in the supergraph. if callee is null, answer return sites for which no callee was found. - * @return the corresponding return nodes. There may be many, because of exceptional control flow. - */ - Iterator getReturnSites(T call, P callee); - - /** - * @param r a "return" node in the supergraph - * @param callee a "called" "procedure" in the supergraph. if callee is null, answer return sites for which no callee was found. - * @return the corresponding call nodes. There may be many. - */ - Iterator getCallSites(T ret, P callee); - - /** - * @param n a node in the supergraph - * @return true iff this node is an exit node - */ - boolean isExit(T n); - - /** - * @param n a node in the supergraph - * @return an object which represents the procedure which contains n - */ - P getProcOf(T n); - - /** - * @return the blocks in the supergraph that represents entry nodes for procedure p - */ - T[] getEntriesForProcedure(P procedure); - - /** - * @return the blocks in the supergraph that represents exit nodes for procedure p - */ - T[] getExitsForProcedure(P procedure); - - /** - * @param procedure an object that represents a procedure - * @return the number of blocks from this procedure in this supergraph - */ - int getNumberOfBlocks(P procedure); - - /** - * @param n a node in the supergraph - * @return the "logical" basic block number of n in its procedure - */ - int getLocalBlockNumber(T n); - - /** - * @param procedure an object that represents a procedure - * @param i the "logical" basic block number of a node in the procedure - * @return the corresponding node in the supergraph - */ - T getLocalBlock(P procedure, int i); - - /** - * @param n a node in this supergraph - * @return true iff this node is a return site. - */ - boolean isReturn(T n); - - /** - * @return true iff this node is an entry node s_p for a procedure - */ - boolean isEntry(T n); - - /** - * @param src node in the supergraph - * @param dest a successor of src in the supergraph - * @return one of CALL_EDGE, RETURN_EDGE, CALL_TO_RETURN_EDGE, or OTHER - */ - byte classifyEdge(T src, T dest); - +/******************************************************************************* + * 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.dataflow.IFDS; + +import java.util.Iterator; + +import com.ibm.wala.util.graph.Graph; +import com.ibm.wala.util.graph.NumberedGraph; + +/** + * + * A supergraph as defined by Reps, Horwitz, and Sagiv POPL95 + *

        + * In our implementation we don't require explicit entry and exit nodes. So, the first basic block in a method is implicitly the + * entry node, but might also be a call node too. Similarly for exit nodes. The solver is coded to deal with this appropriately. + *

        + * Additionally, due to exceptional control flow, each method might have multiple exits or multiple entries. + * + * T type of node in the supergraph P type of a procedure (like a box in an RSM) + */ +public interface ISupergraph extends NumberedGraph { + + public static final byte CALL_EDGE = 0; + + public static final byte RETURN_EDGE = 1; + + public static final byte CALL_TO_RETURN_EDGE = 2; + + public static final byte OTHER = 3; + + /** + * @return the graph of procedures (e.g. a call graph) over which this supergraph is induced. + */ + Graph getProcedureGraph(); + + /** + * @param n a node in this supergraph + * @return true iff this node includes a call. + */ + boolean isCall(T n); + + /** + * @param call a "call" node in the supergraph + * @return an Iterator of nodes that are targets of this call. + */ + Iterator getCalledNodes(T call); + + /** + * @param call a "call" node in the supergraph + * @return an Iterator of nodes that are normal (non-call) successors of this call. This should only apply to backwards problems, + * where we might have, say, a call and a goto flow into a return site. + */ + Iterator getNormalSuccessors(T call); + + /** + * @param call a "call" node in the supergraph + * @param callee a "called" "procedure" in the supergraph. if callee is null, answer return sites for which no callee was found. + * @return the corresponding return nodes. There may be many, because of exceptional control flow. + */ + Iterator getReturnSites(T call, P callee); + + /** + * @param r a "return" node in the supergraph + * @param callee a "called" "procedure" in the supergraph. if callee is null, answer return sites for which no callee was found. + * @return the corresponding call nodes. There may be many. + */ + Iterator getCallSites(T ret, P callee); + + /** + * @param n a node in the supergraph + * @return true iff this node is an exit node + */ + boolean isExit(T n); + + /** + * @param n a node in the supergraph + * @return an object which represents the procedure which contains n + */ + P getProcOf(T n); + + /** + * @return the blocks in the supergraph that represents entry nodes for procedure p + */ + T[] getEntriesForProcedure(P procedure); + + /** + * @return the blocks in the supergraph that represents exit nodes for procedure p + */ + T[] getExitsForProcedure(P procedure); + + /** + * @param procedure an object that represents a procedure + * @return the number of blocks from this procedure in this supergraph + */ + int getNumberOfBlocks(P procedure); + + /** + * @param n a node in the supergraph + * @return the "logical" basic block number of n in its procedure + */ + int getLocalBlockNumber(T n); + + /** + * @param procedure an object that represents a procedure + * @param i the "logical" basic block number of a node in the procedure + * @return the corresponding node in the supergraph + */ + T getLocalBlock(P procedure, int i); + + /** + * @param n a node in this supergraph + * @return true iff this node is a return site. + */ + boolean isReturn(T n); + + /** + * @return true iff this node is an entry node s_p for a procedure + */ + boolean isEntry(T n); + + /** + * @param src node in the supergraph + * @param dest a successor of src in the supergraph + * @return one of CALL_EDGE, RETURN_EDGE, CALL_TO_RETURN_EDGE, or OTHER + */ + byte classifyEdge(T src, T dest); + } \ No newline at end of file diff --git a/com.ibm.wala.core/src/com/ibm/wala/dataflow/IFDS/ITabulationWorklist.java b/com.ibm.wala.core/src/com/ibm/wala/dataflow/IFDS/ITabulationWorklist.java index 3cad963ae..dfc38caae 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/dataflow/IFDS/ITabulationWorklist.java +++ b/com.ibm.wala.core/src/com/ibm/wala/dataflow/IFDS/ITabulationWorklist.java @@ -1,26 +1,26 @@ -/******************************************************************************* - * Copyright (c) 2008 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.dataflow.IFDS; - -/** - * @param represents type of nodes in the supergraph. - */ -public interface ITabulationWorklist { - - /** - * @return the first object in the priority queue - */ - PathEdge take(); - - public void insert(PathEdge elt); - - int size(); -} +/******************************************************************************* + * Copyright (c) 2008 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.dataflow.IFDS; + +/** + * @param represents type of nodes in the supergraph. + */ +public interface ITabulationWorklist { + + /** + * @return the first object in the priority queue + */ + PathEdge take(); + + public void insert(PathEdge elt); + + int size(); +} diff --git a/com.ibm.wala.core/src/com/ibm/wala/dataflow/IFDS/IUnaryFlowFunction.java b/com.ibm.wala.core/src/com/ibm/wala/dataflow/IFDS/IUnaryFlowFunction.java index b0d75ea75..adfc2ff54 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/dataflow/IFDS/IUnaryFlowFunction.java +++ b/com.ibm.wala.core/src/com/ibm/wala/dataflow/IFDS/IUnaryFlowFunction.java @@ -1,28 +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.dataflow.IFDS; - -import com.ibm.wala.util.intset.IntSet; - -/** - * A flow function corresponding to an edge in the supergraph. - * - * This function should be distributive for use with the Tabulation algorithm. - */ -public interface IUnaryFlowFunction extends IFlowFunction { - - /** - * @param d1 - * @return set of d2 such that (d1,d2) is an edge in this distributive function's graph representation, or null if there are none - */ - public IntSet getTargets(int d1); - -} +/******************************************************************************* + * 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.dataflow.IFDS; + +import com.ibm.wala.util.intset.IntSet; + +/** + * A flow function corresponding to an edge in the supergraph. + * + * This function should be distributive for use with the Tabulation algorithm. + */ +public interface IUnaryFlowFunction extends IFlowFunction { + + /** + * @param d1 + * @return set of d2 such that (d1,d2) is an edge in this distributive function's graph representation, or null if there are none + */ + public IntSet getTargets(int d1); + +} diff --git a/com.ibm.wala.core/src/com/ibm/wala/dataflow/IFDS/IdentityFlowFunction.java b/com.ibm.wala.core/src/com/ibm/wala/dataflow/IFDS/IdentityFlowFunction.java index eee64ebfa..24639e6eb 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/dataflow/IFDS/IdentityFlowFunction.java +++ b/com.ibm.wala.core/src/com/ibm/wala/dataflow/IFDS/IdentityFlowFunction.java @@ -1,39 +1,39 @@ -/******************************************************************************* - * Copyright (c) 2002 - 2006 IBM Corporation. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * IBM Corporation - initial API and implementation - *******************************************************************************/ -package com.ibm.wala.dataflow.IFDS; - -import com.ibm.wala.util.intset.SparseIntSet; - -/** - * A flow function where out == in - */ -public class IdentityFlowFunction implements IReversibleFlowFunction { - - private final static IdentityFlowFunction singleton = new IdentityFlowFunction(); - - public SparseIntSet getTargets(int i) { - return SparseIntSet.singleton(i); - } - - public SparseIntSet getSources(int i) { - return SparseIntSet.singleton(i); - } - - public static IdentityFlowFunction identity() { - return singleton; - } - - @Override - public String toString() { - return "Identity Flow"; - } - +/******************************************************************************* + * 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.dataflow.IFDS; + +import com.ibm.wala.util.intset.SparseIntSet; + +/** + * A flow function where out == in + */ +public class IdentityFlowFunction implements IReversibleFlowFunction { + + private final static IdentityFlowFunction singleton = new IdentityFlowFunction(); + + public SparseIntSet getTargets(int i) { + return SparseIntSet.singleton(i); + } + + public SparseIntSet getSources(int i) { + return SparseIntSet.singleton(i); + } + + public static IdentityFlowFunction identity() { + return singleton; + } + + @Override + public String toString() { + return "Identity Flow"; + } + } \ No newline at end of file diff --git a/com.ibm.wala.core/src/com/ibm/wala/dataflow/IFDS/IdentityFlowFunctions.java b/com.ibm.wala.core/src/com/ibm/wala/dataflow/IFDS/IdentityFlowFunctions.java index c36e9f7dc..902ead9d4 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/dataflow/IFDS/IdentityFlowFunctions.java +++ b/com.ibm.wala.core/src/com/ibm/wala/dataflow/IFDS/IdentityFlowFunctions.java @@ -1,67 +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.dataflow.IFDS; - -/** - * A silly debugging aid that always returns the identity flow function - */ -public class IdentityFlowFunctions implements IFlowFunctionMap { - - private final static IdentityFlowFunctions SINGLETON = new IdentityFlowFunctions(); - - @SuppressWarnings("unchecked") - public static IdentityFlowFunctions singleton() { - return SINGLETON; - } - - private IdentityFlowFunctions() { - } - - /* - * @see com.ibm.wala.dataflow.IFDS.IFlowFunctionMap#getNormalFlowFunction(java.lang.Object, java.lang.Object) - */ - public IUnaryFlowFunction getNormalFlowFunction(T src, T dest) { - return IdentityFlowFunction.identity(); - } - - /* - * @see com.ibm.wala.dataflow.IFDS.IFlowFunctionMap#getReturnFlowFunction(java.lang.Object, java.lang.Object, java.lang.Object) - */ - public IFlowFunction getReturnFlowFunction(T call, T src, T dest) { - return IdentityFlowFunction.identity(); - } - - /* - * @see com.ibm.wala.dataflow.IFDS.IFlowFunctionMap#getReturnFlowFunction(java.lang.Object, java.lang.Object, java.lang.Object) - */ - public IFlowFunction getReturnFlowFunction(T src, T dest) { - return IdentityFlowFunction.identity(); - } - - /* - * @see com.ibm.wala.dataflow.IFDS.IFlowFunctionMap#getCallToReturnFlowFunction(java.lang.Object, java.lang.Object) - */ - public IUnaryFlowFunction getCallToReturnFlowFunction(T src, T dest) { - return IdentityFlowFunction.identity(); - } - - /* - * @see com.ibm.wala.dataflow.IFDS.IFlowFunctionMap#getCallNoneToReturnFlowFunction(java.lang.Object, java.lang.Object) - */ - public IUnaryFlowFunction getCallNoneToReturnFlowFunction(T src, T dest) { - return IdentityFlowFunction.identity(); - } - - public IUnaryFlowFunction getCallFlowFunction(T src, T dest, T ret) { - return IdentityFlowFunction.identity(); - } - -} +/******************************************************************************* + * 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.dataflow.IFDS; + +/** + * A silly debugging aid that always returns the identity flow function + */ +public class IdentityFlowFunctions implements IFlowFunctionMap { + + private final static IdentityFlowFunctions SINGLETON = new IdentityFlowFunctions(); + + @SuppressWarnings("unchecked") + public static IdentityFlowFunctions singleton() { + return SINGLETON; + } + + private IdentityFlowFunctions() { + } + + /* + * @see com.ibm.wala.dataflow.IFDS.IFlowFunctionMap#getNormalFlowFunction(java.lang.Object, java.lang.Object) + */ + public IUnaryFlowFunction getNormalFlowFunction(T src, T dest) { + return IdentityFlowFunction.identity(); + } + + /* + * @see com.ibm.wala.dataflow.IFDS.IFlowFunctionMap#getReturnFlowFunction(java.lang.Object, java.lang.Object, java.lang.Object) + */ + public IFlowFunction getReturnFlowFunction(T call, T src, T dest) { + return IdentityFlowFunction.identity(); + } + + /* + * @see com.ibm.wala.dataflow.IFDS.IFlowFunctionMap#getReturnFlowFunction(java.lang.Object, java.lang.Object, java.lang.Object) + */ + public IFlowFunction getReturnFlowFunction(T src, T dest) { + return IdentityFlowFunction.identity(); + } + + /* + * @see com.ibm.wala.dataflow.IFDS.IFlowFunctionMap#getCallToReturnFlowFunction(java.lang.Object, java.lang.Object) + */ + public IUnaryFlowFunction getCallToReturnFlowFunction(T src, T dest) { + return IdentityFlowFunction.identity(); + } + + /* + * @see com.ibm.wala.dataflow.IFDS.IFlowFunctionMap#getCallNoneToReturnFlowFunction(java.lang.Object, java.lang.Object) + */ + public IUnaryFlowFunction getCallNoneToReturnFlowFunction(T src, T dest) { + return IdentityFlowFunction.identity(); + } + + public IUnaryFlowFunction getCallFlowFunction(T src, T dest, T ret) { + return IdentityFlowFunction.identity(); + } + +} diff --git a/com.ibm.wala.core/src/com/ibm/wala/dataflow/IFDS/LocalPathEdges.java b/com.ibm.wala.core/src/com/ibm/wala/dataflow/IFDS/LocalPathEdges.java index 8eb7e84f1..8dd4c39a0 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/dataflow/IFDS/LocalPathEdges.java +++ b/com.ibm.wala.core/src/com/ibm/wala/dataflow/IFDS/LocalPathEdges.java @@ -1,453 +1,453 @@ -/******************************************************************************* - * 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.dataflow.IFDS; - -import java.util.Iterator; - -import com.ibm.wala.util.collections.SparseVector; -import com.ibm.wala.util.intset.BasicNaturalRelation; -import com.ibm.wala.util.intset.BitVectorIntSet; -import com.ibm.wala.util.intset.IBinaryNaturalRelation; -import com.ibm.wala.util.intset.IntIterator; -import com.ibm.wala.util.intset.IntPair; -import com.ibm.wala.util.intset.IntSet; -import com.ibm.wala.util.intset.MutableSparseIntSet; -import com.ibm.wala.util.intset.SparseIntSet; - -/** - * A set of path edges for a particular procedure entry s_p. - */ -public class LocalPathEdges { - - /** - * Do paranoid error checking? (slow) - */ - private final static boolean PARANOID = false; - - /** - * A map from integer (d2) -> (IBinaryNonNegativeIntRelation) - * - * For fact d2, paths[d2] gives a relation R=(n,d1) s.t. ( -> ) is a path edge. - * - * Note that we handle paths of the form -> specially, below. We also handle paths of the form -> specially below. - * - * We choose this somewhat convoluted representation for the following reasons: 1) of the (n, d1, d2) tuple-space, we expect the - * set of n to be dense for a given (d1,d2) pair. However the pairs should be sparse. So, we set up so n is the first dimension of - * the int-relations, which are designed to be dense in the first dimension 2) we need to support getInverse(), so we design - * lookup to get the d1's for an (n,d2) pair. - * - * Note that this representation is not good for merges. See below. - * - * TODO: more representation optimization. A special representation for triples? sparse representations for CFG? exploit shorts - * for ints? - */ - private final SparseVector paths = new SparseVector(1, 1.1f); - - /** - * If this is non-null, it holds a redundant representation of the paths information, designed to make getReachable(II) faster. - * This is designed for algorithms that want to use frequent merges. While it's a shame to waste space, I don't want to compromise - * space or time of the non-merging IFDS solver, for which the original paths representation works well. Is there a better data - * structure tradeoff? - * - * A map from integer (d1) -> (IBinaryNonNegativeIntRelation) - * - * For fact d1, paths[d1] gives a relation R=(n,d2) s.t. ( -> ) is a path edge. - * - * - * We choose this somewhat convoluted representation for the following reasons: 1) of the (n, d1, d2) tuple-space, we expect the - * set of n to be dense for a given (d1,d2) pair. However the pairs should be sparse. So, we set up so n is the first dimension of - * the int-relations, which are designed to be dense in the first dimension 2) we need to support getReachable(), so we design - * lookup to get the d2's for an (n,d1) pair. - */ - private final SparseVector altPaths; - - /** - * a map from integer d1 -> int set. - * - * for fact d1, identityPaths[d1] gives the set of block numbers N s.t. for n \in N, -> is a path edge. - */ - private final SparseVector identityPaths = new SparseVector(1, 1.1f); - - /** - * a map from integer d2 -> int set - * - * for fact d2, zeroPaths[d2] gives the set of block numbers N s.t. for n \in N, -> is a path edge. - */ - private final SparseVector zeroPaths = new SparseVector(1, 1.1f); - - /** - * @param fastMerge if true, the representation uses extra space in order to support faster merge operations - */ - public LocalPathEdges(boolean fastMerge) { - altPaths = fastMerge ? new SparseVector(1, 1.1f) : null; - } - - /** - * Record that in this procedure we've discovered a same-level realizable path from (s_p,d_i) to (n,d_j) - * - * @param i - * @param n local block number of the basic block n - * - * @param j - */ - public void addPathEdge(int i, int n, int j) { - - if (i == 0) { - addZeroPathEdge(n, j); - } else { - if (i == j) { - addIdentityPathEdge(i, n); - } else { - IBinaryNaturalRelation R = paths.get(j); - if (R == null) { - // we expect the first dimension of R to be dense, the second sparse - R = new BasicNaturalRelation(new byte[] { BasicNaturalRelation.SIMPLE_SPACE_STINGY }, BasicNaturalRelation.TWO_LEVEL); - paths.set(j, R); - } - R.add(n, i); - - if (altPaths != null) { - IBinaryNaturalRelation R2 = altPaths.get(i); - if (R2 == null) { - // we expect the first dimension of R to be dense, the second sparse - R2 = new BasicNaturalRelation(new byte[] { BasicNaturalRelation.SIMPLE_SPACE_STINGY }, BasicNaturalRelation.TWO_LEVEL); - altPaths.set(i, R2); - } - R2.add(n, j); - } - - if (TabulationSolver.DEBUG_LEVEL > 1) { - // System.err.println("recording path edge, now d2=" + j + " has been reached from " + R); - } - } - } - } - - /** - * Record that in this procedure we've discovered a same-level realizable path from (s_p,i) to (n,i) - * - * @param n local block number of the basic block n - */ - private void addIdentityPathEdge(int i, int n) { - BitVectorIntSet s = (BitVectorIntSet) identityPaths.get(i); - if (s == null) { - s = new BitVectorIntSet(); - identityPaths.set(i, s); - } - s.add(n); - - if (altPaths != null) { - IBinaryNaturalRelation R2 = altPaths.get(i); - if (R2 == null) { - // we expect the first dimension of R to be dense, the second sparse - R2 = new BasicNaturalRelation(new byte[] { BasicNaturalRelation.SIMPLE_SPACE_STINGY }, BasicNaturalRelation.TWO_LEVEL); - altPaths.set(i, R2); - } - R2.add(n, i); - } - - if (TabulationSolver.DEBUG_LEVEL > 1) { - System.err.println("recording self-path edge, now d1= " + i + " reaches " + s); - } - } - - /** - * Record that in this procedure we've discovered a same-level realizable path from (s_p,0) to (n,d_j) - * - * @param n local block number of the basic block n - * - * @param j - */ - private void addZeroPathEdge(int n, int j) { - - BitVectorIntSet z = (BitVectorIntSet) zeroPaths.get(j); - if (z == null) { - z = new BitVectorIntSet(); - zeroPaths.set(j, z); - } - z.add(n); - if (altPaths != null) { - IBinaryNaturalRelation R = altPaths.get(0); - if (R == null) { - // we expect the first dimension of R to be dense, the second sparse - R = new BasicNaturalRelation(new byte[] { BasicNaturalRelation.SIMPLE_SPACE_STINGY }, BasicNaturalRelation.TWO_LEVEL); - altPaths.set(0, R); - } - R.add(n, j); - } - if (TabulationSolver.DEBUG_LEVEL > 1) { - System.err.println("recording 0-path edge, now d2= " + j + " reached at " + z); - } - } - - /** - * N.B: If we're using the ZERO_PATH_SHORT_CIRCUIT, then we may have -> implicitly represented since we also - * have -> . However, getInverse() will NOT return these implicit d1 bits in the result. This translates - * to saying that the caller had better not care about any other d1 other than d1==0 if d1==0 is present. This happens to be true - * in the single use of getInverse() in the tabulation solver, which uses getInverse() to propagate flow from an exit node back to - * the caller's return site(s). Since we know that we will see flow from fact 0 to the return sites(s), we don't care about other - * facts that may induce the same flow to the return site(s). - * - * @param n local block number of a basic block n - * @param d2 - * @return the sparse int set of d1 s.t. -> are recorded as path edges. null if none found - */ - public IntSet getInverse(int n, int d2) { - IBinaryNaturalRelation R = paths.get(d2); - BitVectorIntSet s = (BitVectorIntSet) identityPaths.get(d2); - BitVectorIntSet z = (BitVectorIntSet) zeroPaths.get(d2); - if (R == null) { - if (s == null) { - if (z == null) { - return null; - } else { - return z.contains(n) ? SparseIntSet.singleton(0) : null; - } - } else { - if (s.contains(n)) { - if (z == null) { - return SparseIntSet.singleton(d2); - } else { - return z.contains(n) ? SparseIntSet.pair(0, d2) : SparseIntSet.singleton(d2); - } - } else { - return null; - } - } - } else { - if (s == null) { - if (z == null) { - return R.getRelated(n); - } else { - if (z.contains(n)) { - IntSet related = R.getRelated(n); - if (related == null) { - return SparseIntSet.singleton(0); - } else { - MutableSparseIntSet result = MutableSparseIntSet.make(related); - result.add(0); - return result; - } - } else { - return R.getRelated(n); - } - } - } else { - if (s.contains(n)) { - IntSet related = R.getRelated(n); - if (related == null) { - if (z == null || !z.contains(n)) { - return SparseIntSet.singleton(d2); - } else { - return SparseIntSet.pair(0, d2); - } - } else { - MutableSparseIntSet result = MutableSparseIntSet.make(related); - result.add(d2); - if (z != null && z.contains(n)) { - result.add(0); - } - return result; - } - } else { - if (z == null || !z.contains(n)) { - return R.getRelated(n); - } else { - IntSet related = R.getRelated(n); - MutableSparseIntSet result = (related == null) ? MutableSparseIntSet.makeEmpty() : MutableSparseIntSet.make(related); - result.add(0); - return result; - } - } - } - } - } - - /** - * @param i - * @param n local block number of a basic block n - * @param j - * @return true iff we have a path edge -> - */ - public boolean contains(int i, int n, int j) { - - if (n < 0) { - throw new IllegalArgumentException("invalid n: " + n); - } - if (i == 0) { - BitVectorIntSet z = (BitVectorIntSet) zeroPaths.get(j); - if (z != null && z.contains(n)) { - return true; - } else { - return false; - } - } else { - if (i == j) { - BitVectorIntSet s = (BitVectorIntSet) identityPaths.get(i); - if (s != null && s.contains(n)) { - return true; - } else { - return false; - } - } else { - IBinaryNaturalRelation R = paths.get(j); - if (R == null) { - return false; - } - return R.contains(n, i); - } - } - } - - /** - * - * @param n - * @return set of d2 s.t. d1->d2 is a path edge for node n. - */ - public IntSet getReachable(int n, int d1) { - if (PARANOID) { - assert getReachableSlow(n, d1).sameValue(getReachableFast(n, d1)); - } - return (altPaths == null) ? getReachableSlow(n, d1) : getReachableFast(n, d1); - } - - /** - * Note that this is really slow!!! - * - * @return set of d2 s.t. d1->d2 is a path edge for node n - */ - private IntSet getReachableSlow(int n, int d1) { - MutableSparseIntSet result = MutableSparseIntSet.makeEmpty(); - if (paths.size() > 0) { - // this is convoluted on purpose for efficiency: to avoid random access to - // the sparse vector, we do parallel iteration with the vector's indices - // and contents. TODO: better data structure? - Iterator contents = paths.iterator(); - for (IntIterator it = paths.iterateIndices(); it.hasNext();) { - int d2 = it.next(); - IBinaryNaturalRelation R = (IBinaryNaturalRelation) contents.next(); - if (R != null && R.contains(n, d1)) { - result.add(d2); - } - } - } - if (identityPaths.size() > 0) { - BitVectorIntSet s = (BitVectorIntSet) identityPaths.get(d1); - if (s != null && s.contains(n)) { - result.add(d1); - } - } - if (d1 == 0 && zeroPaths.size() > 0) { - // this is convoluted on purpose for efficiency: to avoid random access to - // the sparse vector, we do parallel iteration with the vector's indices - // and contents. TODO: better data structure? - Iterator contents = zeroPaths.iterator(); - for (IntIterator it = zeroPaths.iterateIndices(); it.hasNext();) { - int d2 = it.next(); - BitVectorIntSet s = (BitVectorIntSet) contents.next(); - if (s != null && s.contains(n)) { - result.add(d2); - } - } - } - return result; - } - - /** - * @return set of d2 s.t. d1->d2 is a path edge for node n - */ - private IntSet getReachableFast(int n, int d1) { - - IBinaryNaturalRelation R = altPaths.get(d1); - if (R != null) { - return R.getRelated(n); - } - return null; - } - - /** - * TODO: optimize this based on altPaths - * - * @param n the local block number of a node - * @return set of d2 s.t \exists d1 s.t. d1->d2 is a path edge for node n - */ - public IntSet getReachable(int n) { - MutableSparseIntSet result = MutableSparseIntSet.makeEmpty(); - if (paths.size() > 0) { - // this is convoluted on purpose for efficiency: to avoid random access to - // the sparse vector, we do parallel iteration with the vector's indices - // and contents. TODO: better data structure? - Iterator contents = paths.iterator(); - for (IntIterator it = paths.iterateIndices(); it.hasNext();) { - int d2 = it.next(); - IBinaryNaturalRelation R = (IBinaryNaturalRelation) contents.next(); - if (R != null && R.anyRelated(n)) { - result.add(d2); - } - } - } - if (identityPaths.size() > 0) { - // this is convoluted on purpose for efficiency: to avoid random access to - // the sparse vector, we do parallel iteration with the vector's indices - // and contents. TODO: better data structure? - Iterator contents = identityPaths.iterator(); - for (IntIterator it = identityPaths.iterateIndices(); it.hasNext();) { - int d1 = it.next(); - BitVectorIntSet s = (BitVectorIntSet) contents.next(); - if (s != null && s.contains(n)) { - result.add(d1); - } - } - } - if (zeroPaths.size() > 0) { - // this is convoluted on purpose for efficiency: to avoid random access to - // the sparse vector, we do parallel iteration with the vector's indices - // and contents. TODO: better data structure? - Iterator contents = zeroPaths.iterator(); - for (IntIterator it = zeroPaths.iterateIndices(); it.hasNext();) { - int d2 = it.next(); - BitVectorIntSet s = (BitVectorIntSet) contents.next(); - if (s != null && s.contains(n)) { - result.add(d2); - } - } - } - return result; - } - - /** - * TODO: optimize this - * - * @return set of node numbers that are reached by any fact - */ - public IntSet getReachedNodeNumbers() { - MutableSparseIntSet result = MutableSparseIntSet.makeEmpty(); - if (paths.size() > 0) { - for (IBinaryNaturalRelation R : paths) { - for (IntPair p : R) { - result.add(p.getX()); - } - } - } - if (identityPaths.size() > 0) { - for (IntSet s : identityPaths) { - result.addAll(s); - } - } - if (zeroPaths.size() > 0) { - for (IntSet s : zeroPaths) { - result.addAll(s); - } - } - return result; - } +/******************************************************************************* + * 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.dataflow.IFDS; + +import java.util.Iterator; + +import com.ibm.wala.util.collections.SparseVector; +import com.ibm.wala.util.intset.BasicNaturalRelation; +import com.ibm.wala.util.intset.BitVectorIntSet; +import com.ibm.wala.util.intset.IBinaryNaturalRelation; +import com.ibm.wala.util.intset.IntIterator; +import com.ibm.wala.util.intset.IntPair; +import com.ibm.wala.util.intset.IntSet; +import com.ibm.wala.util.intset.MutableSparseIntSet; +import com.ibm.wala.util.intset.SparseIntSet; + +/** + * A set of path edges for a particular procedure entry s_p. + */ +public class LocalPathEdges { + + /** + * Do paranoid error checking? (slow) + */ + private final static boolean PARANOID = false; + + /** + * A map from integer (d2) -> (IBinaryNonNegativeIntRelation) + * + * For fact d2, paths[d2] gives a relation R=(n,d1) s.t. ( -> ) is a path edge. + * + * Note that we handle paths of the form -> specially, below. We also handle paths of the form -> specially below. + * + * We choose this somewhat convoluted representation for the following reasons: 1) of the (n, d1, d2) tuple-space, we expect the + * set of n to be dense for a given (d1,d2) pair. However the pairs should be sparse. So, we set up so n is the first dimension of + * the int-relations, which are designed to be dense in the first dimension 2) we need to support getInverse(), so we design + * lookup to get the d1's for an (n,d2) pair. + * + * Note that this representation is not good for merges. See below. + * + * TODO: more representation optimization. A special representation for triples? sparse representations for CFG? exploit shorts + * for ints? + */ + private final SparseVector paths = new SparseVector(1, 1.1f); + + /** + * If this is non-null, it holds a redundant representation of the paths information, designed to make getReachable(II) faster. + * This is designed for algorithms that want to use frequent merges. While it's a shame to waste space, I don't want to compromise + * space or time of the non-merging IFDS solver, for which the original paths representation works well. Is there a better data + * structure tradeoff? + * + * A map from integer (d1) -> (IBinaryNonNegativeIntRelation) + * + * For fact d1, paths[d1] gives a relation R=(n,d2) s.t. ( -> ) is a path edge. + * + * + * We choose this somewhat convoluted representation for the following reasons: 1) of the (n, d1, d2) tuple-space, we expect the + * set of n to be dense for a given (d1,d2) pair. However the pairs should be sparse. So, we set up so n is the first dimension of + * the int-relations, which are designed to be dense in the first dimension 2) we need to support getReachable(), so we design + * lookup to get the d2's for an (n,d1) pair. + */ + private final SparseVector altPaths; + + /** + * a map from integer d1 -> int set. + * + * for fact d1, identityPaths[d1] gives the set of block numbers N s.t. for n \in N, -> is a path edge. + */ + private final SparseVector identityPaths = new SparseVector(1, 1.1f); + + /** + * a map from integer d2 -> int set + * + * for fact d2, zeroPaths[d2] gives the set of block numbers N s.t. for n \in N, -> is a path edge. + */ + private final SparseVector zeroPaths = new SparseVector(1, 1.1f); + + /** + * @param fastMerge if true, the representation uses extra space in order to support faster merge operations + */ + public LocalPathEdges(boolean fastMerge) { + altPaths = fastMerge ? new SparseVector(1, 1.1f) : null; + } + + /** + * Record that in this procedure we've discovered a same-level realizable path from (s_p,d_i) to (n,d_j) + * + * @param i + * @param n local block number of the basic block n + * + * @param j + */ + public void addPathEdge(int i, int n, int j) { + + if (i == 0) { + addZeroPathEdge(n, j); + } else { + if (i == j) { + addIdentityPathEdge(i, n); + } else { + IBinaryNaturalRelation R = paths.get(j); + if (R == null) { + // we expect the first dimension of R to be dense, the second sparse + R = new BasicNaturalRelation(new byte[] { BasicNaturalRelation.SIMPLE_SPACE_STINGY }, BasicNaturalRelation.TWO_LEVEL); + paths.set(j, R); + } + R.add(n, i); + + if (altPaths != null) { + IBinaryNaturalRelation R2 = altPaths.get(i); + if (R2 == null) { + // we expect the first dimension of R to be dense, the second sparse + R2 = new BasicNaturalRelation(new byte[] { BasicNaturalRelation.SIMPLE_SPACE_STINGY }, BasicNaturalRelation.TWO_LEVEL); + altPaths.set(i, R2); + } + R2.add(n, j); + } + + if (TabulationSolver.DEBUG_LEVEL > 1) { + // System.err.println("recording path edge, now d2=" + j + " has been reached from " + R); + } + } + } + } + + /** + * Record that in this procedure we've discovered a same-level realizable path from (s_p,i) to (n,i) + * + * @param n local block number of the basic block n + */ + private void addIdentityPathEdge(int i, int n) { + BitVectorIntSet s = (BitVectorIntSet) identityPaths.get(i); + if (s == null) { + s = new BitVectorIntSet(); + identityPaths.set(i, s); + } + s.add(n); + + if (altPaths != null) { + IBinaryNaturalRelation R2 = altPaths.get(i); + if (R2 == null) { + // we expect the first dimension of R to be dense, the second sparse + R2 = new BasicNaturalRelation(new byte[] { BasicNaturalRelation.SIMPLE_SPACE_STINGY }, BasicNaturalRelation.TWO_LEVEL); + altPaths.set(i, R2); + } + R2.add(n, i); + } + + if (TabulationSolver.DEBUG_LEVEL > 1) { + System.err.println("recording self-path edge, now d1= " + i + " reaches " + s); + } + } + + /** + * Record that in this procedure we've discovered a same-level realizable path from (s_p,0) to (n,d_j) + * + * @param n local block number of the basic block n + * + * @param j + */ + private void addZeroPathEdge(int n, int j) { + + BitVectorIntSet z = (BitVectorIntSet) zeroPaths.get(j); + if (z == null) { + z = new BitVectorIntSet(); + zeroPaths.set(j, z); + } + z.add(n); + if (altPaths != null) { + IBinaryNaturalRelation R = altPaths.get(0); + if (R == null) { + // we expect the first dimension of R to be dense, the second sparse + R = new BasicNaturalRelation(new byte[] { BasicNaturalRelation.SIMPLE_SPACE_STINGY }, BasicNaturalRelation.TWO_LEVEL); + altPaths.set(0, R); + } + R.add(n, j); + } + if (TabulationSolver.DEBUG_LEVEL > 1) { + System.err.println("recording 0-path edge, now d2= " + j + " reached at " + z); + } + } + + /** + * N.B: If we're using the ZERO_PATH_SHORT_CIRCUIT, then we may have -> implicitly represented since we also + * have -> . However, getInverse() will NOT return these implicit d1 bits in the result. This translates + * to saying that the caller had better not care about any other d1 other than d1==0 if d1==0 is present. This happens to be true + * in the single use of getInverse() in the tabulation solver, which uses getInverse() to propagate flow from an exit node back to + * the caller's return site(s). Since we know that we will see flow from fact 0 to the return sites(s), we don't care about other + * facts that may induce the same flow to the return site(s). + * + * @param n local block number of a basic block n + * @param d2 + * @return the sparse int set of d1 s.t. -> are recorded as path edges. null if none found + */ + public IntSet getInverse(int n, int d2) { + IBinaryNaturalRelation R = paths.get(d2); + BitVectorIntSet s = (BitVectorIntSet) identityPaths.get(d2); + BitVectorIntSet z = (BitVectorIntSet) zeroPaths.get(d2); + if (R == null) { + if (s == null) { + if (z == null) { + return null; + } else { + return z.contains(n) ? SparseIntSet.singleton(0) : null; + } + } else { + if (s.contains(n)) { + if (z == null) { + return SparseIntSet.singleton(d2); + } else { + return z.contains(n) ? SparseIntSet.pair(0, d2) : SparseIntSet.singleton(d2); + } + } else { + return null; + } + } + } else { + if (s == null) { + if (z == null) { + return R.getRelated(n); + } else { + if (z.contains(n)) { + IntSet related = R.getRelated(n); + if (related == null) { + return SparseIntSet.singleton(0); + } else { + MutableSparseIntSet result = MutableSparseIntSet.make(related); + result.add(0); + return result; + } + } else { + return R.getRelated(n); + } + } + } else { + if (s.contains(n)) { + IntSet related = R.getRelated(n); + if (related == null) { + if (z == null || !z.contains(n)) { + return SparseIntSet.singleton(d2); + } else { + return SparseIntSet.pair(0, d2); + } + } else { + MutableSparseIntSet result = MutableSparseIntSet.make(related); + result.add(d2); + if (z != null && z.contains(n)) { + result.add(0); + } + return result; + } + } else { + if (z == null || !z.contains(n)) { + return R.getRelated(n); + } else { + IntSet related = R.getRelated(n); + MutableSparseIntSet result = (related == null) ? MutableSparseIntSet.makeEmpty() : MutableSparseIntSet.make(related); + result.add(0); + return result; + } + } + } + } + } + + /** + * @param i + * @param n local block number of a basic block n + * @param j + * @return true iff we have a path edge -> + */ + public boolean contains(int i, int n, int j) { + + if (n < 0) { + throw new IllegalArgumentException("invalid n: " + n); + } + if (i == 0) { + BitVectorIntSet z = (BitVectorIntSet) zeroPaths.get(j); + if (z != null && z.contains(n)) { + return true; + } else { + return false; + } + } else { + if (i == j) { + BitVectorIntSet s = (BitVectorIntSet) identityPaths.get(i); + if (s != null && s.contains(n)) { + return true; + } else { + return false; + } + } else { + IBinaryNaturalRelation R = paths.get(j); + if (R == null) { + return false; + } + return R.contains(n, i); + } + } + } + + /** + * + * @param n + * @return set of d2 s.t. d1->d2 is a path edge for node n. + */ + public IntSet getReachable(int n, int d1) { + if (PARANOID) { + assert getReachableSlow(n, d1).sameValue(getReachableFast(n, d1)); + } + return (altPaths == null) ? getReachableSlow(n, d1) : getReachableFast(n, d1); + } + + /** + * Note that this is really slow!!! + * + * @return set of d2 s.t. d1->d2 is a path edge for node n + */ + private IntSet getReachableSlow(int n, int d1) { + MutableSparseIntSet result = MutableSparseIntSet.makeEmpty(); + if (paths.size() > 0) { + // this is convoluted on purpose for efficiency: to avoid random access to + // the sparse vector, we do parallel iteration with the vector's indices + // and contents. TODO: better data structure? + Iterator contents = paths.iterator(); + for (IntIterator it = paths.iterateIndices(); it.hasNext();) { + int d2 = it.next(); + IBinaryNaturalRelation R = (IBinaryNaturalRelation) contents.next(); + if (R != null && R.contains(n, d1)) { + result.add(d2); + } + } + } + if (identityPaths.size() > 0) { + BitVectorIntSet s = (BitVectorIntSet) identityPaths.get(d1); + if (s != null && s.contains(n)) { + result.add(d1); + } + } + if (d1 == 0 && zeroPaths.size() > 0) { + // this is convoluted on purpose for efficiency: to avoid random access to + // the sparse vector, we do parallel iteration with the vector's indices + // and contents. TODO: better data structure? + Iterator contents = zeroPaths.iterator(); + for (IntIterator it = zeroPaths.iterateIndices(); it.hasNext();) { + int d2 = it.next(); + BitVectorIntSet s = (BitVectorIntSet) contents.next(); + if (s != null && s.contains(n)) { + result.add(d2); + } + } + } + return result; + } + + /** + * @return set of d2 s.t. d1->d2 is a path edge for node n + */ + private IntSet getReachableFast(int n, int d1) { + + IBinaryNaturalRelation R = altPaths.get(d1); + if (R != null) { + return R.getRelated(n); + } + return null; + } + + /** + * TODO: optimize this based on altPaths + * + * @param n the local block number of a node + * @return set of d2 s.t \exists d1 s.t. d1->d2 is a path edge for node n + */ + public IntSet getReachable(int n) { + MutableSparseIntSet result = MutableSparseIntSet.makeEmpty(); + if (paths.size() > 0) { + // this is convoluted on purpose for efficiency: to avoid random access to + // the sparse vector, we do parallel iteration with the vector's indices + // and contents. TODO: better data structure? + Iterator contents = paths.iterator(); + for (IntIterator it = paths.iterateIndices(); it.hasNext();) { + int d2 = it.next(); + IBinaryNaturalRelation R = (IBinaryNaturalRelation) contents.next(); + if (R != null && R.anyRelated(n)) { + result.add(d2); + } + } + } + if (identityPaths.size() > 0) { + // this is convoluted on purpose for efficiency: to avoid random access to + // the sparse vector, we do parallel iteration with the vector's indices + // and contents. TODO: better data structure? + Iterator contents = identityPaths.iterator(); + for (IntIterator it = identityPaths.iterateIndices(); it.hasNext();) { + int d1 = it.next(); + BitVectorIntSet s = (BitVectorIntSet) contents.next(); + if (s != null && s.contains(n)) { + result.add(d1); + } + } + } + if (zeroPaths.size() > 0) { + // this is convoluted on purpose for efficiency: to avoid random access to + // the sparse vector, we do parallel iteration with the vector's indices + // and contents. TODO: better data structure? + Iterator contents = zeroPaths.iterator(); + for (IntIterator it = zeroPaths.iterateIndices(); it.hasNext();) { + int d2 = it.next(); + BitVectorIntSet s = (BitVectorIntSet) contents.next(); + if (s != null && s.contains(n)) { + result.add(d2); + } + } + } + return result; + } + + /** + * TODO: optimize this + * + * @return set of node numbers that are reached by any fact + */ + public IntSet getReachedNodeNumbers() { + MutableSparseIntSet result = MutableSparseIntSet.makeEmpty(); + if (paths.size() > 0) { + for (IBinaryNaturalRelation R : paths) { + for (IntPair p : R) { + result.add(p.getX()); + } + } + } + if (identityPaths.size() > 0) { + for (IntSet s : identityPaths) { + result.addAll(s); + } + } + if (zeroPaths.size() > 0) { + for (IntSet s : zeroPaths) { + result.addAll(s); + } + } + return result; + } } \ No newline at end of file diff --git a/com.ibm.wala.core/src/com/ibm/wala/dataflow/IFDS/LocalSummaryEdges.java b/com.ibm.wala.core/src/com/ibm/wala/dataflow/IFDS/LocalSummaryEdges.java index 0c1a6c8e2..1fb5434eb 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/dataflow/IFDS/LocalSummaryEdges.java +++ b/com.ibm.wala.core/src/com/ibm/wala/dataflow/IFDS/LocalSummaryEdges.java @@ -1,159 +1,159 @@ -/******************************************************************************* - * 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.dataflow.IFDS; - -import java.util.Iterator; - -import com.ibm.wala.util.collections.SparseVector; -import com.ibm.wala.util.intset.BasicNaturalRelation; -import com.ibm.wala.util.intset.IBinaryNaturalRelation; -import com.ibm.wala.util.intset.IntPair; -import com.ibm.wala.util.intset.IntSet; -import com.ibm.wala.util.intset.MutableSparseIntSet; -import com.ibm.wala.util.intset.SparseLongIntVector; -import com.ibm.wala.util.math.LongUtil; - -/** - * A set of summary edges for a particular procedure. - */ -public class LocalSummaryEdges { - - /** - * A map from integer n -> (IBinaryNonNegativeIntRelation) - * - * Let s_p be an entry to this procedure, and x be an exit. n is a integer which uniquely identifies an (s_p,x) relation. For any - * such n, summaries[n] gives a relation R=(d1,d2) s.t. ( -> ) is a summary edge. - * - * Note that this representation is a little different from the representation described in the PoPL 95 paper. We cache summary - * edges at the CALLEE, not at the CALLER!!! This allows us to avoid eagerly installing summary edges at all call sites to a - * procedure, which may be a win. - * - * we don't technically need this class, since this information is redundantly stored in LocalPathEdges. However, we're keeping it - * cached for now for more efficient access when looking up summary edges. - * - * TODO: more representation optimization. - */ - private final SparseVector summaries = new SparseVector(1, 1.1f); - - /** - * Let (s_p,x) be an entry-exit pair, and let l := the long whose high word is s_p and low word is x. - * - * Then entryExitMap(l) is an int which uniquely identifies (s_p,x) - * - * we populate this map on demand! - */ - private final static int UNASSIGNED = -1; - - private final SparseLongIntVector entryExitMap = new SparseLongIntVector(UNASSIGNED); - - private int nextEntryExitIndex = 0; - - /** - * - */ - public LocalSummaryEdges() { - } - - /** - * Record a summary edge for the flow d1 -> d2 from an entry s_p to an exit x. - * - * @param s_p local block number an entry - * @param x local block number of an exit block - * @param d1 source dataflow fact - * @param d2 target dataflow fact - */ - public void insertSummaryEdge(int s_p, int x, int d1, int d2) { - int n = getIndexForEntryExitPair(s_p, x); - IBinaryNaturalRelation R = summaries.get(n); - if (R == null) { - // we expect R to usually be sparse - R = new BasicNaturalRelation(new byte[] { BasicNaturalRelation.SIMPLE_SPACE_STINGY }, BasicNaturalRelation.SIMPLE); - summaries.set(n, R); - } - R.add(d1, d2); - if (TabulationSolver.DEBUG_LEVEL > 1) { - // System.err.println("recording summary edge, now n=" + n + " summarized by " + R); - } - } - - /** - * Does a particular summary edge exist? - * - * @param s_p local block number an entry - * @param x local block number of an exit block - * @param d1 source dataflow fact - * @param d2 target dataflow fact - */ - public boolean contains(int s_p, int x, int d1, int d2) { - int n = getIndexForEntryExitPair(s_p, x); - IBinaryNaturalRelation R = summaries.get(n); - if (R == null) { - return false; - } else { - return R.contains(d1, d2); - } - } - - /** - * @param s_p local block number an entry - * @param x local block number of an exit block - * @param d1 source dataflow fact - * @return set of d2 s.t. d1->d2 recorded as a summary edge for (s_p,x), or null if none - */ - public IntSet getSummaryEdges(int s_p, int x, int d1) { - int n = getIndexForEntryExitPair(s_p, x); - IBinaryNaturalRelation R = summaries.get(n); - if (R == null) { - return null; - } else { - return R.getRelated(d1); - } - } - - /** - * Note: This is inefficient. Use with care. - * - * @param s_p local block number an entry - * @param x local block number of an exit block - * @param d2 target dataflow fact - * @return set of d1 s.t. d1->d2 recorded as a summary edge for (s_p,x), or null if none - */ - public IntSet getInvertedSummaryEdgesForTarget(int s_p, int x, int d2) { - int n = getIndexForEntryExitPair(s_p, x); - IBinaryNaturalRelation R = summaries.get(n); - if (R == null) { - return null; - } else { - MutableSparseIntSet result = MutableSparseIntSet.makeEmpty(); - for (Iterator it = R.iterator(); it.hasNext();) { - IntPair p = (IntPair) it.next(); - if (p.getY() == d2) { - result.add(p.getX()); - } - } - return result; - } - } - - /** - * @return unique id n that represents the pair (s_p,x) - */ - private int getIndexForEntryExitPair(int c, int r) { - long id = LongUtil.pack(c, r); - int result = entryExitMap.get(id); - if (result == UNASSIGNED) { - result = nextEntryExitIndex++; - entryExitMap.set(id, result); - } - return result; - } - +/******************************************************************************* + * 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.dataflow.IFDS; + +import java.util.Iterator; + +import com.ibm.wala.util.collections.SparseVector; +import com.ibm.wala.util.intset.BasicNaturalRelation; +import com.ibm.wala.util.intset.IBinaryNaturalRelation; +import com.ibm.wala.util.intset.IntPair; +import com.ibm.wala.util.intset.IntSet; +import com.ibm.wala.util.intset.MutableSparseIntSet; +import com.ibm.wala.util.intset.SparseLongIntVector; +import com.ibm.wala.util.math.LongUtil; + +/** + * A set of summary edges for a particular procedure. + */ +public class LocalSummaryEdges { + + /** + * A map from integer n -> (IBinaryNonNegativeIntRelation) + * + * Let s_p be an entry to this procedure, and x be an exit. n is a integer which uniquely identifies an (s_p,x) relation. For any + * such n, summaries[n] gives a relation R=(d1,d2) s.t. ( -> ) is a summary edge. + * + * Note that this representation is a little different from the representation described in the PoPL 95 paper. We cache summary + * edges at the CALLEE, not at the CALLER!!! This allows us to avoid eagerly installing summary edges at all call sites to a + * procedure, which may be a win. + * + * we don't technically need this class, since this information is redundantly stored in LocalPathEdges. However, we're keeping it + * cached for now for more efficient access when looking up summary edges. + * + * TODO: more representation optimization. + */ + private final SparseVector summaries = new SparseVector(1, 1.1f); + + /** + * Let (s_p,x) be an entry-exit pair, and let l := the long whose high word is s_p and low word is x. + * + * Then entryExitMap(l) is an int which uniquely identifies (s_p,x) + * + * we populate this map on demand! + */ + private final static int UNASSIGNED = -1; + + private final SparseLongIntVector entryExitMap = new SparseLongIntVector(UNASSIGNED); + + private int nextEntryExitIndex = 0; + + /** + * + */ + public LocalSummaryEdges() { + } + + /** + * Record a summary edge for the flow d1 -> d2 from an entry s_p to an exit x. + * + * @param s_p local block number an entry + * @param x local block number of an exit block + * @param d1 source dataflow fact + * @param d2 target dataflow fact + */ + public void insertSummaryEdge(int s_p, int x, int d1, int d2) { + int n = getIndexForEntryExitPair(s_p, x); + IBinaryNaturalRelation R = summaries.get(n); + if (R == null) { + // we expect R to usually be sparse + R = new BasicNaturalRelation(new byte[] { BasicNaturalRelation.SIMPLE_SPACE_STINGY }, BasicNaturalRelation.SIMPLE); + summaries.set(n, R); + } + R.add(d1, d2); + if (TabulationSolver.DEBUG_LEVEL > 1) { + // System.err.println("recording summary edge, now n=" + n + " summarized by " + R); + } + } + + /** + * Does a particular summary edge exist? + * + * @param s_p local block number an entry + * @param x local block number of an exit block + * @param d1 source dataflow fact + * @param d2 target dataflow fact + */ + public boolean contains(int s_p, int x, int d1, int d2) { + int n = getIndexForEntryExitPair(s_p, x); + IBinaryNaturalRelation R = summaries.get(n); + if (R == null) { + return false; + } else { + return R.contains(d1, d2); + } + } + + /** + * @param s_p local block number an entry + * @param x local block number of an exit block + * @param d1 source dataflow fact + * @return set of d2 s.t. d1->d2 recorded as a summary edge for (s_p,x), or null if none + */ + public IntSet getSummaryEdges(int s_p, int x, int d1) { + int n = getIndexForEntryExitPair(s_p, x); + IBinaryNaturalRelation R = summaries.get(n); + if (R == null) { + return null; + } else { + return R.getRelated(d1); + } + } + + /** + * Note: This is inefficient. Use with care. + * + * @param s_p local block number an entry + * @param x local block number of an exit block + * @param d2 target dataflow fact + * @return set of d1 s.t. d1->d2 recorded as a summary edge for (s_p,x), or null if none + */ + public IntSet getInvertedSummaryEdgesForTarget(int s_p, int x, int d2) { + int n = getIndexForEntryExitPair(s_p, x); + IBinaryNaturalRelation R = summaries.get(n); + if (R == null) { + return null; + } else { + MutableSparseIntSet result = MutableSparseIntSet.makeEmpty(); + for (Iterator it = R.iterator(); it.hasNext();) { + IntPair p = (IntPair) it.next(); + if (p.getY() == d2) { + result.add(p.getX()); + } + } + return result; + } + } + + /** + * @return unique id n that represents the pair (s_p,x) + */ + private int getIndexForEntryExitPair(int c, int r) { + long id = LongUtil.pack(c, r); + int result = entryExitMap.get(id); + if (result == UNASSIGNED) { + result = nextEntryExitIndex++; + entryExitMap.set(id, result); + } + return result; + } + } \ No newline at end of file diff --git a/com.ibm.wala.core/src/com/ibm/wala/dataflow/IFDS/PartiallyBalancedTabulationProblem.java b/com.ibm.wala.core/src/com/ibm/wala/dataflow/IFDS/PartiallyBalancedTabulationProblem.java index 58474fb13..339c56092 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/dataflow/IFDS/PartiallyBalancedTabulationProblem.java +++ b/com.ibm.wala.core/src/com/ibm/wala/dataflow/IFDS/PartiallyBalancedTabulationProblem.java @@ -1,30 +1,30 @@ -/******************************************************************************* - * Copyright (c) 2007 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.dataflow.IFDS; - -/** - * A {@link TabulationProblem} with additional support for computing with partially balanced parentheses. - * - * @param type of node in the supergraph - * @param

        type of a procedure (like a box in an RSM) - * @param type of factoids propagated when solving this problem - * - */ -public interface PartiallyBalancedTabulationProblem extends TabulationProblem { - - public IPartiallyBalancedFlowFunctions getFunctionMap(); - - /** - * If n is reached by a partially balanced parenthesis, what is the entry node we should use as the root of the {@link PathEdge} - * to n? Note that the result must in fact be an entry node of the procedure containing n. - */ - public T getFakeEntry(T n); -} +/******************************************************************************* + * Copyright (c) 2007 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.dataflow.IFDS; + +/** + * A {@link TabulationProblem} with additional support for computing with partially balanced parentheses. + * + * @param type of node in the supergraph + * @param

        type of a procedure (like a box in an RSM) + * @param type of factoids propagated when solving this problem + * + */ +public interface PartiallyBalancedTabulationProblem extends TabulationProblem { + + public IPartiallyBalancedFlowFunctions getFunctionMap(); + + /** + * If n is reached by a partially balanced parenthesis, what is the entry node we should use as the root of the {@link PathEdge} + * to n? Note that the result must in fact be an entry node of the procedure containing n. + */ + public T getFakeEntry(T n); +} diff --git a/com.ibm.wala.core/src/com/ibm/wala/dataflow/IFDS/PartiallyBalancedTabulationSolver.java b/com.ibm.wala.core/src/com/ibm/wala/dataflow/IFDS/PartiallyBalancedTabulationSolver.java index 6efc85c2c..02813dff3 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/dataflow/IFDS/PartiallyBalancedTabulationSolver.java +++ b/com.ibm.wala.core/src/com/ibm/wala/dataflow/IFDS/PartiallyBalancedTabulationSolver.java @@ -1,91 +1,91 @@ -/******************************************************************************* - * 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 com.ibm.wala.dataflow.IFDS; - -import java.util.Collection; -import java.util.Iterator; - -import com.ibm.wala.util.MonitorUtil.IProgressMonitor; -import com.ibm.wala.util.collections.HashSetFactory; -import com.ibm.wala.util.collections.Pair; -import com.ibm.wala.util.debug.Assertions; -import com.ibm.wala.util.intset.IntIterator; -import com.ibm.wala.util.intset.IntSet; - -/** - * Utilities for dealing with tabulation with partially balanced parentheses. - * - * @param type of node in the supergraph - * @param

        type of a procedure (like a box in an RSM) - * @param type of factoids propagated when solving this problem - */ -public class PartiallyBalancedTabulationSolver extends TabulationSolver { - - public static PartiallyBalancedTabulationSolver createPartiallyBalancedTabulationSolver( - PartiallyBalancedTabulationProblem p, IProgressMonitor monitor) { - return new PartiallyBalancedTabulationSolver(p, monitor); - } - - private final Collection> unbalancedSeeds = HashSetFactory.make(); - - protected PartiallyBalancedTabulationSolver(PartiallyBalancedTabulationProblem p, IProgressMonitor monitor) { - super(p, monitor); - } - - @Override - protected boolean propagate(T s_p, int i, T n, int j) { - boolean result = super.propagate(s_p, i, n, j); - if (result && wasUsedAsUnbalancedSeed(s_p, i) && supergraph.isExit(n)) { - // j was reached from an entry seed. if there are any facts which are reachable from j, even without - // balanced parentheses, we can use these as new seeds. - for (Iterator it2 = supergraph.getSuccNodes(n); it2.hasNext();) { - T retSite = it2.next(); - PartiallyBalancedTabulationProblem problem = (PartiallyBalancedTabulationProblem) getProblem(); - IFlowFunction f = problem.getFunctionMap().getUnbalancedReturnFlowFunction(n, retSite); - // for each fact that can be reached by the return flow ... - if (f instanceof IUnaryFlowFunction) { - IUnaryFlowFunction uf = (IUnaryFlowFunction) f; - IntSet facts = uf.getTargets(j); - if (facts != null) { - for (IntIterator it4 = facts.intIterator(); it4.hasNext();) { - int d3 = it4.next(); - // d3 would be reached if we ignored parentheses. use it as a new seed. - T fakeEntry = problem.getFakeEntry(retSite); - PathEdge seed = PathEdge.createPathEdge(fakeEntry, d3, retSite, d3); - addSeed(seed); - } - } - } else { - Assertions.UNREACHABLE("Partially balanced logic not supported for binary return flow functions"); - } - } - } - return result; - } - - @Override - public void addSeed(PathEdge seed) { - if (getSeeds().contains(seed)) { - return; - } - unbalancedSeeds.add(Pair.make(seed.entry, seed.d1)); - super.addSeed(seed); - - } - - /** - * Was the fact number i named at node s_p introduced as an "unbalanced" seed during partial tabulation? - * If so, any facts "reached" from here can be further propagated with unbalanced parens. - */ - private boolean wasUsedAsUnbalancedSeed(T s_p, int i) { - return unbalancedSeeds.contains(Pair.make(s_p, i)); - } -} +/******************************************************************************* + * 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 com.ibm.wala.dataflow.IFDS; + +import java.util.Collection; +import java.util.Iterator; + +import com.ibm.wala.util.MonitorUtil.IProgressMonitor; +import com.ibm.wala.util.collections.HashSetFactory; +import com.ibm.wala.util.collections.Pair; +import com.ibm.wala.util.debug.Assertions; +import com.ibm.wala.util.intset.IntIterator; +import com.ibm.wala.util.intset.IntSet; + +/** + * Utilities for dealing with tabulation with partially balanced parentheses. + * + * @param type of node in the supergraph + * @param

        type of a procedure (like a box in an RSM) + * @param type of factoids propagated when solving this problem + */ +public class PartiallyBalancedTabulationSolver extends TabulationSolver { + + public static PartiallyBalancedTabulationSolver createPartiallyBalancedTabulationSolver( + PartiallyBalancedTabulationProblem p, IProgressMonitor monitor) { + return new PartiallyBalancedTabulationSolver(p, monitor); + } + + private final Collection> unbalancedSeeds = HashSetFactory.make(); + + protected PartiallyBalancedTabulationSolver(PartiallyBalancedTabulationProblem p, IProgressMonitor monitor) { + super(p, monitor); + } + + @Override + protected boolean propagate(T s_p, int i, T n, int j) { + boolean result = super.propagate(s_p, i, n, j); + if (result && wasUsedAsUnbalancedSeed(s_p, i) && supergraph.isExit(n)) { + // j was reached from an entry seed. if there are any facts which are reachable from j, even without + // balanced parentheses, we can use these as new seeds. + for (Iterator it2 = supergraph.getSuccNodes(n); it2.hasNext();) { + T retSite = it2.next(); + PartiallyBalancedTabulationProblem problem = (PartiallyBalancedTabulationProblem) getProblem(); + IFlowFunction f = problem.getFunctionMap().getUnbalancedReturnFlowFunction(n, retSite); + // for each fact that can be reached by the return flow ... + if (f instanceof IUnaryFlowFunction) { + IUnaryFlowFunction uf = (IUnaryFlowFunction) f; + IntSet facts = uf.getTargets(j); + if (facts != null) { + for (IntIterator it4 = facts.intIterator(); it4.hasNext();) { + int d3 = it4.next(); + // d3 would be reached if we ignored parentheses. use it as a new seed. + T fakeEntry = problem.getFakeEntry(retSite); + PathEdge seed = PathEdge.createPathEdge(fakeEntry, d3, retSite, d3); + addSeed(seed); + } + } + } else { + Assertions.UNREACHABLE("Partially balanced logic not supported for binary return flow functions"); + } + } + } + return result; + } + + @Override + public void addSeed(PathEdge seed) { + if (getSeeds().contains(seed)) { + return; + } + unbalancedSeeds.add(Pair.make(seed.entry, seed.d1)); + super.addSeed(seed); + + } + + /** + * Was the fact number i named at node s_p introduced as an "unbalanced" seed during partial tabulation? + * If so, any facts "reached" from here can be further propagated with unbalanced parens. + */ + private boolean wasUsedAsUnbalancedSeed(T s_p, int i) { + return unbalancedSeeds.contains(Pair.make(s_p, i)); + } +} diff --git a/com.ibm.wala.core/src/com/ibm/wala/dataflow/IFDS/PathEdge.java b/com.ibm.wala.core/src/com/ibm/wala/dataflow/IFDS/PathEdge.java index c54ce2b4d..5dba1e257 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/dataflow/IFDS/PathEdge.java +++ b/com.ibm.wala.core/src/com/ibm/wala/dataflow/IFDS/PathEdge.java @@ -1,110 +1,110 @@ -/******************************************************************************* - * 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.dataflow.IFDS; - - -/** - * an individual edge -> - * - * @param node type in the supergraph - */ -public final class PathEdge { - - final T entry; - final int d1; - final T target; - final int d2; - - public static PathEdge createPathEdge(T s_p, int d1, T n, int d2) { - if (s_p == null) { - throw new IllegalArgumentException("null s_p"); - } - if (n == null) { - throw new IllegalArgumentException("null n"); - } - return new PathEdge(s_p, d1, n, d2); - } - - private PathEdge(T s_p, int d1, T n, int d2) { - this.entry = s_p; - this.d1 = d1; - this.target = n; - this.d2 = d2; - } - - @Override - public String toString() { - StringBuffer result = new StringBuffer(); - result.append("<"); - result.append(entry.toString()); - result.append(","); - result.append(d1); - result.append("> -> <"); - result.append(target.toString()); - result.append(","); - result.append(d2); - result.append(">"); - return result.toString(); - } - - @Override - public int hashCode() { - final int prime = 31; - int result = 1; - result = prime * result + d1; - result = prime * result + d2; - result = prime * result + ((target == null) ? 0 : target.hashCode()); - result = prime * result + ((entry == null) ? 0 : entry.hashCode()); - return result; - } - - @Override - public boolean equals(Object obj) { - if (this == obj) - return true; - if (obj == null) - return false; - if (getClass() != obj.getClass()) - return false; - final PathEdge other = (PathEdge) obj; - if (d1 != other.d1) - return false; - if (d2 != other.d2) - return false; - if (target == null) { - if (other.target != null) - return false; - } else if (!target.equals(other.target)) - return false; - if (entry == null) { - if (other.entry != null) - return false; - } else if (!entry.equals(other.entry)) - return false; - return true; - } - - public int getD1() { - return d1; - } - - public int getD2() { - return d2; - } - - public T getEntry() { - return entry; - } - - public T getTarget() { - return target; - } +/******************************************************************************* + * 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.dataflow.IFDS; + + +/** + * an individual edge -> + * + * @param node type in the supergraph + */ +public final class PathEdge { + + final T entry; + final int d1; + final T target; + final int d2; + + public static PathEdge createPathEdge(T s_p, int d1, T n, int d2) { + if (s_p == null) { + throw new IllegalArgumentException("null s_p"); + } + if (n == null) { + throw new IllegalArgumentException("null n"); + } + return new PathEdge(s_p, d1, n, d2); + } + + private PathEdge(T s_p, int d1, T n, int d2) { + this.entry = s_p; + this.d1 = d1; + this.target = n; + this.d2 = d2; + } + + @Override + public String toString() { + StringBuffer result = new StringBuffer(); + result.append("<"); + result.append(entry.toString()); + result.append(","); + result.append(d1); + result.append("> -> <"); + result.append(target.toString()); + result.append(","); + result.append(d2); + result.append(">"); + return result.toString(); + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + d1; + result = prime * result + d2; + result = prime * result + ((target == null) ? 0 : target.hashCode()); + result = prime * result + ((entry == null) ? 0 : entry.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + final PathEdge other = (PathEdge) obj; + if (d1 != other.d1) + return false; + if (d2 != other.d2) + return false; + if (target == null) { + if (other.target != null) + return false; + } else if (!target.equals(other.target)) + return false; + if (entry == null) { + if (other.entry != null) + return false; + } else if (!entry.equals(other.entry)) + return false; + return true; + } + + public int getD1() { + return d1; + } + + public int getD2() { + return d2; + } + + public T getEntry() { + return entry; + } + + public T getTarget() { + return target; + } } \ No newline at end of file diff --git a/com.ibm.wala.core/src/com/ibm/wala/dataflow/IFDS/SingletonFlowFunction.java b/com.ibm.wala.core/src/com/ibm/wala/dataflow/IFDS/SingletonFlowFunction.java index 7b4ef45fc..836d61637 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/dataflow/IFDS/SingletonFlowFunction.java +++ b/com.ibm.wala.core/src/com/ibm/wala/dataflow/IFDS/SingletonFlowFunction.java @@ -1,48 +1,48 @@ -/******************************************************************************* - * Copyright (c) 2002 - 2006 IBM Corporation. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * IBM Corporation - initial API and implementation - *******************************************************************************/ -package com.ibm.wala.dataflow.IFDS; - -import com.ibm.wala.util.intset.SparseIntSet; - -/** - * A flow function which has only the edge 0 -> dest - */ -public class SingletonFlowFunction implements IReversibleFlowFunction { - - final private static SparseIntSet zeroSet = SparseIntSet.singleton(0); - - final int dest; - - private SingletonFlowFunction(int dest) { - this.dest = dest; - } - - public SparseIntSet getTargets(int i) { - if (i == 0) { - return SparseIntSet.add(zeroSet,dest); - } else { - return null; - } - } - - public SparseIntSet getSources(int i) { - if (i == dest || i == 0) { - return zeroSet; - } else { - return null; - } - } - - public static SingletonFlowFunction create(int dest) { - return new SingletonFlowFunction(dest); - } - -} +/******************************************************************************* + * 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.dataflow.IFDS; + +import com.ibm.wala.util.intset.SparseIntSet; + +/** + * A flow function which has only the edge 0 -> dest + */ +public class SingletonFlowFunction implements IReversibleFlowFunction { + + final private static SparseIntSet zeroSet = SparseIntSet.singleton(0); + + final int dest; + + private SingletonFlowFunction(int dest) { + this.dest = dest; + } + + public SparseIntSet getTargets(int i) { + if (i == 0) { + return SparseIntSet.add(zeroSet,dest); + } else { + return null; + } + } + + public SparseIntSet getSources(int i) { + if (i == dest || i == 0) { + return zeroSet; + } else { + return null; + } + } + + public static SingletonFlowFunction create(int dest) { + return new SingletonFlowFunction(dest); + } + +} diff --git a/com.ibm.wala.core/src/com/ibm/wala/dataflow/IFDS/TabulationCancelException.java b/com.ibm.wala.core/src/com/ibm/wala/dataflow/IFDS/TabulationCancelException.java index 96678250b..33682f788 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/dataflow/IFDS/TabulationCancelException.java +++ b/com.ibm.wala.core/src/com/ibm/wala/dataflow/IFDS/TabulationCancelException.java @@ -1,33 +1,33 @@ -/******************************************************************************* - * Copyright (c) 2007 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.dataflow.IFDS; - -import com.ibm.wala.dataflow.IFDS.TabulationSolver.Result; -import com.ibm.wala.util.CancelException; - -/** - * A {@link CancelException} thrown during tabulation; holds a pointer to a partial {@link Result}. Use with care, this can hold on - * to a lot of memory. - */ -public class TabulationCancelException extends CancelException { - - private final Result result; - - protected TabulationCancelException(Exception cause, Result r) { - super(cause); - this.result = r; - } - - public Result getResult() { - return result; - } - -} +/******************************************************************************* + * Copyright (c) 2007 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.dataflow.IFDS; + +import com.ibm.wala.dataflow.IFDS.TabulationSolver.Result; +import com.ibm.wala.util.CancelException; + +/** + * A {@link CancelException} thrown during tabulation; holds a pointer to a partial {@link Result}. Use with care, this can hold on + * to a lot of memory. + */ +public class TabulationCancelException extends CancelException { + + private final Result result; + + protected TabulationCancelException(Exception cause, Result r) { + super(cause); + this.result = r; + } + + public Result getResult() { + return result; + } + +} diff --git a/com.ibm.wala.core/src/com/ibm/wala/dataflow/IFDS/TabulationDomain.java b/com.ibm.wala.core/src/com/ibm/wala/dataflow/IFDS/TabulationDomain.java index 6c3a42825..52bfe6cfc 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/dataflow/IFDS/TabulationDomain.java +++ b/com.ibm.wala.core/src/com/ibm/wala/dataflow/IFDS/TabulationDomain.java @@ -1,34 +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.dataflow.IFDS; - -import com.ibm.wala.util.intset.OrdinalSetMapping; - -/** - * Domain of facts for tabulation. - * - * @param factoid type - * @param type of nodes in the supergraph - */ -public interface TabulationDomain extends OrdinalSetMapping { - - /** - * returns true if p1 should be processed before - * p2 by the {@link TabulationSolver} - * - * For example, if this domain supports a partial order on facts, return true - * if p1.d2 is weaker than p2.d2 (intuitively p1.d2 meet p2.d2 = p1.d2) - * - * return false otherwise - */ - boolean hasPriorityOver(PathEdge p1, PathEdge p2); - -} +/******************************************************************************* + * 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.dataflow.IFDS; + +import com.ibm.wala.util.intset.OrdinalSetMapping; + +/** + * Domain of facts for tabulation. + * + * @param factoid type + * @param type of nodes in the supergraph + */ +public interface TabulationDomain extends OrdinalSetMapping { + + /** + * returns true if p1 should be processed before + * p2 by the {@link TabulationSolver} + * + * For example, if this domain supports a partial order on facts, return true + * if p1.d2 is weaker than p2.d2 (intuitively p1.d2 meet p2.d2 = p1.d2) + * + * return false otherwise + */ + boolean hasPriorityOver(PathEdge p1, PathEdge p2); + +} diff --git a/com.ibm.wala.core/src/com/ibm/wala/dataflow/IFDS/TabulationProblem.java b/com.ibm.wala.core/src/com/ibm/wala/dataflow/IFDS/TabulationProblem.java index 657b70571..469321959 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/dataflow/IFDS/TabulationProblem.java +++ b/com.ibm.wala.core/src/com/ibm/wala/dataflow/IFDS/TabulationProblem.java @@ -1,51 +1,51 @@ -/******************************************************************************* - * Copyright (c) 2002 - 2006 IBM Corporation. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * IBM Corporation - initial API and implementation - *******************************************************************************/ -package com.ibm.wala.dataflow.IFDS; - -import java.util.Collection; - -/** - * Representation of a Dyck-language graph reachability problem for the tabulation solver. - * - * Special case: if supportsMerge(), then the problem is not really IFDS anymore. (TODO: rename it?). Instead, we perform a merge - * operation before propagating at every program point. This way, we can implement standard interprocedural dataflow and ESP-style - * property simulation, and various other things. - * - * Note that at the moment, the data structures in the TabulationSolver are not set up to do merge efficiently. TODO. - * - * See Reps, Horwitz, Sagiv POPL 95 - * - * @param type of node in the supergraph - * @param

        type of a procedure (like a box in an RSM) - * @param type of factoids propagated when solving this problem - */ -public interface TabulationProblem { - - public ISupergraph getSupergraph(); - - public TabulationDomain getDomain(); - - public IFlowFunctionMap getFunctionMap(); - - /** - * Define the set of path edges to start propagation with. - */ - public Collection> initialSeeds(); - - /** - * Special case: if supportsMerge(), then the problem is not really IFDS anymore. (TODO: rename it?). Instead, we perform a merge - * operation before propagating at every program point. This way, we can implement standard interprocedural dataflow and ESP-style - * property simulation, and various other things. - * - * @return the merge function, or null if !supportsMerge() - */ - public IMergeFunction getMergeFunction(); -} +/******************************************************************************* + * 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.dataflow.IFDS; + +import java.util.Collection; + +/** + * Representation of a Dyck-language graph reachability problem for the tabulation solver. + * + * Special case: if supportsMerge(), then the problem is not really IFDS anymore. (TODO: rename it?). Instead, we perform a merge + * operation before propagating at every program point. This way, we can implement standard interprocedural dataflow and ESP-style + * property simulation, and various other things. + * + * Note that at the moment, the data structures in the TabulationSolver are not set up to do merge efficiently. TODO. + * + * See Reps, Horwitz, Sagiv POPL 95 + * + * @param type of node in the supergraph + * @param

        type of a procedure (like a box in an RSM) + * @param type of factoids propagated when solving this problem + */ +public interface TabulationProblem { + + public ISupergraph getSupergraph(); + + public TabulationDomain getDomain(); + + public IFlowFunctionMap getFunctionMap(); + + /** + * Define the set of path edges to start propagation with. + */ + public Collection> initialSeeds(); + + /** + * Special case: if supportsMerge(), then the problem is not really IFDS anymore. (TODO: rename it?). Instead, we perform a merge + * operation before propagating at every program point. This way, we can implement standard interprocedural dataflow and ESP-style + * property simulation, and various other things. + * + * @return the merge function, or null if !supportsMerge() + */ + public IMergeFunction getMergeFunction(); +} diff --git a/com.ibm.wala.core/src/com/ibm/wala/dataflow/IFDS/TabulationResult.java b/com.ibm.wala.core/src/com/ibm/wala/dataflow/IFDS/TabulationResult.java index 824bcb8cf..1b2454f57 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/dataflow/IFDS/TabulationResult.java +++ b/com.ibm.wala.core/src/com/ibm/wala/dataflow/IFDS/TabulationResult.java @@ -1,57 +1,57 @@ -/******************************************************************************* - * 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.dataflow.IFDS; - -import java.util.Collection; - -import com.ibm.wala.util.intset.IntSet; - -/** - * The solution of a tabulation problem: a mapping from supergraph node -> bit vector representing the dataflow facts that hold at - * the entry to the supergraph node. - * - * @param type of node in the supergraph - * @param

        type of a procedure, like a box in an RSM - * @param type of factoids propagated when solving this problem - */ -public interface TabulationResult { - /** - * get the bitvector of facts that hold at IN for a given node in the supergraph. - * - * @param node a node in the supergraph - * @return SparseIntSet efficiently representing the bitvector - */ - public IntSet getResult(T node); - - /** - * @return the governing IFDS problem - */ - public TabulationProblem getProblem(); - - /** - * @return the set of supergraph nodes for which any fact is reached - */ - public Collection getSupergraphNodesReached(); - - /** - * @param n1 - * @param d1 - * @param n2 - * @return set of d2 s.t. (n1,d1) -> (n2,d2) is recorded as a summary edge, or null if none found - */ - public IntSet getSummaryTargets(T n1, int d1, T n2); - - /** - * @return the set of all {@link PathEdge}s that were used as seeds during the tabulation. - */ - public Collection> getSeeds(); - -} +/******************************************************************************* + * 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.dataflow.IFDS; + +import java.util.Collection; + +import com.ibm.wala.util.intset.IntSet; + +/** + * The solution of a tabulation problem: a mapping from supergraph node -> bit vector representing the dataflow facts that hold at + * the entry to the supergraph node. + * + * @param type of node in the supergraph + * @param

        type of a procedure, like a box in an RSM + * @param type of factoids propagated when solving this problem + */ +public interface TabulationResult { + /** + * get the bitvector of facts that hold at IN for a given node in the supergraph. + * + * @param node a node in the supergraph + * @return SparseIntSet efficiently representing the bitvector + */ + public IntSet getResult(T node); + + /** + * @return the governing IFDS problem + */ + public TabulationProblem getProblem(); + + /** + * @return the set of supergraph nodes for which any fact is reached + */ + public Collection getSupergraphNodesReached(); + + /** + * @param n1 + * @param d1 + * @param n2 + * @return set of d2 s.t. (n1,d1) -> (n2,d2) is recorded as a summary edge, or null if none found + */ + public IntSet getSummaryTargets(T n1, int d1, T n2); + + /** + * @return the set of all {@link PathEdge}s that were used as seeds during the tabulation. + */ + public Collection> getSeeds(); + +} diff --git a/com.ibm.wala.core/src/com/ibm/wala/dataflow/IFDS/TabulationSolver.java b/com.ibm.wala.core/src/com/ibm/wala/dataflow/IFDS/TabulationSolver.java index 1b8106605..6c600b6a5 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/dataflow/IFDS/TabulationSolver.java +++ b/com.ibm.wala.core/src/com/ibm/wala/dataflow/IFDS/TabulationSolver.java @@ -1,1050 +1,1050 @@ -/******************************************************************************* - * 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.dataflow.IFDS; - -import java.util.Arrays; -import java.util.Collection; -import java.util.Collections; -import java.util.Comparator; -import java.util.Iterator; -import java.util.Map; -import java.util.Map.Entry; -import java.util.Set; -import java.util.TreeMap; -import java.util.TreeSet; - -import com.ibm.wala.cfg.IBasicBlock; -import com.ibm.wala.util.CancelException; -import com.ibm.wala.util.CancelRuntimeException; -import com.ibm.wala.util.MonitorUtil; -import com.ibm.wala.util.MonitorUtil.IProgressMonitor; -import com.ibm.wala.util.collections.HashMapFactory; -import com.ibm.wala.util.collections.HashSetFactory; -import com.ibm.wala.util.collections.Heap; -import com.ibm.wala.util.collections.Iterator2Collection; -import com.ibm.wala.util.collections.MapUtil; -import com.ibm.wala.util.collections.ToStringComparator; -import com.ibm.wala.util.heapTrace.HeapTracer; -import com.ibm.wala.util.intset.IntIterator; -import com.ibm.wala.util.intset.IntSet; -import com.ibm.wala.util.intset.IntSetAction; -import com.ibm.wala.util.intset.MutableIntSet; -import com.ibm.wala.util.intset.MutableSparseIntSet; -import com.ibm.wala.util.ref.ReferenceCleanser; - -/** - * A precise interprocedural tabulation solver. - *

        - * See Reps, Horwitz, Sagiv POPL 95. - *

        - * This version differs in some ways from the POPL algorithm. In particular ... - *

          - *
        • to support exceptional control flow ... there may be several return sites for each call site. - *
        • it supports an optional merge operator, useful for non-IFDS problems and widening. - *
        • it stores summary edges at each callee instead of at each call site. - *
        - *

        - * - * @param type of node in the supergraph - * @param

        type of a procedure (like a box in an RSM) - * @param type of factoids propagated when solving this problem - */ -public class TabulationSolver { - - /** - * DEBUG_LEVEL: - *

          - *
        • 0 No output - *
        • 1 Print some simple stats and warning information - *
        • 2 Detailed debugging - *
        • 3 Also print worklists - *
        - */ - protected static final int DEBUG_LEVEL = 0; - - static protected final boolean verbose = true && ("true".equals(System.getProperty("com.ibm.wala.fixedpoint.impl.verbose")) ? true - : false); - - static final int VERBOSE_INTERVAL = 1000; - - static final boolean VERBOSE_TRACE_MEMORY = false; - - private static int verboseCounter = 0; - - /** - * Should we periodically clear out soft reference caches in an attempt to help the GC? - */ - final protected static boolean PERIODIC_WIPE_SOFT_CACHES = true; - - /** - * Interval which defines the period to clear soft reference caches - */ - private final static int WIPE_SOFT_CACHE_INTERVAL = 1000000; - - /** - * Counter for wiping soft caches - */ - private static int wipeCount = WIPE_SOFT_CACHE_INTERVAL; - - /** - * The supergraph which induces this dataflow problem - */ - protected final ISupergraph supergraph; - - /** - * A map from an edge in a supergraph to a flow function - */ - protected final IFlowFunctionMap flowFunctionMap; - - /** - * The problem being solved. - */ - private final TabulationProblem problem; - - /** - * A map from Object (entry node in supergraph) -> LocalPathEdges. - * - * Logically, this represents a set of edges (s_p,d_i) -> (n, d_j). The data structure is chosen to attempt to save space over - * representing each edge explicitly. - */ - final private Map pathEdges = HashMapFactory.make(); - - /** - * A map from Object (entry node in supergraph) -> CallFlowEdges. - * - * Logically, this represents a set of edges (c,d_i) -> (s_p, d_j). The data structure is chosen to attempt to save space over - * representing each edge explicitly. - */ - final private Map callFlowEdges = HashMapFactory.make(); - - /** - * A map from Object (procedure) -> LocalSummaryEdges. - * - */ - final protected Map summaryEdges = HashMapFactory.make(); - - /** - * the set of all {@link PathEdge}s that were used as seeds during the tabulation, grouped by procedure. - */ - private final Map>> seeds = HashMapFactory.make(); - - /** - * All seeds, stored redundantly for quick access. - */ - private final Set> allSeeds = HashSetFactory.make(); - - /** - * The worklist - */ - private ITabulationWorklist worklist; - - /** - * A progress monitor. can be null. - */ - protected final IProgressMonitor progressMonitor; - - /** - * the path edge currently being processed in the main loop of {@link #forwardTabulateSLRPs()}; null if - * {@link #forwardTabulateSLRPs()} is not currently running. Note that if we are applying a summary edge in - * {@link #processExit(PathEdge)}, curPathEdge is modified to be the path edge terminating at the call node in the caller, to - * match the behavior in {@link #processCall(PathEdge)}. - */ - private PathEdge curPathEdge; - - /** - * the summary edge currently being applied in {@link #processCall(PathEdge)} or {@link #processExit(PathEdge)}, or - * null if summary edges are not currently being processed. - */ - private PathEdge curSummaryEdge; - - /** - * @param p a description of the dataflow problem to solve - * @throws IllegalArgumentException if p is null - */ - protected TabulationSolver(TabulationProblem p, IProgressMonitor monitor) { - if (p == null) { - throw new IllegalArgumentException("p is null"); - } - this.supergraph = p.getSupergraph(); - this.flowFunctionMap = p.getFunctionMap(); - this.problem = p; - this.progressMonitor = monitor; - } - - /** - * Subclasses can override this to plug in a different worklist implementation. - */ - protected ITabulationWorklist makeWorklist() { - return new Worklist(); - } - - /** - * @param p a description of the dataflow problem to solve - * @throws IllegalArgumentException if p is null - */ - public static TabulationSolver make(TabulationProblem p) { - return new TabulationSolver(p, null); - } - - /** - * Solve the dataflow problem. - * - * @return a representation of the result - */ - public TabulationResult solve() throws CancelException { - - try { - initialize(); - forwardTabulateSLRPs(); - Result r = new Result(); - return r; - } catch (CancelException e) { - // store a partially-tabulated result in the thrown exception. - Result r = new Result(); - throw new TabulationCancelException(e, r); - } catch (CancelRuntimeException e) { - // store a partially-tabulated result in the thrown exception. - Result r = new Result(); - throw new TabulationCancelException(e, r); - } - } - - /** - * Start tabulation with the initial seeds. - */ - protected void initialize() { - for (PathEdge seed : problem.initialSeeds()) { - addSeed(seed); - } - } - - /** - * Restart tabulation from a particular path edge. Use with care. - */ - public void addSeed(PathEdge seed) { - Set> s = MapUtil.findOrCreateSet(seeds, supergraph.getProcOf(seed.entry)); - s.add(seed); - allSeeds.add(seed); - propagate(seed.entry, seed.d1, seed.target, seed.d2); - } - - /** - * See POPL 95 paper for this algorithm, Figure 3 - * - * @throws CancelException - */ - private void forwardTabulateSLRPs() throws CancelException { - assert curPathEdge == null : "curPathEdge should not be non-null here"; - if (worklist == null) { - worklist = makeWorklist(); - } - while (worklist.size() > 0) { - MonitorUtil.throwExceptionIfCanceled(progressMonitor); - if (verbose) { - performVerboseAction(); - } - if (PERIODIC_WIPE_SOFT_CACHES) { - tendToSoftCaches(); - } - - final PathEdge edge = popFromWorkList(); - if (DEBUG_LEVEL > 0) { - System.err.println("TABULATE " + edge); - } - curPathEdge = edge; - int j = merge(edge.entry, edge.d1, edge.target, edge.d2); - if (j == -1 && DEBUG_LEVEL > 0) { - System.err.println("merge -1: DROPPING"); - } - if (j != -1) { - if (j != edge.d2) { - // this means that we don't want to push the edge. instead, - // we'll push the merged fact. a little tricky, but i think should - // work. - if (DEBUG_LEVEL > 0) { - System.err.println("propagating merged fact " + j); - } - propagate(edge.entry, edge.d1, edge.target, j); - } else { - if (supergraph.isCall(edge.target)) { - // [13] - processCall(edge); - } else if (supergraph.isExit(edge.target)) { - // [21] - processExit(edge); - } else { - // [33] - processNormal(edge); - } - } - } - } - curPathEdge = null; - } - - /** - * For some reason (either a bug in our code that defeats soft references, or a bad policy in the GC), leaving soft reference - * caches to clear themselves out doesn't work. Help it out. - * - * It's unfortunate that this method exits. - */ - protected void tendToSoftCaches() { - wipeCount++; - if (wipeCount > WIPE_SOFT_CACHE_INTERVAL) { - wipeCount = 0; - ReferenceCleanser.clearSoftCaches(); - } - } - - /** - * - */ - protected final void performVerboseAction() { - verboseCounter++; - if (verboseCounter % VERBOSE_INTERVAL == 0) { - System.err.println("Tabulation Solver " + verboseCounter); - System.err.println(" " + peekFromWorkList()); - if (VERBOSE_TRACE_MEMORY) { - ReferenceCleanser.clearSoftCaches(); - System.err.println("Analyze leaks.."); - HeapTracer.traceHeap(Collections.singleton(this), true); - System.err.println("done analyzing leaks"); - } - } - } - - /** - * Handle lines [33-37] of the algorithm - * - * @param edge - */ - private void processNormal(final PathEdge edge) { - if (DEBUG_LEVEL > 0) { - System.err.println("process normal: " + edge); - } - for (Iterator it = supergraph.getSuccNodes(edge.target); it.hasNext();) { - final T m = it.next(); - if (DEBUG_LEVEL > 0) { - System.err.println("normal successor: " + m); - } - IUnaryFlowFunction f = flowFunctionMap.getNormalFlowFunction(edge.target, m); - IntSet D3 = computeFlow(edge.d2, f); - if (DEBUG_LEVEL > 0) { - System.err.println(" reached: " + D3); - } - if (D3 != null) { - D3.foreach(new IntSetAction() { - public void act(int d3) { - propagate(edge.entry, edge.d1, m, d3); - } - }); - } - } - } - - /** - * Handle lines [21 - 32] of the algorithm, propagating information from an exit node. - * - * Note that we've changed the way we record summary edges. Summary edges are now associated with a callee (s_p,exit), where the - * original algorithm used a call, return pair in the caller. - */ - protected void processExit(final PathEdge edge) { - if (DEBUG_LEVEL > 0) { - System.err.println("process exit: " + edge); - } - - final LocalSummaryEdges summaries = findOrCreateLocalSummaryEdges(supergraph.getProcOf(edge.target)); - int s_p_n = supergraph.getLocalBlockNumber(edge.entry); - int x = supergraph.getLocalBlockNumber(edge.target); - if (!summaries.contains(s_p_n, x, edge.d1, edge.d2)) { - summaries.insertSummaryEdge(s_p_n, x, edge.d1, edge.d2); - } - assert curSummaryEdge == null : "curSummaryEdge should be null here"; - curSummaryEdge = edge; - - final CallFlowEdges callFlow = findOrCreateCallFlowEdges(edge.entry); - - // [22] for each c /in callers(p) - IntSet callFlowSourceNodes = callFlow.getCallFlowSourceNodes(edge.d1); - if (callFlowSourceNodes != null) { - for (IntIterator it = callFlowSourceNodes.intIterator(); it.hasNext();) { - // [23] for each d4 s.t. -> occurred earlier - int globalC = it.next(); - final IntSet D4 = callFlow.getCallFlowSources(globalC, edge.d1); - - // [23] for each d5 s.t. -> ... - propagateToReturnSites(edge, supergraph.getNode(globalC), D4); - } - } - curSummaryEdge = null; - } - - /** - * Propagate information for an "exit" edge to the appropriate return sites - * - * [23] for each d5 s.t. -> .. - * - * @param edge the edge being processed - * @param succ numbers of the nodes that are successors of edge.n (the return block in the callee) in the call graph. - * @param c a call site of edge.s_p - * @param D4 set of d1 s.t. -> was recorded as call flow - */ - private void propagateToReturnSites(final PathEdge edge, final T c, final IntSet D4) { - P proc = supergraph.getProcOf(c); - final T[] entries = supergraph.getEntriesForProcedure(proc); - - // we iterate over each potential return site; - // we might have multiple return sites due to exceptions - // note that we might have different summary edges for each - // potential return site, and different flow functions from this - // exit block to each return site. - for (Iterator retSites = supergraph.getReturnSites(c, supergraph.getProcOf(edge.target)); retSites.hasNext();) { - final T retSite = retSites.next(); - if (DEBUG_LEVEL > 1) { - System.err.println("candidate return site: " + retSite + " " + supergraph.getNumber(retSite)); - } - // note: since we might have multiple exit nodes for the callee, (to handle exceptional returns) - // not every return site might be valid for this exit node (edge.n). - // so, we'll filter the logic by checking that we only process reachable return sites. - // the supergraph carries the information regarding the legal successors - // of the exit node - if (!supergraph.hasEdge(edge.target, retSite)) { - continue; - } - if (DEBUG_LEVEL > 1) { - System.err.println("feasible return site: " + retSite); - } - final IFlowFunction retf = flowFunctionMap.getReturnFlowFunction(c, edge.target, retSite); - if (retf instanceof IBinaryReturnFlowFunction) { - propagateToReturnSiteWithBinaryFlowFunction(edge, c, D4, entries, retSite, retf); - } else { - final IntSet D5 = computeFlow(edge.d2, (IUnaryFlowFunction) retf); - if (DEBUG_LEVEL > 1) { - System.err.println("D4" + D4); - System.err.println("D5 " + D5); - } - IntSetAction action = new IntSetAction() { - public void act(final int d4) { - propToReturnSite(c, entries, retSite, d4, D5); - } - }; - D4.foreach(action); - } - } - } - - /** - * Propagate information for an "exit" edge to a caller return site - * - * [23] for each d5 s.t. -> .. - * - * @param edge the edge being processed - * @param c a call site of edge.s_p - * @param D4 set of d1 s.t. -> was recorded as call flow - * @param entries the blocks in the supergraph that are entries for the procedure of c - * @param retSite the return site being propagated to - * @param retf the flow function - */ - private void propagateToReturnSiteWithBinaryFlowFunction(final PathEdge edge, final T c, final IntSet D4, final T[] entries, - final T retSite, final IFlowFunction retf) { - D4.foreach(new IntSetAction() { - public void act(final int d4) { - final IntSet D5 = computeBinaryFlow(d4, edge.d2, (IBinaryReturnFlowFunction) retf); - propToReturnSite(c, entries, retSite, d4, D5); - } - - }); - } - - /** - * Propagate information to a particular return site. - * - * @param c the corresponding call site - * @param entries entry nodes in the caller - * @param retSite the return site - * @param d4 a fact s.t. -> was recorded as call flow and is the source of the summary edge - * being applied - * @param D5 facts to propagate to return site - */ - private void propToReturnSite(final T c, final T[] entries, final T retSite, final int d4, final IntSet D5) { - if (D5 != null) { - D5.foreach(new IntSetAction() { - public void act(final int d5) { - // [26 - 28] - // note that we've modified the algorithm here to account - // for potential - // multiple entry nodes. Instead of propagating the new - // summary edge - // with respect to one s_profOf(c), we have to propagate - // for each - // potential entry node s_p /in s_procof(c) - for (int i = 0; i < entries.length; i++) { - final T s_p = entries[i]; - if (DEBUG_LEVEL > 1) { - System.err.println(" do entry " + s_p); - } - IntSet D3 = getInversePathEdges(s_p, c, d4); - if (DEBUG_LEVEL > 1) { - System.err.println("D3" + D3); - } - if (D3 != null) { - D3.foreach(new IntSetAction() { - public void act(int d3) { - // set curPathEdge to be consistent with its setting in processCall() when applying a summary edge - curPathEdge = PathEdge.createPathEdge(s_p, d3, c, d4); - propagate(s_p, d3, retSite, d5); - } - }); - } - } - } - }); - } - } - - /** - * @param s_p - * @param n - * @param d2 note that s_p must be an entry for procof(n) - * @return set of d1 s.t. -> is a path edge, or null if none found - */ - protected IntSet getInversePathEdges(T s_p, T n, int d2) { - int number = supergraph.getLocalBlockNumber(n); - LocalPathEdges lp = pathEdges.get(s_p); - if (lp == null) { - return null; - } - return lp.getInverse(number, d2); - } - - /** - * Handle lines [14 - 19] of the algorithm, propagating information into and across a call site. - */ - protected void processCall(final PathEdge edge) { - if (DEBUG_LEVEL > 0) { - System.err.println("process call: " + edge); - } - - // c:= number of the call node - final int c = supergraph.getNumber(edge.target); - - Collection allReturnSites = HashSetFactory.make(); - // populate allReturnSites with return sites for missing calls. - for (Iterator it = supergraph.getReturnSites(edge.target, null); it.hasNext();) { - allReturnSites.add(it.next()); - } - // [14 - 16] - boolean hasCallee = false; - for (Iterator it = supergraph.getCalledNodes(edge.target); it.hasNext();) { - hasCallee = true; - final T callee = it.next(); - processParticularCallee(edge, c, allReturnSites, callee); - } - // special logic: in backwards problems, a "call" node can have - // "normal" successors as well. deal with these. - for (Iterator it = supergraph.getNormalSuccessors(edge.target); it.hasNext();) { - final T m = it.next(); - if (DEBUG_LEVEL > 0) { - System.err.println("normal successor: " + m); - } - IUnaryFlowFunction f = flowFunctionMap.getNormalFlowFunction(edge.target, m); - IntSet D3 = computeFlow(edge.d2, f); - if (DEBUG_LEVEL > 0) { - System.err.println("normal successor reached: " + D3); - } - if (D3 != null) { - D3.foreach(new IntSetAction() { - public void act(int d3) { - propagate(edge.entry, edge.d1, m, d3); - } - }); - } - } - - // [17 - 19] - // we modify this to handle each return site individually - for (final T returnSite : allReturnSites) { - if (DEBUG_LEVEL > 0) { - System.err.println(" process return site: " + returnSite); - } - IUnaryFlowFunction f = null; - if (hasCallee) { - f = flowFunctionMap.getCallToReturnFlowFunction(edge.target, returnSite); - } else { - f = flowFunctionMap.getCallNoneToReturnFlowFunction(edge.target, returnSite); - } - IntSet reached = computeFlow(edge.d2, f); - if (DEBUG_LEVEL > 0) { - System.err.println("reached: " + reached); - } - if (reached != null) { - reached.foreach(new IntSetAction() { - public void act(int x) { - assert x >= 0; - assert edge.d1 >= 0; - propagate(edge.entry, edge.d1, returnSite, x); - } - }); - } - } - } - - /** - * handle a particular callee for some call node. - * - * @param edge the path edge being processed - * @param callNodeNum the number of the call node in the supergraph - * @param allReturnSites a set collecting return sites for the call. This set is mutated with the return sites for this callee. - * @param calleeEntry the entry node of the callee in question - */ - protected void processParticularCallee(final PathEdge edge, final int callNodeNum, Collection allReturnSites, final T calleeEntry) { - if (DEBUG_LEVEL > 0) { - System.err.println(" process callee: " + calleeEntry); - } - // reached := {d1} that reach the callee - MutableSparseIntSet reached = MutableSparseIntSet.makeEmpty(); - final Collection returnSitesForCallee = Iterator2Collection.toSet(supergraph.getReturnSites(edge.target, supergraph - .getProcOf(calleeEntry))); - allReturnSites.addAll(returnSitesForCallee); - // we modify this to handle each return site individually. Some types of problems - // compute different flow functions for each return site. - for (final T returnSite : returnSitesForCallee) { - IUnaryFlowFunction f = flowFunctionMap.getCallFlowFunction(edge.target, calleeEntry, returnSite); - IntSet r = computeFlow(edge.d2, f); - if (r != null) { - reached.addAll(r); - } - } - // in some problems, we also want to consider flow into a callee that can never flow out - // via a return. in this case, the return site is null. - IUnaryFlowFunction f = flowFunctionMap.getCallFlowFunction(edge.target, calleeEntry, null); - IntSet r = computeFlow(edge.d2, f); - if (r != null) { - reached.addAll(r); - } - if (DEBUG_LEVEL > 0) { - System.err.println(" reached: " + reached); - } - if (reached != null) { - final LocalSummaryEdges summaries = summaryEdges.get(supergraph.getProcOf(calleeEntry)); - final CallFlowEdges callFlow = findOrCreateCallFlowEdges(calleeEntry); - final int s_p_num = supergraph.getLocalBlockNumber(calleeEntry); - - reached.foreach(new IntSetAction() { - public void act(final int d1) { - // we get reuse if we _don't_ propagate a new fact to the callee entry - final boolean gotReuse = !propagate(calleeEntry, d1, calleeEntry, d1); - recordCall(edge.target, calleeEntry, d1, gotReuse); - // cache the fact that we've flowed -> by a - // call flow - callFlow.addCallEdge(callNodeNum, edge.d2, d1); - // handle summary edges now as well. this is different from the PoPL - // 95 paper. - if (summaries != null) { - // for each exit from the callee - P p = supergraph.getProcOf(calleeEntry); - T[] exits = supergraph.getExitsForProcedure(p); - for (int e = 0; e < exits.length; e++) { - final T exit = exits[e]; - if (DEBUG_LEVEL > 0) { - assert supergraph.containsNode(exit); - } - int x_num = supergraph.getLocalBlockNumber(exit); - // reachedBySummary := {d2} s.t. -> - // was recorded as a summary edge - IntSet reachedBySummary = summaries.getSummaryEdges(s_p_num, x_num, d1); - if (reachedBySummary != null) { - for (final T returnSite : returnSitesForCallee) { - // if "exit" is a valid exit from the callee to the return - // site being processed - if (supergraph.hasEdge(exit, returnSite)) { - final IFlowFunction retf = flowFunctionMap.getReturnFlowFunction(edge.target, exit, returnSite); - reachedBySummary.foreach(new IntSetAction() { - public void act(int d2) { - assert curSummaryEdge == null : "curSummaryEdge should be null here"; - curSummaryEdge = PathEdge.createPathEdge(calleeEntry, d1, exit, d2); - if (retf instanceof IBinaryReturnFlowFunction) { - final IntSet D5 = computeBinaryFlow(edge.d2, d2, (IBinaryReturnFlowFunction) retf); - if (D5 != null) { - D5.foreach(new IntSetAction() { - public void act(int d5) { - propagate(edge.entry, edge.d1, returnSite, d5); - } - }); - } - } else { - final IntSet D5 = computeFlow(d2, (IUnaryFlowFunction) retf); - if (D5 != null) { - D5.foreach(new IntSetAction() { - public void act(int d5) { - propagate(edge.entry, edge.d1, returnSite, d5); - } - }); - } - } - curSummaryEdge = null; - } - }); - } - } - } - } - } - } - }); - } - } - - /** - * invoked when a callee is processed with a particular entry fact - * - * @param callNode - * @param callee - * @param d1 the entry fact - * @param gotReuse whether existing summary edges were applied - */ - protected void recordCall(T callNode, T callee, int d1, boolean gotReuse) { - } - - /** - * @return f(call_d, exit_d); - * - */ - protected IntSet computeBinaryFlow(int call_d, int exit_d, IBinaryReturnFlowFunction f) { - if (DEBUG_LEVEL > 0) { - System.err.println("got binary flow function " + f); - } - IntSet result = f.getTargets(call_d, exit_d); - return result; - } - - /** - * @return f(d1) - * - */ - protected IntSet computeFlow(int d1, IUnaryFlowFunction f) { - if (DEBUG_LEVEL > 0) { - System.err.println("got flow function " + f); - } - IntSet result = f.getTargets(d1); - - if (result == null) { - return null; - } else { - return result; - } - } - - /** - * @return f^{-1}(d2) - */ - protected IntSet computeInverseFlow(int d2, IReversibleFlowFunction f) { - return f.getSources(d2); - } - - protected PathEdge popFromWorkList() { - assert worklist != null; - return worklist.take(); - } - - private PathEdge peekFromWorkList() { - // horrible. don't use in performance-critical - assert worklist != null; - PathEdge result = worklist.take(); - worklist.insert(result); - return result; - } - - /** - * Propagate the fact -> has arisen as a path edge. Returns true iff the path edge was not previously - * observed. - * - * @param s_p entry block - * @param i dataflow fact on entry - * @param n reached block - * @param j dataflow fact reached - */ - protected boolean propagate(T s_p, int i, T n, int j) { - int number = supergraph.getLocalBlockNumber(n); - if (number < 0) { - System.err.println("BOOM " + n); - supergraph.getLocalBlockNumber(n); - } - assert number >= 0; - - LocalPathEdges pLocal = findOrCreateLocalPathEdges(s_p); - - assert j >= 0; - - if (!pLocal.contains(i, number, j)) { - if (DEBUG_LEVEL > 0) { - System.err.println("propagate " + s_p + " " + i + " " + number + " " + j); - } - pLocal.addPathEdge(i, number, j); - addToWorkList(s_p, i, n, j); - return true; - } - return false; - } - - public LocalPathEdges getLocalPathEdges(T s_p) { - return pathEdges.get(s_p); - } - - /** - * Merging: suppose we're doing propagate -> but we already have path edges -> , -> , and - * ->. - * - * let \alpha be the merge function. then instead of -> , we propagate -> !!! - * - * return -1 if no fact should be propagated - */ - private int merge(T s_p, int i, T n, int j) { - assert j >= 0; - IMergeFunction alpha = problem.getMergeFunction(); - if (alpha != null) { - LocalPathEdges lp = pathEdges.get(s_p); - IntSet preExistFacts = lp.getReachable(supergraph.getLocalBlockNumber(n), i); - if (preExistFacts == null) { - return j; - } else { - int size = preExistFacts.size(); - if ((size == 0) || ((size == 1) && preExistFacts.contains(j))) { - return j; - } else { - int result = alpha.merge(preExistFacts, j); - return result; - } - } - } else { - return j; - } - } - - protected void addToWorkList(T s_p, int i, T n, int j) { - if (worklist == null) { - worklist = makeWorklist(); - } - worklist.insert(PathEdge.createPathEdge(s_p, i, n, j)); - if (DEBUG_LEVEL >= 3) { - System.err.println("WORKLIST: " + worklist); - } - } - - protected LocalPathEdges findOrCreateLocalPathEdges(T s_p) { - LocalPathEdges result = pathEdges.get(s_p); - if (result == null) { - result = makeLocalPathEdges(); - pathEdges.put(s_p, result); - } - return result; - } - - private LocalPathEdges makeLocalPathEdges() { - return problem.getMergeFunction() == null ? new LocalPathEdges(false) : new LocalPathEdges(true); - } - - protected LocalSummaryEdges findOrCreateLocalSummaryEdges(P proc) { - LocalSummaryEdges result = summaryEdges.get(proc); - if (result == null) { - result = new LocalSummaryEdges(); - summaryEdges.put(proc, result); - } - return result; - } - - protected CallFlowEdges findOrCreateCallFlowEdges(T s_p) { - CallFlowEdges result = callFlowEdges.get(s_p); - if (result == null) { - result = new CallFlowEdges(); - callFlowEdges.put(s_p, result); - } - return result; - } - - /** - * get the bitvector of facts that hold at the entry to a given node - * - * @return IntSet representing the bitvector - */ - public IntSet getResult(T node) { - P proc = supergraph.getProcOf(node); - int n = supergraph.getLocalBlockNumber(node); - T[] entries = supergraph.getEntriesForProcedure(proc); - MutableIntSet result = MutableSparseIntSet.makeEmpty(); - - Set allEntries = HashSetFactory.make(Arrays.asList(entries)); - Set> pSeeds = seeds.get(proc); - if (pSeeds != null) { - for (PathEdge seed : pSeeds) { - allEntries.add(seed.entry); - } - } - - for (T entry : allEntries){ - LocalPathEdges lp = pathEdges.get(entry); - if (lp != null) { - result.addAll(lp.getReachable(n)); - } - } - - return result; - } - - public class Result implements TabulationResult { - - /** - * get the bitvector of facts that hold at the entry to a given node - * - * @return IntSet representing the bitvector - */ - public IntSet getResult(T node) { - return TabulationSolver.this.getResult(node); - } - - @Override - public String toString() { - - StringBuffer result = new StringBuffer(); - TreeMap> map = new TreeMap>(ToStringComparator.instance()); - - Comparator c = new Comparator() { - public int compare(Object o1, Object o2) { - if (!(o1 instanceof IBasicBlock)) { - return -1; - } - IBasicBlock bb1 = (IBasicBlock) o1; - IBasicBlock bb2 = (IBasicBlock) o2; - return bb1.getNumber() - bb2.getNumber(); - } - }; - for (Iterator it = supergraph.iterator(); it.hasNext();) { - T n = it.next(); - P proc = supergraph.getProcOf(n); - TreeSet s = map.get(proc); - if (s == null) { - s = new TreeSet(c); - map.put(proc, s); - } - s.add(n); - } - - for (Iterator>> it = map.entrySet().iterator(); it.hasNext();) { - Map.Entry> e = it.next(); - Set s = e.getValue(); - for (Iterator it2 = s.iterator(); it2.hasNext();) { - T o = it2.next(); - result.append(o + " : " + getResult(o) + "\n"); - } - } - return result.toString(); - } - - /* - * @see com.ibm.wala.dataflow.IFDS.TabulationResult#getProblem() - */ - public TabulationProblem getProblem() { - return problem; - } - - /* - * @see com.ibm.wala.dataflow.IFDS.TabulationResult#getSupergraphNodesReached() - */ - public Collection getSupergraphNodesReached() { - Collection result = HashSetFactory.make(); - for (Entry e : pathEdges.entrySet()) { - T key = e.getKey(); - P proc = supergraph.getProcOf(key); - IntSet reached = e.getValue().getReachedNodeNumbers(); - for (IntIterator ii = reached.intIterator(); ii.hasNext();) { - result.add(supergraph.getLocalBlock(proc, ii.next())); - } - } - - return result; - } - - /** - * @param n1 - * @param d1 - * @param n2 - * @return set of d2 s.t. (n1,d1) -> (n2,d2) is recorded as a summary edge, or null if none found - */ - public IntSet getSummaryTargets(T n1, int d1, T n2) { - LocalSummaryEdges summaries = summaryEdges.get(supergraph.getProcOf(n1)); - if (summaries == null) { - return null; - } - int num1 = supergraph.getLocalBlockNumber(n1); - int num2 = supergraph.getLocalBlockNumber(n2); - return summaries.getSummaryEdges(num1, num2, d1); - } - - public Collection> getSeeds() { - return TabulationSolver.this.getSeeds(); - } - } - - /** - * @return Returns the supergraph. - */ - public ISupergraph getSupergraph() { - return supergraph; - } - - protected class Worklist extends Heap> implements ITabulationWorklist { - - Worklist() { - super(100); - } - - @Override - protected boolean compareElements(PathEdge p1, PathEdge p2) { - return problem.getDomain().hasPriorityOver(p1, p2); - } - - } - - /** - * @return set of d1 s.t. (n1,d1) -> (n2,d2) is recorded as a summary edge, or null if none found - * @throws UnsupportedOperationException unconditionally - */ - public IntSet getSummarySources(T n2, int d2, T n1) throws UnsupportedOperationException { - throw new UnsupportedOperationException("not currently supported. be careful"); - // LocalSummaryEdges summaries = summaryEdges.get(supergraph.getProcOf(n1)); - // if (summaries == null) { - // return null; - // } - // int num1 = supergraph.getLocalBlockNumber(n1); - // int num2 = supergraph.getLocalBlockNumber(n2); - // return summaries.getInvertedSummaryEdgesForTarget(num1, num2, d2); - } - - public TabulationProblem getProblem() { - return problem; - } - - public Collection> getSeeds() { - return Collections.unmodifiableCollection(allSeeds); - } - - public IProgressMonitor getProgressMonitor() { - return progressMonitor; - } - - protected PathEdge getCurPathEdge() { - return curPathEdge; - } - - protected PathEdge getCurSummaryEdge() { - return curSummaryEdge; - } -} +/******************************************************************************* + * 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.dataflow.IFDS; + +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.Comparator; +import java.util.Iterator; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Set; +import java.util.TreeMap; +import java.util.TreeSet; + +import com.ibm.wala.cfg.IBasicBlock; +import com.ibm.wala.util.CancelException; +import com.ibm.wala.util.CancelRuntimeException; +import com.ibm.wala.util.MonitorUtil; +import com.ibm.wala.util.MonitorUtil.IProgressMonitor; +import com.ibm.wala.util.collections.HashMapFactory; +import com.ibm.wala.util.collections.HashSetFactory; +import com.ibm.wala.util.collections.Heap; +import com.ibm.wala.util.collections.Iterator2Collection; +import com.ibm.wala.util.collections.MapUtil; +import com.ibm.wala.util.collections.ToStringComparator; +import com.ibm.wala.util.heapTrace.HeapTracer; +import com.ibm.wala.util.intset.IntIterator; +import com.ibm.wala.util.intset.IntSet; +import com.ibm.wala.util.intset.IntSetAction; +import com.ibm.wala.util.intset.MutableIntSet; +import com.ibm.wala.util.intset.MutableSparseIntSet; +import com.ibm.wala.util.ref.ReferenceCleanser; + +/** + * A precise interprocedural tabulation solver. + *

        + * See Reps, Horwitz, Sagiv POPL 95. + *

        + * This version differs in some ways from the POPL algorithm. In particular ... + *

          + *
        • to support exceptional control flow ... there may be several return sites for each call site. + *
        • it supports an optional merge operator, useful for non-IFDS problems and widening. + *
        • it stores summary edges at each callee instead of at each call site. + *
        + *

        + * + * @param type of node in the supergraph + * @param

        type of a procedure (like a box in an RSM) + * @param type of factoids propagated when solving this problem + */ +public class TabulationSolver { + + /** + * DEBUG_LEVEL: + *

          + *
        • 0 No output + *
        • 1 Print some simple stats and warning information + *
        • 2 Detailed debugging + *
        • 3 Also print worklists + *
        + */ + protected static final int DEBUG_LEVEL = 0; + + static protected final boolean verbose = true && ("true".equals(System.getProperty("com.ibm.wala.fixedpoint.impl.verbose")) ? true + : false); + + static final int VERBOSE_INTERVAL = 1000; + + static final boolean VERBOSE_TRACE_MEMORY = false; + + private static int verboseCounter = 0; + + /** + * Should we periodically clear out soft reference caches in an attempt to help the GC? + */ + final protected static boolean PERIODIC_WIPE_SOFT_CACHES = true; + + /** + * Interval which defines the period to clear soft reference caches + */ + private final static int WIPE_SOFT_CACHE_INTERVAL = 1000000; + + /** + * Counter for wiping soft caches + */ + private static int wipeCount = WIPE_SOFT_CACHE_INTERVAL; + + /** + * The supergraph which induces this dataflow problem + */ + protected final ISupergraph supergraph; + + /** + * A map from an edge in a supergraph to a flow function + */ + protected final IFlowFunctionMap flowFunctionMap; + + /** + * The problem being solved. + */ + private final TabulationProblem problem; + + /** + * A map from Object (entry node in supergraph) -> LocalPathEdges. + * + * Logically, this represents a set of edges (s_p,d_i) -> (n, d_j). The data structure is chosen to attempt to save space over + * representing each edge explicitly. + */ + final private Map pathEdges = HashMapFactory.make(); + + /** + * A map from Object (entry node in supergraph) -> CallFlowEdges. + * + * Logically, this represents a set of edges (c,d_i) -> (s_p, d_j). The data structure is chosen to attempt to save space over + * representing each edge explicitly. + */ + final private Map callFlowEdges = HashMapFactory.make(); + + /** + * A map from Object (procedure) -> LocalSummaryEdges. + * + */ + final protected Map summaryEdges = HashMapFactory.make(); + + /** + * the set of all {@link PathEdge}s that were used as seeds during the tabulation, grouped by procedure. + */ + private final Map>> seeds = HashMapFactory.make(); + + /** + * All seeds, stored redundantly for quick access. + */ + private final Set> allSeeds = HashSetFactory.make(); + + /** + * The worklist + */ + private ITabulationWorklist worklist; + + /** + * A progress monitor. can be null. + */ + protected final IProgressMonitor progressMonitor; + + /** + * the path edge currently being processed in the main loop of {@link #forwardTabulateSLRPs()}; null if + * {@link #forwardTabulateSLRPs()} is not currently running. Note that if we are applying a summary edge in + * {@link #processExit(PathEdge)}, curPathEdge is modified to be the path edge terminating at the call node in the caller, to + * match the behavior in {@link #processCall(PathEdge)}. + */ + private PathEdge curPathEdge; + + /** + * the summary edge currently being applied in {@link #processCall(PathEdge)} or {@link #processExit(PathEdge)}, or + * null if summary edges are not currently being processed. + */ + private PathEdge curSummaryEdge; + + /** + * @param p a description of the dataflow problem to solve + * @throws IllegalArgumentException if p is null + */ + protected TabulationSolver(TabulationProblem p, IProgressMonitor monitor) { + if (p == null) { + throw new IllegalArgumentException("p is null"); + } + this.supergraph = p.getSupergraph(); + this.flowFunctionMap = p.getFunctionMap(); + this.problem = p; + this.progressMonitor = monitor; + } + + /** + * Subclasses can override this to plug in a different worklist implementation. + */ + protected ITabulationWorklist makeWorklist() { + return new Worklist(); + } + + /** + * @param p a description of the dataflow problem to solve + * @throws IllegalArgumentException if p is null + */ + public static TabulationSolver make(TabulationProblem p) { + return new TabulationSolver(p, null); + } + + /** + * Solve the dataflow problem. + * + * @return a representation of the result + */ + public TabulationResult solve() throws CancelException { + + try { + initialize(); + forwardTabulateSLRPs(); + Result r = new Result(); + return r; + } catch (CancelException e) { + // store a partially-tabulated result in the thrown exception. + Result r = new Result(); + throw new TabulationCancelException(e, r); + } catch (CancelRuntimeException e) { + // store a partially-tabulated result in the thrown exception. + Result r = new Result(); + throw new TabulationCancelException(e, r); + } + } + + /** + * Start tabulation with the initial seeds. + */ + protected void initialize() { + for (PathEdge seed : problem.initialSeeds()) { + addSeed(seed); + } + } + + /** + * Restart tabulation from a particular path edge. Use with care. + */ + public void addSeed(PathEdge seed) { + Set> s = MapUtil.findOrCreateSet(seeds, supergraph.getProcOf(seed.entry)); + s.add(seed); + allSeeds.add(seed); + propagate(seed.entry, seed.d1, seed.target, seed.d2); + } + + /** + * See POPL 95 paper for this algorithm, Figure 3 + * + * @throws CancelException + */ + private void forwardTabulateSLRPs() throws CancelException { + assert curPathEdge == null : "curPathEdge should not be non-null here"; + if (worklist == null) { + worklist = makeWorklist(); + } + while (worklist.size() > 0) { + MonitorUtil.throwExceptionIfCanceled(progressMonitor); + if (verbose) { + performVerboseAction(); + } + if (PERIODIC_WIPE_SOFT_CACHES) { + tendToSoftCaches(); + } + + final PathEdge edge = popFromWorkList(); + if (DEBUG_LEVEL > 0) { + System.err.println("TABULATE " + edge); + } + curPathEdge = edge; + int j = merge(edge.entry, edge.d1, edge.target, edge.d2); + if (j == -1 && DEBUG_LEVEL > 0) { + System.err.println("merge -1: DROPPING"); + } + if (j != -1) { + if (j != edge.d2) { + // this means that we don't want to push the edge. instead, + // we'll push the merged fact. a little tricky, but i think should + // work. + if (DEBUG_LEVEL > 0) { + System.err.println("propagating merged fact " + j); + } + propagate(edge.entry, edge.d1, edge.target, j); + } else { + if (supergraph.isCall(edge.target)) { + // [13] + processCall(edge); + } else if (supergraph.isExit(edge.target)) { + // [21] + processExit(edge); + } else { + // [33] + processNormal(edge); + } + } + } + } + curPathEdge = null; + } + + /** + * For some reason (either a bug in our code that defeats soft references, or a bad policy in the GC), leaving soft reference + * caches to clear themselves out doesn't work. Help it out. + * + * It's unfortunate that this method exits. + */ + protected void tendToSoftCaches() { + wipeCount++; + if (wipeCount > WIPE_SOFT_CACHE_INTERVAL) { + wipeCount = 0; + ReferenceCleanser.clearSoftCaches(); + } + } + + /** + * + */ + protected final void performVerboseAction() { + verboseCounter++; + if (verboseCounter % VERBOSE_INTERVAL == 0) { + System.err.println("Tabulation Solver " + verboseCounter); + System.err.println(" " + peekFromWorkList()); + if (VERBOSE_TRACE_MEMORY) { + ReferenceCleanser.clearSoftCaches(); + System.err.println("Analyze leaks.."); + HeapTracer.traceHeap(Collections.singleton(this), true); + System.err.println("done analyzing leaks"); + } + } + } + + /** + * Handle lines [33-37] of the algorithm + * + * @param edge + */ + private void processNormal(final PathEdge edge) { + if (DEBUG_LEVEL > 0) { + System.err.println("process normal: " + edge); + } + for (Iterator it = supergraph.getSuccNodes(edge.target); it.hasNext();) { + final T m = it.next(); + if (DEBUG_LEVEL > 0) { + System.err.println("normal successor: " + m); + } + IUnaryFlowFunction f = flowFunctionMap.getNormalFlowFunction(edge.target, m); + IntSet D3 = computeFlow(edge.d2, f); + if (DEBUG_LEVEL > 0) { + System.err.println(" reached: " + D3); + } + if (D3 != null) { + D3.foreach(new IntSetAction() { + public void act(int d3) { + propagate(edge.entry, edge.d1, m, d3); + } + }); + } + } + } + + /** + * Handle lines [21 - 32] of the algorithm, propagating information from an exit node. + * + * Note that we've changed the way we record summary edges. Summary edges are now associated with a callee (s_p,exit), where the + * original algorithm used a call, return pair in the caller. + */ + protected void processExit(final PathEdge edge) { + if (DEBUG_LEVEL > 0) { + System.err.println("process exit: " + edge); + } + + final LocalSummaryEdges summaries = findOrCreateLocalSummaryEdges(supergraph.getProcOf(edge.target)); + int s_p_n = supergraph.getLocalBlockNumber(edge.entry); + int x = supergraph.getLocalBlockNumber(edge.target); + if (!summaries.contains(s_p_n, x, edge.d1, edge.d2)) { + summaries.insertSummaryEdge(s_p_n, x, edge.d1, edge.d2); + } + assert curSummaryEdge == null : "curSummaryEdge should be null here"; + curSummaryEdge = edge; + + final CallFlowEdges callFlow = findOrCreateCallFlowEdges(edge.entry); + + // [22] for each c /in callers(p) + IntSet callFlowSourceNodes = callFlow.getCallFlowSourceNodes(edge.d1); + if (callFlowSourceNodes != null) { + for (IntIterator it = callFlowSourceNodes.intIterator(); it.hasNext();) { + // [23] for each d4 s.t. -> occurred earlier + int globalC = it.next(); + final IntSet D4 = callFlow.getCallFlowSources(globalC, edge.d1); + + // [23] for each d5 s.t. -> ... + propagateToReturnSites(edge, supergraph.getNode(globalC), D4); + } + } + curSummaryEdge = null; + } + + /** + * Propagate information for an "exit" edge to the appropriate return sites + * + * [23] for each d5 s.t. -> .. + * + * @param edge the edge being processed + * @param succ numbers of the nodes that are successors of edge.n (the return block in the callee) in the call graph. + * @param c a call site of edge.s_p + * @param D4 set of d1 s.t. -> was recorded as call flow + */ + private void propagateToReturnSites(final PathEdge edge, final T c, final IntSet D4) { + P proc = supergraph.getProcOf(c); + final T[] entries = supergraph.getEntriesForProcedure(proc); + + // we iterate over each potential return site; + // we might have multiple return sites due to exceptions + // note that we might have different summary edges for each + // potential return site, and different flow functions from this + // exit block to each return site. + for (Iterator retSites = supergraph.getReturnSites(c, supergraph.getProcOf(edge.target)); retSites.hasNext();) { + final T retSite = retSites.next(); + if (DEBUG_LEVEL > 1) { + System.err.println("candidate return site: " + retSite + " " + supergraph.getNumber(retSite)); + } + // note: since we might have multiple exit nodes for the callee, (to handle exceptional returns) + // not every return site might be valid for this exit node (edge.n). + // so, we'll filter the logic by checking that we only process reachable return sites. + // the supergraph carries the information regarding the legal successors + // of the exit node + if (!supergraph.hasEdge(edge.target, retSite)) { + continue; + } + if (DEBUG_LEVEL > 1) { + System.err.println("feasible return site: " + retSite); + } + final IFlowFunction retf = flowFunctionMap.getReturnFlowFunction(c, edge.target, retSite); + if (retf instanceof IBinaryReturnFlowFunction) { + propagateToReturnSiteWithBinaryFlowFunction(edge, c, D4, entries, retSite, retf); + } else { + final IntSet D5 = computeFlow(edge.d2, (IUnaryFlowFunction) retf); + if (DEBUG_LEVEL > 1) { + System.err.println("D4" + D4); + System.err.println("D5 " + D5); + } + IntSetAction action = new IntSetAction() { + public void act(final int d4) { + propToReturnSite(c, entries, retSite, d4, D5); + } + }; + D4.foreach(action); + } + } + } + + /** + * Propagate information for an "exit" edge to a caller return site + * + * [23] for each d5 s.t. -> .. + * + * @param edge the edge being processed + * @param c a call site of edge.s_p + * @param D4 set of d1 s.t. -> was recorded as call flow + * @param entries the blocks in the supergraph that are entries for the procedure of c + * @param retSite the return site being propagated to + * @param retf the flow function + */ + private void propagateToReturnSiteWithBinaryFlowFunction(final PathEdge edge, final T c, final IntSet D4, final T[] entries, + final T retSite, final IFlowFunction retf) { + D4.foreach(new IntSetAction() { + public void act(final int d4) { + final IntSet D5 = computeBinaryFlow(d4, edge.d2, (IBinaryReturnFlowFunction) retf); + propToReturnSite(c, entries, retSite, d4, D5); + } + + }); + } + + /** + * Propagate information to a particular return site. + * + * @param c the corresponding call site + * @param entries entry nodes in the caller + * @param retSite the return site + * @param d4 a fact s.t. -> was recorded as call flow and is the source of the summary edge + * being applied + * @param D5 facts to propagate to return site + */ + private void propToReturnSite(final T c, final T[] entries, final T retSite, final int d4, final IntSet D5) { + if (D5 != null) { + D5.foreach(new IntSetAction() { + public void act(final int d5) { + // [26 - 28] + // note that we've modified the algorithm here to account + // for potential + // multiple entry nodes. Instead of propagating the new + // summary edge + // with respect to one s_profOf(c), we have to propagate + // for each + // potential entry node s_p /in s_procof(c) + for (int i = 0; i < entries.length; i++) { + final T s_p = entries[i]; + if (DEBUG_LEVEL > 1) { + System.err.println(" do entry " + s_p); + } + IntSet D3 = getInversePathEdges(s_p, c, d4); + if (DEBUG_LEVEL > 1) { + System.err.println("D3" + D3); + } + if (D3 != null) { + D3.foreach(new IntSetAction() { + public void act(int d3) { + // set curPathEdge to be consistent with its setting in processCall() when applying a summary edge + curPathEdge = PathEdge.createPathEdge(s_p, d3, c, d4); + propagate(s_p, d3, retSite, d5); + } + }); + } + } + } + }); + } + } + + /** + * @param s_p + * @param n + * @param d2 note that s_p must be an entry for procof(n) + * @return set of d1 s.t. -> is a path edge, or null if none found + */ + protected IntSet getInversePathEdges(T s_p, T n, int d2) { + int number = supergraph.getLocalBlockNumber(n); + LocalPathEdges lp = pathEdges.get(s_p); + if (lp == null) { + return null; + } + return lp.getInverse(number, d2); + } + + /** + * Handle lines [14 - 19] of the algorithm, propagating information into and across a call site. + */ + protected void processCall(final PathEdge edge) { + if (DEBUG_LEVEL > 0) { + System.err.println("process call: " + edge); + } + + // c:= number of the call node + final int c = supergraph.getNumber(edge.target); + + Collection allReturnSites = HashSetFactory.make(); + // populate allReturnSites with return sites for missing calls. + for (Iterator it = supergraph.getReturnSites(edge.target, null); it.hasNext();) { + allReturnSites.add(it.next()); + } + // [14 - 16] + boolean hasCallee = false; + for (Iterator it = supergraph.getCalledNodes(edge.target); it.hasNext();) { + hasCallee = true; + final T callee = it.next(); + processParticularCallee(edge, c, allReturnSites, callee); + } + // special logic: in backwards problems, a "call" node can have + // "normal" successors as well. deal with these. + for (Iterator it = supergraph.getNormalSuccessors(edge.target); it.hasNext();) { + final T m = it.next(); + if (DEBUG_LEVEL > 0) { + System.err.println("normal successor: " + m); + } + IUnaryFlowFunction f = flowFunctionMap.getNormalFlowFunction(edge.target, m); + IntSet D3 = computeFlow(edge.d2, f); + if (DEBUG_LEVEL > 0) { + System.err.println("normal successor reached: " + D3); + } + if (D3 != null) { + D3.foreach(new IntSetAction() { + public void act(int d3) { + propagate(edge.entry, edge.d1, m, d3); + } + }); + } + } + + // [17 - 19] + // we modify this to handle each return site individually + for (final T returnSite : allReturnSites) { + if (DEBUG_LEVEL > 0) { + System.err.println(" process return site: " + returnSite); + } + IUnaryFlowFunction f = null; + if (hasCallee) { + f = flowFunctionMap.getCallToReturnFlowFunction(edge.target, returnSite); + } else { + f = flowFunctionMap.getCallNoneToReturnFlowFunction(edge.target, returnSite); + } + IntSet reached = computeFlow(edge.d2, f); + if (DEBUG_LEVEL > 0) { + System.err.println("reached: " + reached); + } + if (reached != null) { + reached.foreach(new IntSetAction() { + public void act(int x) { + assert x >= 0; + assert edge.d1 >= 0; + propagate(edge.entry, edge.d1, returnSite, x); + } + }); + } + } + } + + /** + * handle a particular callee for some call node. + * + * @param edge the path edge being processed + * @param callNodeNum the number of the call node in the supergraph + * @param allReturnSites a set collecting return sites for the call. This set is mutated with the return sites for this callee. + * @param calleeEntry the entry node of the callee in question + */ + protected void processParticularCallee(final PathEdge edge, final int callNodeNum, Collection allReturnSites, final T calleeEntry) { + if (DEBUG_LEVEL > 0) { + System.err.println(" process callee: " + calleeEntry); + } + // reached := {d1} that reach the callee + MutableSparseIntSet reached = MutableSparseIntSet.makeEmpty(); + final Collection returnSitesForCallee = Iterator2Collection.toSet(supergraph.getReturnSites(edge.target, supergraph + .getProcOf(calleeEntry))); + allReturnSites.addAll(returnSitesForCallee); + // we modify this to handle each return site individually. Some types of problems + // compute different flow functions for each return site. + for (final T returnSite : returnSitesForCallee) { + IUnaryFlowFunction f = flowFunctionMap.getCallFlowFunction(edge.target, calleeEntry, returnSite); + IntSet r = computeFlow(edge.d2, f); + if (r != null) { + reached.addAll(r); + } + } + // in some problems, we also want to consider flow into a callee that can never flow out + // via a return. in this case, the return site is null. + IUnaryFlowFunction f = flowFunctionMap.getCallFlowFunction(edge.target, calleeEntry, null); + IntSet r = computeFlow(edge.d2, f); + if (r != null) { + reached.addAll(r); + } + if (DEBUG_LEVEL > 0) { + System.err.println(" reached: " + reached); + } + if (reached != null) { + final LocalSummaryEdges summaries = summaryEdges.get(supergraph.getProcOf(calleeEntry)); + final CallFlowEdges callFlow = findOrCreateCallFlowEdges(calleeEntry); + final int s_p_num = supergraph.getLocalBlockNumber(calleeEntry); + + reached.foreach(new IntSetAction() { + public void act(final int d1) { + // we get reuse if we _don't_ propagate a new fact to the callee entry + final boolean gotReuse = !propagate(calleeEntry, d1, calleeEntry, d1); + recordCall(edge.target, calleeEntry, d1, gotReuse); + // cache the fact that we've flowed -> by a + // call flow + callFlow.addCallEdge(callNodeNum, edge.d2, d1); + // handle summary edges now as well. this is different from the PoPL + // 95 paper. + if (summaries != null) { + // for each exit from the callee + P p = supergraph.getProcOf(calleeEntry); + T[] exits = supergraph.getExitsForProcedure(p); + for (int e = 0; e < exits.length; e++) { + final T exit = exits[e]; + if (DEBUG_LEVEL > 0) { + assert supergraph.containsNode(exit); + } + int x_num = supergraph.getLocalBlockNumber(exit); + // reachedBySummary := {d2} s.t. -> + // was recorded as a summary edge + IntSet reachedBySummary = summaries.getSummaryEdges(s_p_num, x_num, d1); + if (reachedBySummary != null) { + for (final T returnSite : returnSitesForCallee) { + // if "exit" is a valid exit from the callee to the return + // site being processed + if (supergraph.hasEdge(exit, returnSite)) { + final IFlowFunction retf = flowFunctionMap.getReturnFlowFunction(edge.target, exit, returnSite); + reachedBySummary.foreach(new IntSetAction() { + public void act(int d2) { + assert curSummaryEdge == null : "curSummaryEdge should be null here"; + curSummaryEdge = PathEdge.createPathEdge(calleeEntry, d1, exit, d2); + if (retf instanceof IBinaryReturnFlowFunction) { + final IntSet D5 = computeBinaryFlow(edge.d2, d2, (IBinaryReturnFlowFunction) retf); + if (D5 != null) { + D5.foreach(new IntSetAction() { + public void act(int d5) { + propagate(edge.entry, edge.d1, returnSite, d5); + } + }); + } + } else { + final IntSet D5 = computeFlow(d2, (IUnaryFlowFunction) retf); + if (D5 != null) { + D5.foreach(new IntSetAction() { + public void act(int d5) { + propagate(edge.entry, edge.d1, returnSite, d5); + } + }); + } + } + curSummaryEdge = null; + } + }); + } + } + } + } + } + } + }); + } + } + + /** + * invoked when a callee is processed with a particular entry fact + * + * @param callNode + * @param callee + * @param d1 the entry fact + * @param gotReuse whether existing summary edges were applied + */ + protected void recordCall(T callNode, T callee, int d1, boolean gotReuse) { + } + + /** + * @return f(call_d, exit_d); + * + */ + protected IntSet computeBinaryFlow(int call_d, int exit_d, IBinaryReturnFlowFunction f) { + if (DEBUG_LEVEL > 0) { + System.err.println("got binary flow function " + f); + } + IntSet result = f.getTargets(call_d, exit_d); + return result; + } + + /** + * @return f(d1) + * + */ + protected IntSet computeFlow(int d1, IUnaryFlowFunction f) { + if (DEBUG_LEVEL > 0) { + System.err.println("got flow function " + f); + } + IntSet result = f.getTargets(d1); + + if (result == null) { + return null; + } else { + return result; + } + } + + /** + * @return f^{-1}(d2) + */ + protected IntSet computeInverseFlow(int d2, IReversibleFlowFunction f) { + return f.getSources(d2); + } + + protected PathEdge popFromWorkList() { + assert worklist != null; + return worklist.take(); + } + + private PathEdge peekFromWorkList() { + // horrible. don't use in performance-critical + assert worklist != null; + PathEdge result = worklist.take(); + worklist.insert(result); + return result; + } + + /** + * Propagate the fact -> has arisen as a path edge. Returns true iff the path edge was not previously + * observed. + * + * @param s_p entry block + * @param i dataflow fact on entry + * @param n reached block + * @param j dataflow fact reached + */ + protected boolean propagate(T s_p, int i, T n, int j) { + int number = supergraph.getLocalBlockNumber(n); + if (number < 0) { + System.err.println("BOOM " + n); + supergraph.getLocalBlockNumber(n); + } + assert number >= 0; + + LocalPathEdges pLocal = findOrCreateLocalPathEdges(s_p); + + assert j >= 0; + + if (!pLocal.contains(i, number, j)) { + if (DEBUG_LEVEL > 0) { + System.err.println("propagate " + s_p + " " + i + " " + number + " " + j); + } + pLocal.addPathEdge(i, number, j); + addToWorkList(s_p, i, n, j); + return true; + } + return false; + } + + public LocalPathEdges getLocalPathEdges(T s_p) { + return pathEdges.get(s_p); + } + + /** + * Merging: suppose we're doing propagate -> but we already have path edges -> , -> , and + * ->. + * + * let \alpha be the merge function. then instead of -> , we propagate -> !!! + * + * return -1 if no fact should be propagated + */ + private int merge(T s_p, int i, T n, int j) { + assert j >= 0; + IMergeFunction alpha = problem.getMergeFunction(); + if (alpha != null) { + LocalPathEdges lp = pathEdges.get(s_p); + IntSet preExistFacts = lp.getReachable(supergraph.getLocalBlockNumber(n), i); + if (preExistFacts == null) { + return j; + } else { + int size = preExistFacts.size(); + if ((size == 0) || ((size == 1) && preExistFacts.contains(j))) { + return j; + } else { + int result = alpha.merge(preExistFacts, j); + return result; + } + } + } else { + return j; + } + } + + protected void addToWorkList(T s_p, int i, T n, int j) { + if (worklist == null) { + worklist = makeWorklist(); + } + worklist.insert(PathEdge.createPathEdge(s_p, i, n, j)); + if (DEBUG_LEVEL >= 3) { + System.err.println("WORKLIST: " + worklist); + } + } + + protected LocalPathEdges findOrCreateLocalPathEdges(T s_p) { + LocalPathEdges result = pathEdges.get(s_p); + if (result == null) { + result = makeLocalPathEdges(); + pathEdges.put(s_p, result); + } + return result; + } + + private LocalPathEdges makeLocalPathEdges() { + return problem.getMergeFunction() == null ? new LocalPathEdges(false) : new LocalPathEdges(true); + } + + protected LocalSummaryEdges findOrCreateLocalSummaryEdges(P proc) { + LocalSummaryEdges result = summaryEdges.get(proc); + if (result == null) { + result = new LocalSummaryEdges(); + summaryEdges.put(proc, result); + } + return result; + } + + protected CallFlowEdges findOrCreateCallFlowEdges(T s_p) { + CallFlowEdges result = callFlowEdges.get(s_p); + if (result == null) { + result = new CallFlowEdges(); + callFlowEdges.put(s_p, result); + } + return result; + } + + /** + * get the bitvector of facts that hold at the entry to a given node + * + * @return IntSet representing the bitvector + */ + public IntSet getResult(T node) { + P proc = supergraph.getProcOf(node); + int n = supergraph.getLocalBlockNumber(node); + T[] entries = supergraph.getEntriesForProcedure(proc); + MutableIntSet result = MutableSparseIntSet.makeEmpty(); + + Set allEntries = HashSetFactory.make(Arrays.asList(entries)); + Set> pSeeds = seeds.get(proc); + if (pSeeds != null) { + for (PathEdge seed : pSeeds) { + allEntries.add(seed.entry); + } + } + + for (T entry : allEntries){ + LocalPathEdges lp = pathEdges.get(entry); + if (lp != null) { + result.addAll(lp.getReachable(n)); + } + } + + return result; + } + + public class Result implements TabulationResult { + + /** + * get the bitvector of facts that hold at the entry to a given node + * + * @return IntSet representing the bitvector + */ + public IntSet getResult(T node) { + return TabulationSolver.this.getResult(node); + } + + @Override + public String toString() { + + StringBuffer result = new StringBuffer(); + TreeMap> map = new TreeMap>(ToStringComparator.instance()); + + Comparator c = new Comparator() { + public int compare(Object o1, Object o2) { + if (!(o1 instanceof IBasicBlock)) { + return -1; + } + IBasicBlock bb1 = (IBasicBlock) o1; + IBasicBlock bb2 = (IBasicBlock) o2; + return bb1.getNumber() - bb2.getNumber(); + } + }; + for (Iterator it = supergraph.iterator(); it.hasNext();) { + T n = it.next(); + P proc = supergraph.getProcOf(n); + TreeSet s = map.get(proc); + if (s == null) { + s = new TreeSet(c); + map.put(proc, s); + } + s.add(n); + } + + for (Iterator>> it = map.entrySet().iterator(); it.hasNext();) { + Map.Entry> e = it.next(); + Set s = e.getValue(); + for (Iterator it2 = s.iterator(); it2.hasNext();) { + T o = it2.next(); + result.append(o + " : " + getResult(o) + "\n"); + } + } + return result.toString(); + } + + /* + * @see com.ibm.wala.dataflow.IFDS.TabulationResult#getProblem() + */ + public TabulationProblem getProblem() { + return problem; + } + + /* + * @see com.ibm.wala.dataflow.IFDS.TabulationResult#getSupergraphNodesReached() + */ + public Collection getSupergraphNodesReached() { + Collection result = HashSetFactory.make(); + for (Entry e : pathEdges.entrySet()) { + T key = e.getKey(); + P proc = supergraph.getProcOf(key); + IntSet reached = e.getValue().getReachedNodeNumbers(); + for (IntIterator ii = reached.intIterator(); ii.hasNext();) { + result.add(supergraph.getLocalBlock(proc, ii.next())); + } + } + + return result; + } + + /** + * @param n1 + * @param d1 + * @param n2 + * @return set of d2 s.t. (n1,d1) -> (n2,d2) is recorded as a summary edge, or null if none found + */ + public IntSet getSummaryTargets(T n1, int d1, T n2) { + LocalSummaryEdges summaries = summaryEdges.get(supergraph.getProcOf(n1)); + if (summaries == null) { + return null; + } + int num1 = supergraph.getLocalBlockNumber(n1); + int num2 = supergraph.getLocalBlockNumber(n2); + return summaries.getSummaryEdges(num1, num2, d1); + } + + public Collection> getSeeds() { + return TabulationSolver.this.getSeeds(); + } + } + + /** + * @return Returns the supergraph. + */ + public ISupergraph getSupergraph() { + return supergraph; + } + + protected class Worklist extends Heap> implements ITabulationWorklist { + + Worklist() { + super(100); + } + + @Override + protected boolean compareElements(PathEdge p1, PathEdge p2) { + return problem.getDomain().hasPriorityOver(p1, p2); + } + + } + + /** + * @return set of d1 s.t. (n1,d1) -> (n2,d2) is recorded as a summary edge, or null if none found + * @throws UnsupportedOperationException unconditionally + */ + public IntSet getSummarySources(T n2, int d2, T n1) throws UnsupportedOperationException { + throw new UnsupportedOperationException("not currently supported. be careful"); + // LocalSummaryEdges summaries = summaryEdges.get(supergraph.getProcOf(n1)); + // if (summaries == null) { + // return null; + // } + // int num1 = supergraph.getLocalBlockNumber(n1); + // int num2 = supergraph.getLocalBlockNumber(n2); + // return summaries.getInvertedSummaryEdgesForTarget(num1, num2, d2); + } + + public TabulationProblem getProblem() { + return problem; + } + + public Collection> getSeeds() { + return Collections.unmodifiableCollection(allSeeds); + } + + public IProgressMonitor getProgressMonitor() { + return progressMonitor; + } + + protected PathEdge getCurPathEdge() { + return curPathEdge; + } + + protected PathEdge getCurSummaryEdge() { + return curSummaryEdge; + } +} diff --git a/com.ibm.wala.core/src/com/ibm/wala/dataflow/IFDS/UnorderedDomain.java b/com.ibm.wala.core/src/com/ibm/wala/dataflow/IFDS/UnorderedDomain.java index 67b6a7a75..310e8dd16 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/dataflow/IFDS/UnorderedDomain.java +++ b/com.ibm.wala.core/src/com/ibm/wala/dataflow/IFDS/UnorderedDomain.java @@ -1,27 +1,27 @@ -/******************************************************************************* - * Copyright (c) 2002 - 2006 IBM Corporation. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * IBM Corporation - initial API and implementation - *******************************************************************************/ -package com.ibm.wala.dataflow.IFDS; - -import com.ibm.wala.util.intset.MutableMapping; - -/** - * A {@link TabulationDomain} with no build-in partial order defining priority. - */ -public class UnorderedDomain extends MutableMapping implements TabulationDomain { - - /* - * @see com.ibm.wala.dataflow.IFDS.TabulationDomain#isWeakerThan(int, int) - */ - public boolean hasPriorityOver(PathEdge p1, PathEdge p2) { - return false; - } - -} +/******************************************************************************* + * 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.dataflow.IFDS; + +import com.ibm.wala.util.intset.MutableMapping; + +/** + * A {@link TabulationDomain} with no build-in partial order defining priority. + */ +public class UnorderedDomain extends MutableMapping implements TabulationDomain { + + /* + * @see com.ibm.wala.dataflow.IFDS.TabulationDomain#isWeakerThan(int, int) + */ + public boolean hasPriorityOver(PathEdge p1, PathEdge p2) { + return false; + } + +} diff --git a/com.ibm.wala.core/src/com/ibm/wala/dataflow/IFDS/VectorGenFlowFunction.java b/com.ibm.wala.core/src/com/ibm/wala/dataflow/IFDS/VectorGenFlowFunction.java index e4d140df3..e3e03eba6 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/dataflow/IFDS/VectorGenFlowFunction.java +++ b/com.ibm.wala.core/src/com/ibm/wala/dataflow/IFDS/VectorGenFlowFunction.java @@ -1,53 +1,53 @@ -/******************************************************************************* - * Copyright (c) 2002 - 2006 IBM Corporation. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * IBM Corporation - initial API and implementation - *******************************************************************************/ -package com.ibm.wala.dataflow.IFDS; - -import com.ibm.wala.util.intset.IntSet; -import com.ibm.wala.util.intset.SparseIntSet; - -/** - * A function which gens a vector of outgoing dataflow facts - */ -public class VectorGenFlowFunction implements IReversibleFlowFunction { - - private final IntSet gen; - - /** - * @param gen the intset of facts which are gen'ned by this flow function - */ - private VectorGenFlowFunction(IntSet gen) { - this.gen = gen; - } - - public IntSet getTargets(int i) { - return (i == 0) ? gen : gen.contains(i) ? null : SparseIntSet.singleton(i); - } - - public IntSet getSources(int i) { - return (gen.contains(i)) ? SparseIntSet.singleton(0) : SparseIntSet.singleton(i); - } - - /** - * @param gen the intset of facts which should be gen'ed by a function - * @return an instance of a flow function which gens these facts - */ - public static VectorGenFlowFunction make(IntSet gen) { - if (gen == null) { - throw new IllegalArgumentException("null gen"); - } - return new VectorGenFlowFunction(gen); - } - - @Override - public String toString() { - return "VectorGen: " + gen; - } -} +/******************************************************************************* + * 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.dataflow.IFDS; + +import com.ibm.wala.util.intset.IntSet; +import com.ibm.wala.util.intset.SparseIntSet; + +/** + * A function which gens a vector of outgoing dataflow facts + */ +public class VectorGenFlowFunction implements IReversibleFlowFunction { + + private final IntSet gen; + + /** + * @param gen the intset of facts which are gen'ned by this flow function + */ + private VectorGenFlowFunction(IntSet gen) { + this.gen = gen; + } + + public IntSet getTargets(int i) { + return (i == 0) ? gen : gen.contains(i) ? null : SparseIntSet.singleton(i); + } + + public IntSet getSources(int i) { + return (gen.contains(i)) ? SparseIntSet.singleton(0) : SparseIntSet.singleton(i); + } + + /** + * @param gen the intset of facts which should be gen'ed by a function + * @return an instance of a flow function which gens these facts + */ + public static VectorGenFlowFunction make(IntSet gen) { + if (gen == null) { + throw new IllegalArgumentException("null gen"); + } + return new VectorGenFlowFunction(gen); + } + + @Override + public String toString() { + return "VectorGen: " + gen; + } +} diff --git a/com.ibm.wala.core/src/com/ibm/wala/dataflow/IFDS/VectorKillFlowFunction.java b/com.ibm.wala.core/src/com/ibm/wala/dataflow/IFDS/VectorKillFlowFunction.java index f30d1ea2d..0f3cbf1e9 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/dataflow/IFDS/VectorKillFlowFunction.java +++ b/com.ibm.wala.core/src/com/ibm/wala/dataflow/IFDS/VectorKillFlowFunction.java @@ -1,49 +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.dataflow.IFDS; - -import com.ibm.wala.util.intset.IntSet; -import com.ibm.wala.util.intset.SparseIntSet; - -/** - * A function which kills a vector of incoming dataflow facts - */ -public class VectorKillFlowFunction implements IReversibleFlowFunction { - - private final IntSet kill; - - /** - * @param kill the intset of facts which are killed by this flow function - */ - private VectorKillFlowFunction(IntSet kill) { - if (kill == null) { - throw new IllegalArgumentException("null kill"); - } - this.kill = kill; - } - - public IntSet getTargets(int i) { - return (kill.contains(i)) ? null : SparseIntSet.singleton(i); - } - - public IntSet getSources(int i) { - return (kill.contains(i)) ? null : SparseIntSet.singleton(i); - } - - /** - * @param kill the intset of facts which should be killed by a function - * @return an instance of a flow function which kills these facts - */ - public static VectorKillFlowFunction make(IntSet kill) { - return new VectorKillFlowFunction(kill); - } - -} +/******************************************************************************* + * 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.dataflow.IFDS; + +import com.ibm.wala.util.intset.IntSet; +import com.ibm.wala.util.intset.SparseIntSet; + +/** + * A function which kills a vector of incoming dataflow facts + */ +public class VectorKillFlowFunction implements IReversibleFlowFunction { + + private final IntSet kill; + + /** + * @param kill the intset of facts which are killed by this flow function + */ + private VectorKillFlowFunction(IntSet kill) { + if (kill == null) { + throw new IllegalArgumentException("null kill"); + } + this.kill = kill; + } + + public IntSet getTargets(int i) { + return (kill.contains(i)) ? null : SparseIntSet.singleton(i); + } + + public IntSet getSources(int i) { + return (kill.contains(i)) ? null : SparseIntSet.singleton(i); + } + + /** + * @param kill the intset of facts which should be killed by a function + * @return an instance of a flow function which kills these facts + */ + public static VectorKillFlowFunction make(IntSet kill) { + return new VectorKillFlowFunction(kill); + } + +} diff --git a/com.ibm.wala.core/src/com/ibm/wala/dataflow/ssa/SSAInference.java b/com.ibm.wala.core/src/com/ibm/wala/dataflow/ssa/SSAInference.java index 0d111c6ac..ce3ad5c5d 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/dataflow/ssa/SSAInference.java +++ b/com.ibm.wala.core/src/com/ibm/wala/dataflow/ssa/SSAInference.java @@ -1,167 +1,167 @@ -/******************************************************************************* - * 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.dataflow.ssa; - -import java.util.Iterator; - -import com.ibm.wala.analysis.typeInference.TypeInference; -import com.ibm.wala.fixedpoint.impl.DefaultFixedPointSolver; -import com.ibm.wala.fixedpoint.impl.NullaryOperator; -import com.ibm.wala.fixpoint.AbstractOperator; -import com.ibm.wala.fixpoint.IVariable; -import com.ibm.wala.ssa.IR; -import com.ibm.wala.ssa.SSAInstruction; -import com.ibm.wala.ssa.SymbolTable; - -/** - * This class performs intra-procedural propagation over an SSA form. - * - * A client will subclass an {@link SSAInference} by providing factories that generate {@link IVariable}s corresponding to SSA value - * numbers, and {@link AbstractOperator}s corresponding to SSA instructions. This class will set up a dataflow system induced by the - * SSA def-use graph, and solve the system by iterating to a fixed point. - * - * @see TypeInference for the canonical client of this machinery. - */ -public abstract class SSAInference> extends DefaultFixedPointSolver { - static final boolean DEBUG = false; - - /** - * The governing SSA form - */ - private IR ir; - - /** - * The governing symbol table - */ - private SymbolTable symbolTable; - - /** - * Dataflow variables, one for each value in the symbol table. - */ - private IVariable[] vars; - - public interface OperatorFactory { - /** - * Get the dataflow operator induced by an instruction in SSA form. - * - * @param instruction - * @return dataflow operator for the instruction, or null if the instruction is not applicable to the dataflow system. - */ - AbstractOperator get(SSAInstruction instruction); - } - - public interface VariableFactory { - /** - * Make the variable for a given value number. - * - * @return a newly created dataflow variable, or null if not applicable. - */ - public IVariable makeVariable(int valueNumber); - } - - /** - * initializer for SSA Inference equations. - */ - protected void init(IR ir, VariableFactory varFactory, OperatorFactory opFactory) { - - this.ir = ir; - this.symbolTable = ir.getSymbolTable(); - - createVariables(varFactory); - createEquations(opFactory); - } - - private void createEquations(OperatorFactory opFactory) { - SSAInstruction[] instructions = ir.getInstructions(); - for (int i = 0; i < instructions.length; i++) { - SSAInstruction s = instructions[i]; - makeEquationForInstruction(opFactory, s); - } - for (Iterator it = ir.iteratePhis(); it.hasNext();) { - SSAInstruction s = (SSAInstruction) it.next(); - makeEquationForInstruction(opFactory, s); - } - for (Iterator it = ir.iteratePis(); it.hasNext();) { - SSAInstruction s = (SSAInstruction) it.next(); - makeEquationForInstruction(opFactory, s); - } - for (Iterator it = ir.iterateCatchInstructions(); it.hasNext();) { - SSAInstruction s = (SSAInstruction) it.next(); - makeEquationForInstruction(opFactory, s); - } - } - - /** - * Create a dataflow equation induced by a given instruction - */ - private void makeEquationForInstruction(OperatorFactory opFactory, SSAInstruction s) { - if (s != null && s.hasDef()) { - AbstractOperator op = opFactory.get(s); - if (op != null) { - T def = getVariable(s.getDef()); - if (op instanceof NullaryOperator) { - newStatement(def, (NullaryOperator) op, false, false); - } else { - int n = s.getNumberOfUses(); - T[] uses = makeStmtRHS(n); - for (int j = 0; j < n; j++) { - if (s.getUse(j) > -1) { - uses[j] = getVariable(s.getUse(j)); - assert uses[j] != null; - } - } - newStatement(def, op, uses, false, false); - } - } - } - } - - /** - * Create a dataflow variable for each value number - */ - private void createVariables(VariableFactory factory) { - vars = new IVariable[symbolTable.getMaxValueNumber() + 1]; - for (int i = 1; i < vars.length; i++) { - vars[i] = factory.makeVariable(i); - } - - } - - /** - * @return the dataflow variable representing the value number, or null if none found. - */ - @SuppressWarnings("unchecked") - protected T getVariable(int valueNumber) { - if (valueNumber < 0) { - throw new IllegalArgumentException("Illegal valueNumber " + valueNumber); - } - if (DEBUG) { - System.err.println(("getVariable for " + valueNumber + " returns " + vars[valueNumber])); - } - assert vars != null : "null vars array"; - return (T) vars[valueNumber]; - } - - /** - * Return a string representation of the system - * - * @return a string representation of the system - */ - @Override - public String toString() { - StringBuffer result = new StringBuffer("Type inference : \n"); - for (int i = 0; i < vars.length; i++) { - result.append("v").append(i).append(" ").append(vars[i]).append("\n"); - } - return result.toString(); - } -} +/******************************************************************************* + * 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.dataflow.ssa; + +import java.util.Iterator; + +import com.ibm.wala.analysis.typeInference.TypeInference; +import com.ibm.wala.fixedpoint.impl.DefaultFixedPointSolver; +import com.ibm.wala.fixedpoint.impl.NullaryOperator; +import com.ibm.wala.fixpoint.AbstractOperator; +import com.ibm.wala.fixpoint.IVariable; +import com.ibm.wala.ssa.IR; +import com.ibm.wala.ssa.SSAInstruction; +import com.ibm.wala.ssa.SymbolTable; + +/** + * This class performs intra-procedural propagation over an SSA form. + * + * A client will subclass an {@link SSAInference} by providing factories that generate {@link IVariable}s corresponding to SSA value + * numbers, and {@link AbstractOperator}s corresponding to SSA instructions. This class will set up a dataflow system induced by the + * SSA def-use graph, and solve the system by iterating to a fixed point. + * + * @see TypeInference for the canonical client of this machinery. + */ +public abstract class SSAInference> extends DefaultFixedPointSolver { + static final boolean DEBUG = false; + + /** + * The governing SSA form + */ + private IR ir; + + /** + * The governing symbol table + */ + private SymbolTable symbolTable; + + /** + * Dataflow variables, one for each value in the symbol table. + */ + private IVariable[] vars; + + public interface OperatorFactory { + /** + * Get the dataflow operator induced by an instruction in SSA form. + * + * @param instruction + * @return dataflow operator for the instruction, or null if the instruction is not applicable to the dataflow system. + */ + AbstractOperator get(SSAInstruction instruction); + } + + public interface VariableFactory { + /** + * Make the variable for a given value number. + * + * @return a newly created dataflow variable, or null if not applicable. + */ + public IVariable makeVariable(int valueNumber); + } + + /** + * initializer for SSA Inference equations. + */ + protected void init(IR ir, VariableFactory varFactory, OperatorFactory opFactory) { + + this.ir = ir; + this.symbolTable = ir.getSymbolTable(); + + createVariables(varFactory); + createEquations(opFactory); + } + + private void createEquations(OperatorFactory opFactory) { + SSAInstruction[] instructions = ir.getInstructions(); + for (int i = 0; i < instructions.length; i++) { + SSAInstruction s = instructions[i]; + makeEquationForInstruction(opFactory, s); + } + for (Iterator it = ir.iteratePhis(); it.hasNext();) { + SSAInstruction s = (SSAInstruction) it.next(); + makeEquationForInstruction(opFactory, s); + } + for (Iterator it = ir.iteratePis(); it.hasNext();) { + SSAInstruction s = (SSAInstruction) it.next(); + makeEquationForInstruction(opFactory, s); + } + for (Iterator it = ir.iterateCatchInstructions(); it.hasNext();) { + SSAInstruction s = (SSAInstruction) it.next(); + makeEquationForInstruction(opFactory, s); + } + } + + /** + * Create a dataflow equation induced by a given instruction + */ + private void makeEquationForInstruction(OperatorFactory opFactory, SSAInstruction s) { + if (s != null && s.hasDef()) { + AbstractOperator op = opFactory.get(s); + if (op != null) { + T def = getVariable(s.getDef()); + if (op instanceof NullaryOperator) { + newStatement(def, (NullaryOperator) op, false, false); + } else { + int n = s.getNumberOfUses(); + T[] uses = makeStmtRHS(n); + for (int j = 0; j < n; j++) { + if (s.getUse(j) > -1) { + uses[j] = getVariable(s.getUse(j)); + assert uses[j] != null; + } + } + newStatement(def, op, uses, false, false); + } + } + } + } + + /** + * Create a dataflow variable for each value number + */ + private void createVariables(VariableFactory factory) { + vars = new IVariable[symbolTable.getMaxValueNumber() + 1]; + for (int i = 1; i < vars.length; i++) { + vars[i] = factory.makeVariable(i); + } + + } + + /** + * @return the dataflow variable representing the value number, or null if none found. + */ + @SuppressWarnings("unchecked") + protected T getVariable(int valueNumber) { + if (valueNumber < 0) { + throw new IllegalArgumentException("Illegal valueNumber " + valueNumber); + } + if (DEBUG) { + System.err.println(("getVariable for " + valueNumber + " returns " + vars[valueNumber])); + } + assert vars != null : "null vars array"; + return (T) vars[valueNumber]; + } + + /** + * Return a string representation of the system + * + * @return a string representation of the system + */ + @Override + public String toString() { + StringBuffer result = new StringBuffer("Type inference : \n"); + for (int i = 0; i < vars.length; i++) { + result.append("v").append(i).append(" ").append(vars[i]).append("\n"); + } + return result.toString(); + } +} diff --git a/com.ibm.wala.core/src/com/ibm/wala/demandpa/alg/AbstractDemandPointsTo.java b/com.ibm.wala.core/src/com/ibm/wala/demandpa/alg/AbstractDemandPointsTo.java index 0490407bc..a3ef60364 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/demandpa/alg/AbstractDemandPointsTo.java +++ b/com.ibm.wala.core/src/com/ibm/wala/demandpa/alg/AbstractDemandPointsTo.java @@ -1,117 +1,117 @@ - -/******************************************************************************* - * 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. - * - * This file is a derivative of code released by the University of - * California under the terms listed below. - * - * Refinement Analysis Tools is Copyright (c) 2007 The Regents of the - * University of California (Regents). Provided that this notice and - * the following two paragraphs are included in any distribution of - * Refinement Analysis Tools or its derivative work, Regents agrees - * not to assert any of Regents' copyright rights in Refinement - * Analysis Tools against recipient for recipient's reproduction, - * preparation of derivative works, public display, public - * performance, distribution or sublicensing of Refinement Analysis - * Tools and derivative works, in source code and object code form. - * This agreement not to assert does not confer, by implication, - * estoppel, or otherwise any license or rights in any intellectual - * property of Regents, including, but not limited to, any patents - * of Regents or Regents' employees. - * - * IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, - * INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, - * INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE - * AND ITS DOCUMENTATION, EVEN IF REGENTS HAS BEEN ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE AND FURTHER DISCLAIMS ANY STATUTORY - * WARRANTY OF NON-INFRINGEMENT. THE SOFTWARE AND ACCOMPANYING - * DOCUMENTATION, IF ANY, PROVIDED HEREUNDER IS PROVIDED "AS - * IS". REGENTS HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, - * UPDATES, ENHANCEMENTS, OR MODIFICATIONS. - */ - -package com.ibm.wala.demandpa.alg; - -import com.ibm.wala.demandpa.util.MemoryAccessMap; -import com.ibm.wala.ipa.callgraph.AnalysisOptions; -import com.ibm.wala.ipa.callgraph.CallGraph; -import com.ibm.wala.ipa.callgraph.propagation.HeapModel; -import com.ibm.wala.ipa.cha.IClassHierarchy; - -/** - * Abstract super class for demand points-to analysis. Implements basic methods - * for tracking how much traversal has been done. - * - * @author Manu Sridharan - * - */ -public abstract class AbstractDemandPointsTo implements IDemandPointerAnalysis { - - protected final CallGraph cg; - - protected final HeapModel heapModel; - - protected final MemoryAccessMap mam; - - protected final IClassHierarchy cha; - - protected final AnalysisOptions options; - - protected int numNodesTraversed; - - private int traversalBudget = Integer.MAX_VALUE; - - public int getTraversalBudget() { - return traversalBudget; - } - - protected void setTraversalBudget(int traversalBudget) { - this.traversalBudget = traversalBudget; - } - - public AbstractDemandPointsTo(CallGraph cg, HeapModel model, MemoryAccessMap mam, IClassHierarchy cha, - AnalysisOptions options) { - this.cg = cg; - this.heapModel = model; - this.mam = mam; - this.cha = cha; - this.options = options; - } - - public HeapModel getHeapModel() { - return heapModel; - } - - /** - * - */ - protected void incrementNumNodesTraversed() { - if (numNodesTraversed > traversalBudget) { - throw new BudgetExceededException(); - } - numNodesTraversed++; - } - - protected void setNumNodesTraversed(int traversed) { - numNodesTraversed = traversed; - } - - public int getNumNodesTraversed() { - return numNodesTraversed; - } - - public CallGraph getBaseCallGraph() { - return cg; - } - - public IClassHierarchy getClassHierarchy() { - return cha; - } -} + +/******************************************************************************* + * 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. + * + * This file is a derivative of code released by the University of + * California under the terms listed below. + * + * Refinement Analysis Tools is Copyright (c) 2007 The Regents of the + * University of California (Regents). Provided that this notice and + * the following two paragraphs are included in any distribution of + * Refinement Analysis Tools or its derivative work, Regents agrees + * not to assert any of Regents' copyright rights in Refinement + * Analysis Tools against recipient for recipient's reproduction, + * preparation of derivative works, public display, public + * performance, distribution or sublicensing of Refinement Analysis + * Tools and derivative works, in source code and object code form. + * This agreement not to assert does not confer, by implication, + * estoppel, or otherwise any license or rights in any intellectual + * property of Regents, including, but not limited to, any patents + * of Regents or Regents' employees. + * + * IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, + * INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, + * INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE + * AND ITS DOCUMENTATION, EVEN IF REGENTS HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE AND FURTHER DISCLAIMS ANY STATUTORY + * WARRANTY OF NON-INFRINGEMENT. THE SOFTWARE AND ACCOMPANYING + * DOCUMENTATION, IF ANY, PROVIDED HEREUNDER IS PROVIDED "AS + * IS". REGENTS HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, + * UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + */ + +package com.ibm.wala.demandpa.alg; + +import com.ibm.wala.demandpa.util.MemoryAccessMap; +import com.ibm.wala.ipa.callgraph.AnalysisOptions; +import com.ibm.wala.ipa.callgraph.CallGraph; +import com.ibm.wala.ipa.callgraph.propagation.HeapModel; +import com.ibm.wala.ipa.cha.IClassHierarchy; + +/** + * Abstract super class for demand points-to analysis. Implements basic methods + * for tracking how much traversal has been done. + * + * @author Manu Sridharan + * + */ +public abstract class AbstractDemandPointsTo implements IDemandPointerAnalysis { + + protected final CallGraph cg; + + protected final HeapModel heapModel; + + protected final MemoryAccessMap mam; + + protected final IClassHierarchy cha; + + protected final AnalysisOptions options; + + protected int numNodesTraversed; + + private int traversalBudget = Integer.MAX_VALUE; + + public int getTraversalBudget() { + return traversalBudget; + } + + protected void setTraversalBudget(int traversalBudget) { + this.traversalBudget = traversalBudget; + } + + public AbstractDemandPointsTo(CallGraph cg, HeapModel model, MemoryAccessMap mam, IClassHierarchy cha, + AnalysisOptions options) { + this.cg = cg; + this.heapModel = model; + this.mam = mam; + this.cha = cha; + this.options = options; + } + + public HeapModel getHeapModel() { + return heapModel; + } + + /** + * + */ + protected void incrementNumNodesTraversed() { + if (numNodesTraversed > traversalBudget) { + throw new BudgetExceededException(); + } + numNodesTraversed++; + } + + protected void setNumNodesTraversed(int traversed) { + numNodesTraversed = traversed; + } + + public int getNumNodesTraversed() { + return numNodesTraversed; + } + + public CallGraph getBaseCallGraph() { + return cg; + } + + public IClassHierarchy getClassHierarchy() { + return cha; + } +} diff --git a/com.ibm.wala.core/src/com/ibm/wala/demandpa/alg/BudgetExceededException.java b/com.ibm.wala.core/src/com/ibm/wala/demandpa/alg/BudgetExceededException.java index 5f832d415..d3a0ce21b 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/demandpa/alg/BudgetExceededException.java +++ b/com.ibm.wala.core/src/com/ibm/wala/demandpa/alg/BudgetExceededException.java @@ -1,51 +1,51 @@ -/******************************************************************************* - * 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. - * - * This file is a derivative of code released by the University of - * California under the terms listed below. - * - * Refinement Analysis Tools is Copyright (c) 2007 The Regents of the - * University of California (Regents). Provided that this notice and - * the following two paragraphs are included in any distribution of - * Refinement Analysis Tools or its derivative work, Regents agrees - * not to assert any of Regents' copyright rights in Refinement - * Analysis Tools against recipient for recipient's reproduction, - * preparation of derivative works, public display, public - * performance, distribution or sublicensing of Refinement Analysis - * Tools and derivative works, in source code and object code form. - * This agreement not to assert does not confer, by implication, - * estoppel, or otherwise any license or rights in any intellectual - * property of Regents, including, but not limited to, any patents - * of Regents or Regents' employees. - * - * IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, - * INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, - * INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE - * AND ITS DOCUMENTATION, EVEN IF REGENTS HAS BEEN ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE AND FURTHER DISCLAIMS ANY STATUTORY - * WARRANTY OF NON-INFRINGEMENT. THE SOFTWARE AND ACCOMPANYING - * DOCUMENTATION, IF ANY, PROVIDED HEREUNDER IS PROVIDED "AS - * IS". REGENTS HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, - * UPDATES, ENHANCEMENTS, OR MODIFICATIONS. - */ -package com.ibm.wala.demandpa.alg; - -/** - * Exception thrown when a demand-driven points-to query - * exceeds its allocated budget. - * - * @author Manu Sridharan - * - */ -public class BudgetExceededException extends RuntimeException { - - private static final long serialVersionUID = -797000809257983053L; - -} +/******************************************************************************* + * 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. + * + * This file is a derivative of code released by the University of + * California under the terms listed below. + * + * Refinement Analysis Tools is Copyright (c) 2007 The Regents of the + * University of California (Regents). Provided that this notice and + * the following two paragraphs are included in any distribution of + * Refinement Analysis Tools or its derivative work, Regents agrees + * not to assert any of Regents' copyright rights in Refinement + * Analysis Tools against recipient for recipient's reproduction, + * preparation of derivative works, public display, public + * performance, distribution or sublicensing of Refinement Analysis + * Tools and derivative works, in source code and object code form. + * This agreement not to assert does not confer, by implication, + * estoppel, or otherwise any license or rights in any intellectual + * property of Regents, including, but not limited to, any patents + * of Regents or Regents' employees. + * + * IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, + * INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, + * INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE + * AND ITS DOCUMENTATION, EVEN IF REGENTS HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE AND FURTHER DISCLAIMS ANY STATUTORY + * WARRANTY OF NON-INFRINGEMENT. THE SOFTWARE AND ACCOMPANYING + * DOCUMENTATION, IF ANY, PROVIDED HEREUNDER IS PROVIDED "AS + * IS". REGENTS HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, + * UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + */ +package com.ibm.wala.demandpa.alg; + +/** + * Exception thrown when a demand-driven points-to query + * exceeds its allocated budget. + * + * @author Manu Sridharan + * + */ +public class BudgetExceededException extends RuntimeException { + + private static final long serialVersionUID = -797000809257983053L; + +} diff --git a/com.ibm.wala.core/src/com/ibm/wala/demandpa/alg/CallStack.java b/com.ibm.wala.core/src/com/ibm/wala/demandpa/alg/CallStack.java index 08884c5e1..a19b96be9 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/demandpa/alg/CallStack.java +++ b/com.ibm.wala.core/src/com/ibm/wala/demandpa/alg/CallStack.java @@ -1,81 +1,81 @@ -/******************************************************************************* - * 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. - * - * This file is a derivative of code released by the University of - * California under the terms listed below. - * - * Refinement Analysis Tools is Copyright (c) 2007 The Regents of the - * University of California (Regents). Provided that this notice and - * the following two paragraphs are included in any distribution of - * Refinement Analysis Tools or its derivative work, Regents agrees - * not to assert any of Regents' copyright rights in Refinement - * Analysis Tools against recipient for recipient's reproduction, - * preparation of derivative works, public display, public - * performance, distribution or sublicensing of Refinement Analysis - * Tools and derivative works, in source code and object code form. - * This agreement not to assert does not confer, by implication, - * estoppel, or otherwise any license or rights in any intellectual - * property of Regents, including, but not limited to, any patents - * of Regents or Regents' employees. - * - * IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, - * INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, - * INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE - * AND ITS DOCUMENTATION, EVEN IF REGENTS HAS BEEN ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE AND FURTHER DISCLAIMS ANY STATUTORY - * WARRANTY OF NON-INFRINGEMENT. THE SOFTWARE AND ACCOMPANYING - * DOCUMENTATION, IF ANY, PROVIDED HEREUNDER IS PROVIDED "AS - * IS". REGENTS HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, - * UPDATES, ENHANCEMENTS, OR MODIFICATIONS. - */ -package com.ibm.wala.demandpa.alg; - -import com.ibm.wala.demandpa.alg.statemachine.StateMachine.State; -import com.ibm.wala.ipa.callgraph.propagation.cfa.CallerSiteContext; -import com.ibm.wala.util.collections.ImmutableStack; - -/** - * Representation for a calling context. - */ -public class CallStack extends ImmutableStack implements State { - - public static CallStack emptyCallStack() { - CallStack ret = new CallStack(new CallerSiteContext[0]); - return ret; - } - - protected CallStack(CallerSiteContext[] entries) { - super(entries); - } - - @Override - protected CallStack makeStack(CallerSiteContext[] tmpEntries) { - return new CallStack(tmpEntries); - } - - @Override - protected CallerSiteContext[] makeInternalArray(int size) { - return new CallerSiteContext[size]; - } - - @Override - public CallStack pop() { - final CallStack ret = (CallStack) super.pop(); - return ret; - } - - @Override - public CallStack push(CallerSiteContext entry) { - final CallStack ret = (CallStack) super.push(entry); - return ret; - } - - -} +/******************************************************************************* + * 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. + * + * This file is a derivative of code released by the University of + * California under the terms listed below. + * + * Refinement Analysis Tools is Copyright (c) 2007 The Regents of the + * University of California (Regents). Provided that this notice and + * the following two paragraphs are included in any distribution of + * Refinement Analysis Tools or its derivative work, Regents agrees + * not to assert any of Regents' copyright rights in Refinement + * Analysis Tools against recipient for recipient's reproduction, + * preparation of derivative works, public display, public + * performance, distribution or sublicensing of Refinement Analysis + * Tools and derivative works, in source code and object code form. + * This agreement not to assert does not confer, by implication, + * estoppel, or otherwise any license or rights in any intellectual + * property of Regents, including, but not limited to, any patents + * of Regents or Regents' employees. + * + * IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, + * INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, + * INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE + * AND ITS DOCUMENTATION, EVEN IF REGENTS HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE AND FURTHER DISCLAIMS ANY STATUTORY + * WARRANTY OF NON-INFRINGEMENT. THE SOFTWARE AND ACCOMPANYING + * DOCUMENTATION, IF ANY, PROVIDED HEREUNDER IS PROVIDED "AS + * IS". REGENTS HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, + * UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + */ +package com.ibm.wala.demandpa.alg; + +import com.ibm.wala.demandpa.alg.statemachine.StateMachine.State; +import com.ibm.wala.ipa.callgraph.propagation.cfa.CallerSiteContext; +import com.ibm.wala.util.collections.ImmutableStack; + +/** + * Representation for a calling context. + */ +public class CallStack extends ImmutableStack implements State { + + public static CallStack emptyCallStack() { + CallStack ret = new CallStack(new CallerSiteContext[0]); + return ret; + } + + protected CallStack(CallerSiteContext[] entries) { + super(entries); + } + + @Override + protected CallStack makeStack(CallerSiteContext[] tmpEntries) { + return new CallStack(tmpEntries); + } + + @Override + protected CallerSiteContext[] makeInternalArray(int size) { + return new CallerSiteContext[size]; + } + + @Override + public CallStack pop() { + final CallStack ret = (CallStack) super.pop(); + return ret; + } + + @Override + public CallStack push(CallerSiteContext entry) { + final CallStack ret = (CallStack) super.push(entry); + return ret; + } + + +} diff --git a/com.ibm.wala.core/src/com/ibm/wala/demandpa/alg/ContextSensitiveStateMachine.java b/com.ibm.wala.core/src/com/ibm/wala/demandpa/alg/ContextSensitiveStateMachine.java index da4847ada..200a93353 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/demandpa/alg/ContextSensitiveStateMachine.java +++ b/com.ibm.wala.core/src/com/ibm/wala/demandpa/alg/ContextSensitiveStateMachine.java @@ -1,293 +1,293 @@ -/******************************************************************************* - * 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. - * - * This file is a derivative of code released by the University of - * California under the terms listed below. - * - * Refinement Analysis Tools is Copyright (c) 2007 The Regents of the - * University of California (Regents). Provided that this notice and - * the following two paragraphs are included in any distribution of - * Refinement Analysis Tools or its derivative work, Regents agrees - * not to assert any of Regents' copyright rights in Refinement - * Analysis Tools against recipient for recipient's reproduction, - * preparation of derivative works, public display, public - * performance, distribution or sublicensing of Refinement Analysis - * Tools and derivative works, in source code and object code form. - * This agreement not to assert does not confer, by implication, - * estoppel, or otherwise any license or rights in any intellectual - * property of Regents, including, but not limited to, any patents - * of Regents or Regents' employees. - * - * IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, - * INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, - * INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE - * AND ITS DOCUMENTATION, EVEN IF REGENTS HAS BEEN ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE AND FURTHER DISCLAIMS ANY STATUTORY - * WARRANTY OF NON-INFRINGEMENT. THE SOFTWARE AND ACCOMPANYING - * DOCUMENTATION, IF ANY, PROVIDED HEREUNDER IS PROVIDED "AS - * IS". REGENTS HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, - * UPDATES, ENHANCEMENTS, OR MODIFICATIONS. - */ -package com.ibm.wala.demandpa.alg; - -import java.util.Collection; -import java.util.HashSet; - -import com.ibm.wala.demandpa.alg.statemachine.StateMachine; -import com.ibm.wala.demandpa.alg.statemachine.StateMachineFactory; -import com.ibm.wala.demandpa.alg.statemachine.StatesMergedException; -import com.ibm.wala.demandpa.flowgraph.AssignBarLabel; -import com.ibm.wala.demandpa.flowgraph.AssignGlobalBarLabel; -import com.ibm.wala.demandpa.flowgraph.AssignGlobalLabel; -import com.ibm.wala.demandpa.flowgraph.AssignLabel; -import com.ibm.wala.demandpa.flowgraph.GetFieldBarLabel; -import com.ibm.wala.demandpa.flowgraph.GetFieldLabel; -import com.ibm.wala.demandpa.flowgraph.IFlowLabel; -import com.ibm.wala.demandpa.flowgraph.IFlowLabel.IFlowLabelVisitor; -import com.ibm.wala.demandpa.flowgraph.MatchBarLabel; -import com.ibm.wala.demandpa.flowgraph.MatchLabel; -import com.ibm.wala.demandpa.flowgraph.NewBarLabel; -import com.ibm.wala.demandpa.flowgraph.NewLabel; -import com.ibm.wala.demandpa.flowgraph.ParamBarLabel; -import com.ibm.wala.demandpa.flowgraph.ParamLabel; -import com.ibm.wala.demandpa.flowgraph.PutFieldBarLabel; -import com.ibm.wala.demandpa.flowgraph.PutFieldLabel; -import com.ibm.wala.demandpa.flowgraph.ReturnBarLabel; -import com.ibm.wala.demandpa.flowgraph.ReturnLabel; -import com.ibm.wala.ipa.callgraph.propagation.cfa.CallerSiteContext; -import com.ibm.wala.util.collections.HashSetFactory; - -/** - * A state machine for tracking calling context during a points-to query. - * Filters unrealizable paths. - * - */ -public class ContextSensitiveStateMachine implements StateMachine { - - private static final boolean DEBUG = false; - - private static final boolean DEBUG_RECURSION = false; - - /** - * The empty call stack. Note that the empty stack essentially represents all - * possible states. - */ - private final CallStack emptyStack = CallStack.emptyCallStack(); - - public CallStack getStartState() { - return emptyStack; - } - - private final RecursionHandler recursionHandler; - - private class CSLabelVisitor implements IFlowLabelVisitor { - - final CallStack prevStack; - - State nextState = null; - - CSLabelVisitor(CallStack prevStack) { - this.prevStack = prevStack; - } - - public void visitAssign(AssignLabel label, Object dst) { - nextState = prevStack; - } - - public void visitAssignBar(AssignBarLabel label, Object dst) { - nextState = prevStack; - } - - public void visitAssignGlobal(AssignGlobalLabel label, Object dst) { - nextState = emptyStack; - } - - public void visitAssignGlobalBar(AssignGlobalBarLabel label, Object dst) { - nextState = emptyStack; - } - - public void visitGetField(GetFieldLabel label, Object dst) { - nextState = prevStack; - } - - public void visitGetFieldBar(GetFieldBarLabel label, Object dst) { - nextState = prevStack; - } - - public void visitMatch(MatchLabel label, Object dst) { - nextState = emptyStack; - } - - public void visitMatchBar(MatchBarLabel label, Object dst) { - nextState = emptyStack; - } - - public void visitNew(NewLabel label, Object dst) { - nextState = prevStack; - } - - public void visitNewBar(NewBarLabel label, Object dst) { - nextState = prevStack; - } - - public void visitParam(ParamLabel label, Object dst) { - handleMethodExit(label.getCallSite()); - } - - private void handleMethodExit(CallerSiteContext callSite) { - if (recursionHandler.isRecursive(callSite)) { - nextState = prevStack; - } else if (prevStack.isEmpty()) { - nextState = prevStack; - } else if (prevStack.peek().equals(callSite)) { - nextState = prevStack.pop(); - } else { - nextState = ERROR; - } - } - - public void visitParamBar(ParamBarLabel label, Object dst) { - // method entry - handleMethodEntry(label.getCallSite()); - } - - private void handleMethodEntry(CallerSiteContext callSite) { - if (recursionHandler.isRecursive(callSite)) { - // just ignore it; we don't track recursive calls - nextState = prevStack; - } else if (prevStack.contains(callSite)) { - if (DEBUG_RECURSION) { - System.err.println("FOUND RECURSION"); - System.err.println("stack " + prevStack + " contains " + callSite); - } - CallerSiteContext topCallSite = null; - CallStack tmpStack = prevStack; - // mark the appropriate call sites as recursive - // and pop them - Collection newRecursiveSites = HashSetFactory.make(); - do { - topCallSite = tmpStack.peek(); - newRecursiveSites.add(topCallSite); - tmpStack = tmpStack.pop(); - } while (!topCallSite.equals(callSite) && !tmpStack.isEmpty()); - recursionHandler.makeRecursive(newRecursiveSites); - // here we throw the states merged exception to indicate - // that recursion was detected - // ideally, we would update all relevant data structures and continue, - // but it greatly complicates the analysis implementation - throw new StatesMergedException(); - } else { - nextState = prevStack.push(callSite); - } - } - - public void visitPutField(PutFieldLabel label, Object dst) { - nextState = prevStack; - } - - public void visitPutFieldBar(PutFieldBarLabel label, Object dst) { - nextState = prevStack; - } - - public void visitReturn(ReturnLabel label, Object dst) { - handleMethodEntry(label.getCallSite()); - } - - public void visitReturnBar(ReturnBarLabel label, Object dst) { - handleMethodExit(label.getCallSite()); - } - - } - - /* - * @see com.ibm.wala.demandpa.alg.statemachine.StateMachine#transition(com.ibm.wala.demandpa.alg.statemachine.StateMachine.State, java.lang.Object) - */ - public State transition(State prevState, IFlowLabel label) throws IllegalArgumentException, IllegalArgumentException { - if (prevState == null) { - throw new IllegalArgumentException("prevState == null"); - } - if (!(prevState instanceof CallStack)) { - throw new IllegalArgumentException("not ( prevState instanceof com.ibm.wala.demandpa.alg.CallStack ) "); - } - CallStack prevStack = (CallStack) prevState; - if (!prevStack.isEmpty() && recursionHandler.isRecursive(prevStack.peek())) { - // I don't think this is possible anymore - assert false; - // just pop off the call site - return transition(prevStack.pop(), label); - } - CSLabelVisitor v = new CSLabelVisitor(prevStack); - label.visit(v, null); - if (DEBUG) { - if (prevStack != v.nextState && v.nextState != ERROR) { - System.err.println("prev stack " + prevStack); - System.err.println("label " + label); - System.err.println("recursive call sites " + recursionHandler); - System.err.println("next stack " + v.nextState); - } - } - return v.nextState; - } - - private ContextSensitiveStateMachine(RecursionHandler recursionHandler) { - this.recursionHandler = recursionHandler; - } - - public static class Factory implements StateMachineFactory { - - private final RecursionHandler prototype; - - public Factory(RecursionHandler prototype) { - this.prototype = prototype; - } - - public Factory() { - this(new BasicRecursionHandler()); - } - - public StateMachine make() { - return new ContextSensitiveStateMachine(prototype.makeNew()); - } - - } - - public static interface RecursionHandler { - - public boolean isRecursive(CallerSiteContext callSite); - - public void makeRecursive(Collection callSites); - - /** - * in lieu of creating factories - */ - public RecursionHandler makeNew(); - } - - /** - * handles method recursion by only collapsing cycles of recursive - * calls observed during analysis - */ - public static class BasicRecursionHandler implements RecursionHandler { - - private final HashSet recursiveCallSites = HashSetFactory.make(); - - public boolean isRecursive(CallerSiteContext callSite) { - return recursiveCallSites.contains(callSite); - } - - public void makeRecursive(Collection callSites) { - recursiveCallSites.addAll(callSites); - } - - public RecursionHandler makeNew() { - return new BasicRecursionHandler(); - } - } -} +/******************************************************************************* + * 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. + * + * This file is a derivative of code released by the University of + * California under the terms listed below. + * + * Refinement Analysis Tools is Copyright (c) 2007 The Regents of the + * University of California (Regents). Provided that this notice and + * the following two paragraphs are included in any distribution of + * Refinement Analysis Tools or its derivative work, Regents agrees + * not to assert any of Regents' copyright rights in Refinement + * Analysis Tools against recipient for recipient's reproduction, + * preparation of derivative works, public display, public + * performance, distribution or sublicensing of Refinement Analysis + * Tools and derivative works, in source code and object code form. + * This agreement not to assert does not confer, by implication, + * estoppel, or otherwise any license or rights in any intellectual + * property of Regents, including, but not limited to, any patents + * of Regents or Regents' employees. + * + * IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, + * INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, + * INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE + * AND ITS DOCUMENTATION, EVEN IF REGENTS HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE AND FURTHER DISCLAIMS ANY STATUTORY + * WARRANTY OF NON-INFRINGEMENT. THE SOFTWARE AND ACCOMPANYING + * DOCUMENTATION, IF ANY, PROVIDED HEREUNDER IS PROVIDED "AS + * IS". REGENTS HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, + * UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + */ +package com.ibm.wala.demandpa.alg; + +import java.util.Collection; +import java.util.HashSet; + +import com.ibm.wala.demandpa.alg.statemachine.StateMachine; +import com.ibm.wala.demandpa.alg.statemachine.StateMachineFactory; +import com.ibm.wala.demandpa.alg.statemachine.StatesMergedException; +import com.ibm.wala.demandpa.flowgraph.AssignBarLabel; +import com.ibm.wala.demandpa.flowgraph.AssignGlobalBarLabel; +import com.ibm.wala.demandpa.flowgraph.AssignGlobalLabel; +import com.ibm.wala.demandpa.flowgraph.AssignLabel; +import com.ibm.wala.demandpa.flowgraph.GetFieldBarLabel; +import com.ibm.wala.demandpa.flowgraph.GetFieldLabel; +import com.ibm.wala.demandpa.flowgraph.IFlowLabel; +import com.ibm.wala.demandpa.flowgraph.IFlowLabel.IFlowLabelVisitor; +import com.ibm.wala.demandpa.flowgraph.MatchBarLabel; +import com.ibm.wala.demandpa.flowgraph.MatchLabel; +import com.ibm.wala.demandpa.flowgraph.NewBarLabel; +import com.ibm.wala.demandpa.flowgraph.NewLabel; +import com.ibm.wala.demandpa.flowgraph.ParamBarLabel; +import com.ibm.wala.demandpa.flowgraph.ParamLabel; +import com.ibm.wala.demandpa.flowgraph.PutFieldBarLabel; +import com.ibm.wala.demandpa.flowgraph.PutFieldLabel; +import com.ibm.wala.demandpa.flowgraph.ReturnBarLabel; +import com.ibm.wala.demandpa.flowgraph.ReturnLabel; +import com.ibm.wala.ipa.callgraph.propagation.cfa.CallerSiteContext; +import com.ibm.wala.util.collections.HashSetFactory; + +/** + * A state machine for tracking calling context during a points-to query. + * Filters unrealizable paths. + * + */ +public class ContextSensitiveStateMachine implements StateMachine { + + private static final boolean DEBUG = false; + + private static final boolean DEBUG_RECURSION = false; + + /** + * The empty call stack. Note that the empty stack essentially represents all + * possible states. + */ + private final CallStack emptyStack = CallStack.emptyCallStack(); + + public CallStack getStartState() { + return emptyStack; + } + + private final RecursionHandler recursionHandler; + + private class CSLabelVisitor implements IFlowLabelVisitor { + + final CallStack prevStack; + + State nextState = null; + + CSLabelVisitor(CallStack prevStack) { + this.prevStack = prevStack; + } + + public void visitAssign(AssignLabel label, Object dst) { + nextState = prevStack; + } + + public void visitAssignBar(AssignBarLabel label, Object dst) { + nextState = prevStack; + } + + public void visitAssignGlobal(AssignGlobalLabel label, Object dst) { + nextState = emptyStack; + } + + public void visitAssignGlobalBar(AssignGlobalBarLabel label, Object dst) { + nextState = emptyStack; + } + + public void visitGetField(GetFieldLabel label, Object dst) { + nextState = prevStack; + } + + public void visitGetFieldBar(GetFieldBarLabel label, Object dst) { + nextState = prevStack; + } + + public void visitMatch(MatchLabel label, Object dst) { + nextState = emptyStack; + } + + public void visitMatchBar(MatchBarLabel label, Object dst) { + nextState = emptyStack; + } + + public void visitNew(NewLabel label, Object dst) { + nextState = prevStack; + } + + public void visitNewBar(NewBarLabel label, Object dst) { + nextState = prevStack; + } + + public void visitParam(ParamLabel label, Object dst) { + handleMethodExit(label.getCallSite()); + } + + private void handleMethodExit(CallerSiteContext callSite) { + if (recursionHandler.isRecursive(callSite)) { + nextState = prevStack; + } else if (prevStack.isEmpty()) { + nextState = prevStack; + } else if (prevStack.peek().equals(callSite)) { + nextState = prevStack.pop(); + } else { + nextState = ERROR; + } + } + + public void visitParamBar(ParamBarLabel label, Object dst) { + // method entry + handleMethodEntry(label.getCallSite()); + } + + private void handleMethodEntry(CallerSiteContext callSite) { + if (recursionHandler.isRecursive(callSite)) { + // just ignore it; we don't track recursive calls + nextState = prevStack; + } else if (prevStack.contains(callSite)) { + if (DEBUG_RECURSION) { + System.err.println("FOUND RECURSION"); + System.err.println("stack " + prevStack + " contains " + callSite); + } + CallerSiteContext topCallSite = null; + CallStack tmpStack = prevStack; + // mark the appropriate call sites as recursive + // and pop them + Collection newRecursiveSites = HashSetFactory.make(); + do { + topCallSite = tmpStack.peek(); + newRecursiveSites.add(topCallSite); + tmpStack = tmpStack.pop(); + } while (!topCallSite.equals(callSite) && !tmpStack.isEmpty()); + recursionHandler.makeRecursive(newRecursiveSites); + // here we throw the states merged exception to indicate + // that recursion was detected + // ideally, we would update all relevant data structures and continue, + // but it greatly complicates the analysis implementation + throw new StatesMergedException(); + } else { + nextState = prevStack.push(callSite); + } + } + + public void visitPutField(PutFieldLabel label, Object dst) { + nextState = prevStack; + } + + public void visitPutFieldBar(PutFieldBarLabel label, Object dst) { + nextState = prevStack; + } + + public void visitReturn(ReturnLabel label, Object dst) { + handleMethodEntry(label.getCallSite()); + } + + public void visitReturnBar(ReturnBarLabel label, Object dst) { + handleMethodExit(label.getCallSite()); + } + + } + + /* + * @see com.ibm.wala.demandpa.alg.statemachine.StateMachine#transition(com.ibm.wala.demandpa.alg.statemachine.StateMachine.State, java.lang.Object) + */ + public State transition(State prevState, IFlowLabel label) throws IllegalArgumentException, IllegalArgumentException { + if (prevState == null) { + throw new IllegalArgumentException("prevState == null"); + } + if (!(prevState instanceof CallStack)) { + throw new IllegalArgumentException("not ( prevState instanceof com.ibm.wala.demandpa.alg.CallStack ) "); + } + CallStack prevStack = (CallStack) prevState; + if (!prevStack.isEmpty() && recursionHandler.isRecursive(prevStack.peek())) { + // I don't think this is possible anymore + assert false; + // just pop off the call site + return transition(prevStack.pop(), label); + } + CSLabelVisitor v = new CSLabelVisitor(prevStack); + label.visit(v, null); + if (DEBUG) { + if (prevStack != v.nextState && v.nextState != ERROR) { + System.err.println("prev stack " + prevStack); + System.err.println("label " + label); + System.err.println("recursive call sites " + recursionHandler); + System.err.println("next stack " + v.nextState); + } + } + return v.nextState; + } + + private ContextSensitiveStateMachine(RecursionHandler recursionHandler) { + this.recursionHandler = recursionHandler; + } + + public static class Factory implements StateMachineFactory { + + private final RecursionHandler prototype; + + public Factory(RecursionHandler prototype) { + this.prototype = prototype; + } + + public Factory() { + this(new BasicRecursionHandler()); + } + + public StateMachine make() { + return new ContextSensitiveStateMachine(prototype.makeNew()); + } + + } + + public static interface RecursionHandler { + + public boolean isRecursive(CallerSiteContext callSite); + + public void makeRecursive(Collection callSites); + + /** + * in lieu of creating factories + */ + public RecursionHandler makeNew(); + } + + /** + * handles method recursion by only collapsing cycles of recursive + * calls observed during analysis + */ + public static class BasicRecursionHandler implements RecursionHandler { + + private final HashSet recursiveCallSites = HashSetFactory.make(); + + public boolean isRecursive(CallerSiteContext callSite) { + return recursiveCallSites.contains(callSite); + } + + public void makeRecursive(Collection callSites) { + recursiveCallSites.addAll(callSites); + } + + public RecursionHandler makeNew() { + return new BasicRecursionHandler(); + } + } +} diff --git a/com.ibm.wala.core/src/com/ibm/wala/demandpa/alg/DemandRefinementPointsTo.java b/com.ibm.wala.core/src/com/ibm/wala/demandpa/alg/DemandRefinementPointsTo.java index 31eafe470..f794680a8 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/demandpa/alg/DemandRefinementPointsTo.java +++ b/com.ibm.wala.core/src/com/ibm/wala/demandpa/alg/DemandRefinementPointsTo.java @@ -1,2531 +1,2531 @@ -/******************************************************************************* - * 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. - * - * This file is a derivative of code released by the University of - * California under the terms listed below. - * - * Refinement Analysis Tools is Copyright (c) 2007 The Regents of the - * University of California (Regents). Provided that this notice and - * the following two paragraphs are included in any distribution of - * Refinement Analysis Tools or its derivative work, Regents agrees - * not to assert any of Regents' copyright rights in Refinement - * Analysis Tools against recipient for recipient's reproduction, - * preparation of derivative works, public display, public - * performance, distribution or sublicensing of Refinement Analysis - * Tools and derivative works, in source code and object code form. - * This agreement not to assert does not confer, by implication, - * estoppel, or otherwise any license or rights in any intellectual - * property of Regents, including, but not limited to, any patents - * of Regents or Regents' employees. - * - * IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, - * INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, - * INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE - * AND ITS DOCUMENTATION, EVEN IF REGENTS HAS BEEN ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE AND FURTHER DISCLAIMS ANY STATUTORY - * WARRANTY OF NON-INFRINGEMENT. THE SOFTWARE AND ACCOMPANYING - * DOCUMENTATION, IF ANY, PROVIDED HEREUNDER IS PROVIDED "AS - * IS". REGENTS HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, - * UPDATES, ENHANCEMENTS, OR MODIFICATIONS. - */ -package com.ibm.wala.demandpa.alg; - -import java.util.Collection; -import java.util.Collections; -import java.util.HashSet; -import java.util.Iterator; -import java.util.LinkedHashSet; -import java.util.LinkedList; -import java.util.Map; -import java.util.Set; - -import com.ibm.wala.analysis.reflection.InstanceKeyWithNode; -import com.ibm.wala.classLoader.CallSiteReference; -import com.ibm.wala.classLoader.IClass; -import com.ibm.wala.classLoader.IField; -import com.ibm.wala.classLoader.IMethod; -import com.ibm.wala.classLoader.ShrikeBTMethod; -import com.ibm.wala.demandpa.alg.refinepolicy.NeverRefineCGPolicy; -import com.ibm.wala.demandpa.alg.refinepolicy.NeverRefineFieldsPolicy; -import com.ibm.wala.demandpa.alg.refinepolicy.RefinementPolicy; -import com.ibm.wala.demandpa.alg.refinepolicy.RefinementPolicyFactory; -import com.ibm.wala.demandpa.alg.refinepolicy.SinglePassRefinementPolicy; -import com.ibm.wala.demandpa.alg.statemachine.StateMachine; -import com.ibm.wala.demandpa.alg.statemachine.StateMachine.State; -import com.ibm.wala.demandpa.alg.statemachine.StateMachineFactory; -import com.ibm.wala.demandpa.alg.statemachine.StatesMergedException; -import com.ibm.wala.demandpa.flowgraph.AbstractFlowGraph; -import com.ibm.wala.demandpa.flowgraph.AbstractFlowLabelVisitor; -import com.ibm.wala.demandpa.flowgraph.AssignBarLabel; -import com.ibm.wala.demandpa.flowgraph.AssignGlobalBarLabel; -import com.ibm.wala.demandpa.flowgraph.AssignGlobalLabel; -import com.ibm.wala.demandpa.flowgraph.AssignLabel; -import com.ibm.wala.demandpa.flowgraph.DemandPointerFlowGraph; -import com.ibm.wala.demandpa.flowgraph.GetFieldLabel; -import com.ibm.wala.demandpa.flowgraph.IFlowGraph; -import com.ibm.wala.demandpa.flowgraph.IFlowLabel; -import com.ibm.wala.demandpa.flowgraph.IFlowLabel.IFlowLabelVisitor; -import com.ibm.wala.demandpa.flowgraph.IFlowLabelWithFilter; -import com.ibm.wala.demandpa.flowgraph.MatchBarLabel; -import com.ibm.wala.demandpa.flowgraph.MatchLabel; -import com.ibm.wala.demandpa.flowgraph.NewLabel; -import com.ibm.wala.demandpa.flowgraph.ParamBarLabel; -import com.ibm.wala.demandpa.flowgraph.ParamLabel; -import com.ibm.wala.demandpa.flowgraph.PutFieldLabel; -import com.ibm.wala.demandpa.flowgraph.ReturnBarLabel; -import com.ibm.wala.demandpa.flowgraph.ReturnLabel; -import com.ibm.wala.demandpa.util.ArrayContents; -import com.ibm.wala.demandpa.util.MemoryAccess; -import com.ibm.wala.demandpa.util.MemoryAccessMap; -import com.ibm.wala.demandpa.util.PointerParamValueNumIterator; -import com.ibm.wala.ipa.callgraph.AnalysisOptions; -import com.ibm.wala.ipa.callgraph.CGNode; -import com.ibm.wala.ipa.callgraph.CallGraph; -import com.ibm.wala.ipa.callgraph.propagation.AbstractLocalPointerKey; -import com.ibm.wala.ipa.callgraph.propagation.FilteredPointerKey; -import com.ibm.wala.ipa.callgraph.propagation.FilteredPointerKey.MultipleClassesFilter; -import com.ibm.wala.ipa.callgraph.propagation.FilteredPointerKey.SingleClassFilter; -import com.ibm.wala.ipa.callgraph.propagation.FilteredPointerKey.SingleInstanceFilter; -import com.ibm.wala.ipa.callgraph.propagation.FilteredPointerKey.TypeFilter; -import com.ibm.wala.ipa.callgraph.propagation.HeapModel; -import com.ibm.wala.ipa.callgraph.propagation.InstanceFieldKey; -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.callgraph.propagation.ReturnValueKey; -import com.ibm.wala.ipa.callgraph.propagation.StaticFieldKey; -import com.ibm.wala.ipa.callgraph.propagation.cfa.CallerSiteContext; -import com.ibm.wala.ipa.callgraph.propagation.cfa.ExceptionReturnValueKey; -import com.ibm.wala.ipa.cha.IClassHierarchy; -import com.ibm.wala.shrikeBT.IInstruction; -import com.ibm.wala.shrikeCT.InvalidClassFileException; -import com.ibm.wala.ssa.IR; -import com.ibm.wala.ssa.SSAAbstractInvokeInstruction; -import com.ibm.wala.ssa.SSAArrayStoreInstruction; -import com.ibm.wala.ssa.SSAInstruction; -import com.ibm.wala.ssa.SSAInvokeInstruction; -import com.ibm.wala.ssa.SSANewInstruction; -import com.ibm.wala.ssa.SSAPutInstruction; -import com.ibm.wala.util.Predicate; -import com.ibm.wala.util.collections.ArraySet; -import com.ibm.wala.util.collections.ArraySetMultiMap; -import com.ibm.wala.util.collections.HashMapFactory; -import com.ibm.wala.util.collections.HashSetFactory; -import com.ibm.wala.util.collections.HashSetMultiMap; -import com.ibm.wala.util.collections.Iterator2Collection; -import com.ibm.wala.util.collections.Iterator2Iterable; -import com.ibm.wala.util.collections.MapIterator; -import com.ibm.wala.util.collections.MultiMap; -import com.ibm.wala.util.collections.Pair; -import com.ibm.wala.util.collections.Util; -import com.ibm.wala.util.debug.Assertions; -import com.ibm.wala.util.debug.UnimplementedError; -import com.ibm.wala.util.functions.Function; -import com.ibm.wala.util.intset.IntSet; -import com.ibm.wala.util.intset.IntSetAction; -import com.ibm.wala.util.intset.MutableIntSet; -import com.ibm.wala.util.intset.MutableIntSetFactory; -import com.ibm.wala.util.intset.MutableMapping; -import com.ibm.wala.util.intset.MutableSparseIntSetFactory; -import com.ibm.wala.util.intset.OrdinalSet; -import com.ibm.wala.util.intset.OrdinalSetMapping; - -/** - * Demand-driven refinement-based points-to analysis. - */ -public class DemandRefinementPointsTo extends AbstractDemandPointsTo { - - private static final boolean DEBUG = false; - - private static final boolean DEBUG_TOPLEVEL = false; - - private static final boolean PARANOID = false; - - private static final boolean MEASURE_MEMORY_USAGE = false; - - protected final IFlowGraph g; - - private StateMachineFactory stateMachineFactory; - - /** - * the state machine for additional filtering of paths - */ - private StateMachine stateMachine; - - protected RefinementPolicy refinementPolicy; - - private RefinementPolicyFactory refinementPolicyFactory; - - public RefinementPolicy getRefinementPolicy() { - return refinementPolicy; - } - - private DemandRefinementPointsTo(CallGraph cg, ThisFilteringHeapModel model, MemoryAccessMap fam, IClassHierarchy cha, - AnalysisOptions options, StateMachineFactory stateMachineFactory, IFlowGraph flowGraph) { - super(cg, model, fam, cha, options); - this.stateMachineFactory = stateMachineFactory; - g = flowGraph; - this.refinementPolicyFactory = new SinglePassRefinementPolicy.Factory(new NeverRefineFieldsPolicy(), new NeverRefineCGPolicy()); - sanityCheckCG(); - } - - private void sanityCheckCG() { - if (PARANOID) { - for (CGNode callee : cg) { - for (Iterator predNodes = cg.getPredNodes(callee); predNodes.hasNext();) { - CGNode caller = predNodes.next(); - for (Iterator iterator = cg.getPossibleSites(caller, callee); iterator.hasNext();) { - CallSiteReference site = iterator.next(); - try { - caller.getIR().getCalls(site); - } catch (IllegalArgumentException e) { - System.err.println(caller + " is pred of " + callee); - System.err.println("no calls at site " + site); - System.err.println(caller.getIR()); - if (caller.getMethod() instanceof ShrikeBTMethod) { - try { - IInstruction[] instructions = ((ShrikeBTMethod) caller.getMethod()).getInstructions(); - for (int i = 0; i < instructions.length; i++) { - System.err.println(i + ": " + instructions[i]); - } - } catch (InvalidClassFileException e1) { - // TODO Auto-generated catch block - e1.printStackTrace(); - } - } - Assertions.UNREACHABLE(); - } - } - } - } - } - } - - /** - * Possible results of a query. - * - * @see DemandRefinementPointsTo#getPointsTo(PointerKey, Predicate) - * @author manu - * - */ - public static enum PointsToResult { - /** - * The points-to set result satisfies the supplied {@link Predicate} - */ - SUCCESS, - /** - * The {@link RefinementPolicy} indicated that no more refinement was possible, and on at least one refinement pass the - * budget was not exhausted - */ - NOMOREREFINE, - /** - * The budget specified in the {@link RefinementPolicy} was exceeded on all refinement passes - */ - BUDGETEXCEEDED - }; - - /** - * re-initialize state for a new query - */ - protected void startNewQuery() { - // re-init the refinement policy - refinementPolicy = refinementPolicyFactory.make(); - // re-init the state machine - stateMachine = stateMachineFactory.make(); - } - - /** - * compute a points-to set for a pointer key, aiming to satisfy some predicate - * - * @param pk the pointer key - * @param ikeyPred the desired predicate that each instance key in the points-to set should ideally satisfy - * @return a pair consisting of (1) a {@link PointsToResult} indicating whether a points-to set satisfying the predicate was - * computed, and (2) the last computed points-to set for the variable (possibly null if no points-to set - * could be computed in the budget) - * @throws IllegalArgumentException if pk is not a {@link LocalPointerKey}; to eventually be fixed - */ - public Pair> getPointsTo(PointerKey pk, Predicate ikeyPred) - throws IllegalArgumentException { - Pair> p = getPointsToWithStates(pk, ikeyPred); - final Collection p2SetWithStates = p.snd; - Collection finalP2Set = removeStates(p2SetWithStates); - return Pair.make(p.fst, finalP2Set); - } - - /** - * @param pk - * @param ikeyPred - * @return - */ - private Pair> getPointsToWithStates(PointerKey pk, Predicate ikeyPred) { - if (!(pk instanceof com.ibm.wala.ipa.callgraph.propagation.LocalPointerKey)) { - throw new IllegalArgumentException("only locals for now"); - } - LocalPointerKey queriedPk = (LocalPointerKey) pk; - if (DEBUG) { - System.err.println("answering query for " + pk); - } - startNewQuery(); - Pair> p = outerRefinementLoop(new PointerKeyAndState(queriedPk, stateMachine - .getStartState()), ikeyPred); - return p; - } - - /** - * Unwrap a Collection of WithState objects, returning a Collection containing the wrapped objects - */ - private static Collection removeStates(final Collection> p2SetWithStates) { - Collection finalP2Set = Iterator2Collection.toSet(new MapIterator, T>(p2SetWithStates.iterator(), - new Function, T>() { - - public T apply(WithState object) { - return object.getWrapped(); - } - })); - return finalP2Set; - } - - /** - * create a demand points-to analysis runner - * - * @param cg the underlying call graph for the analysis - * @param model the heap model to be used for the analysis - * @param mam indicates what code reads or writes each field - * @param cha - * @param options - * @param stateMachineFactory factory for state machines to track additional properties like calling context - */ - public static DemandRefinementPointsTo makeWithDefaultFlowGraph(CallGraph cg, HeapModel model, MemoryAccessMap mam, - IClassHierarchy cha, AnalysisOptions options, StateMachineFactory stateMachineFactory) { - final ThisFilteringHeapModel thisFilteringHeapModel = new ThisFilteringHeapModel(model, cha); - return new DemandRefinementPointsTo(cg, thisFilteringHeapModel, mam, cha, options, stateMachineFactory, - new DemandPointerFlowGraph(cg, thisFilteringHeapModel, mam, cha)); - } - - private Pair> outerRefinementLoop(PointerKeyAndState queried, - Predicate ikeyPred) { - Collection lastP2Set = null; - boolean succeeded = false; - int numPasses = refinementPolicy.getNumPasses(); - int passNum = 0; - for (; passNum < numPasses; passNum++) { - setNumNodesTraversed(0); - setTraversalBudget(refinementPolicy.getBudgetForPass(passNum)); - Collection curP2Set = null; - PointsToComputer computer = null; - boolean completedPassInBudget = false; - try { - while (true) { - try { - computer = new PointsToComputer(queried); - computer.compute(); - curP2Set = computer.getComputedP2Set(queried); - // System.err.println("completed pass"); - if (DEBUG) { - System.err.println("traversed " + getNumNodesTraversed() + " nodes"); - System.err.println("POINTS-TO SET " + curP2Set); - } - completedPassInBudget = true; - break; - } catch (StatesMergedException e) { - if (DEBUG) { - System.err.println("restarting..."); - } - } - } - } catch (BudgetExceededException e) { - - } - if (curP2Set != null) { - if (lastP2Set == null) { - lastP2Set = curP2Set; - } else if (lastP2Set.size() > curP2Set.size()) { - // got a more precise set - assert removeStates(lastP2Set).containsAll(removeStates(curP2Set)); - lastP2Set = curP2Set; - } else { - // new set size is >= lastP2Set, so don't update - assert removeStates(curP2Set).containsAll(removeStates(lastP2Set)); - } - if (curP2Set.isEmpty() || passesPred(curP2Set, ikeyPred)) { - // we did it! - // if (curP2Set.isEmpty()) { - // System.err.println("EMPTY PTO SET"); - // } - succeeded = true; - break; - } else if (completedPassInBudget) { - } - } - // if we get here, means either budget for pass was exceeded, - // or points-to set wasn't good enough - // so, start new pass, if more refinement to do - if (!refinementPolicy.nextPass()) { - break; - } - } - PointsToResult result = null; - if (succeeded) { - result = PointsToResult.SUCCESS; - } else if (passNum == numPasses) { - // we ran all the passes without succeeding and - // without the refinement policy giving up - result = PointsToResult.BUDGETEXCEEDED; - } else { - if (lastP2Set != null) { - result = PointsToResult.NOMOREREFINE; - } else { - // we stopped before the maximum number of passes, but we never - // actually finished a pass, so we count this as BUDGETEXCEEDED - result = PointsToResult.BUDGETEXCEEDED; - } - } - return Pair.make(result, lastP2Set); - } - - /** - * to measure memory usage - */ - public long lastQueryMemoryUse; - - /** - * check if the points-to set of a variable passes some predicate, without necessarily computing the whole points-to set - * - * @param pk the pointer key - * @param ikeyPred the desired predicate that each instance key in the points-to set should ideally satisfy - * @param pa a pre-computed points-to analysis - * @return a {@link PointsToResult} indicating whether a points-to set satisfying the predicate was computed - * @throws IllegalArgumentException if pk is not a {@link LocalPointerKey}; to eventually be fixed - */ - public PointsToResult pointsToPassesPred(PointerKey pk, Predicate ikeyPred, PointerAnalysis pa) - throws IllegalArgumentException { - if (!(pk instanceof com.ibm.wala.ipa.callgraph.propagation.LocalPointerKey)) { - throw new IllegalArgumentException("only locals for now"); - } - LocalPointerKey queriedPk = (LocalPointerKey) pk; - if (DEBUG) { - System.err.println("answering query for " + pk); - } - boolean succeeded = false; - startNewQuery(); - int numPasses = refinementPolicy.getNumPasses(); - int passNum = 0; - boolean completedSomePass = false; - if (MEASURE_MEMORY_USAGE) { - lastQueryMemoryUse = -1; - } - for (; passNum < numPasses; passNum++) { - setNumNodesTraversed(0); - setTraversalBudget(refinementPolicy.getBudgetForPass(passNum)); - boolean completedPassInBudget = false; - boolean passed = false; - long initialMemory = 0; - try { - while (true) { - try { - if (MEASURE_MEMORY_USAGE) { - initialMemory = Util.getUsedMemory(); - } - PointsToComputer computer = new PointsToComputer(queriedPk); - passed = doTopLevelTraversal(queriedPk, ikeyPred, computer, pa); - // System.err.println("completed pass"); - if (DEBUG) { - System.err.println("traversed " + getNumNodesTraversed() + " nodes"); - } - completedPassInBudget = true; - completedSomePass = true; - break; - } catch (StatesMergedException e) { - if (DEBUG) { - System.err.println("restarting..."); - } - } finally { - if (MEASURE_MEMORY_USAGE) { - long memoryAfterPass = Util.getUsedMemory(); - assert initialMemory != 0; - long usedByPass = memoryAfterPass - initialMemory; - if (usedByPass > lastQueryMemoryUse) { - lastQueryMemoryUse = usedByPass; - if (usedByPass > 20000000) { - System.err.println("DOH!"); - System.exit(1); - } - } - } - - } - } - } catch (BudgetExceededException e) { - - } - if (completedPassInBudget) { - if (passed) { - succeeded = true; - break; - } - } - // if we get here, means either budget for pass was exceeded, - // or points-to set wasn't good enough - // so, start new pass, if more refinement to do - if (!refinementPolicy.nextPass()) { - break; - } - } - PointsToResult result = null; - if (succeeded) { - result = PointsToResult.SUCCESS; - } else if (passNum == numPasses) { - // we ran all the passes without succeeding and - // without the refinement policy giving up - result = PointsToResult.BUDGETEXCEEDED; - } else { - result = completedSomePass ? PointsToResult.NOMOREREFINE : PointsToResult.BUDGETEXCEEDED; - } - if (MEASURE_MEMORY_USAGE) { - System.err.println("memory " + lastQueryMemoryUse); - } - return result; - } - - /** - * do all instance keys in p2set pass ikeyPred? - */ - private boolean passesPred(Collection curP2Set, final Predicate ikeyPred) { - return Util.forAll(curP2Set, new Predicate() { - - @Override - public boolean test(InstanceKeyAndState t) { - return ikeyPred.test(t.getInstanceKey()); - } - }); - } - - /** - * @return the points-to set of pk, or null if the points-to set can't be computed in the allocated - * budget - */ - public Collection getPointsTo(PointerKey pk) { - return getPointsTo(pk, Predicate. falsePred()).snd; - } - - /** - * @return the points-to set of pk, including the {@link State}s attached to the {@link InstanceKey}s, or - * null if the points-to set can't be computed in the allocated budget - */ - public Collection getPointsToWithStates(PointerKey pk) { - return getPointsToWithStates(pk, Predicate. falsePred()).snd; - } - - /** - * get all the pointer keys that some instance key can flow to - * - * @return a pair consisting of (1) a {@link PointsToResult} indicating whether a flows-to set was computed, and (2) the last - * computed flows-to set for the instance key (possibly null if no flows-to set could be computed in the - * budget) - */ - public Pair> getFlowsTo(InstanceKey ik) { - startNewQuery(); - return getFlowsToInternal(new InstanceKeyAndState(ik, stateMachine.getStartState())); - } - - /** - * get all the pointer keys that some instance key with state can flow to - * - * @return a pair consisting of (1) a {@link PointsToResult} indicating whether a flows-to set was computed, and (2) the last - * computed flows-to set for the instance key (possibly null if no flows-to set could be computed in the - * budget) - */ - public Pair> getFlowsTo(InstanceKeyAndState ikAndState) { - startNewQuery(); - return getFlowsToInternal(ikAndState); - } - - /** - * @param ik - * @return - */ - private Pair> getFlowsToInternal(InstanceKeyAndState ikAndState) { - InstanceKey ik = ikAndState.getInstanceKey(); - if (!(ik instanceof InstanceKeyWithNode)) { - assert false : "TODO: handle " + ik.getClass(); - } - if (DEBUG) { - System.err.println("answering flows-to query for " + ikAndState); - } - Collection lastFlowsToSet = null; - boolean succeeded = false; - int numPasses = refinementPolicy.getNumPasses(); - int passNum = 0; - for (; passNum < numPasses; passNum++) { - setNumNodesTraversed(0); - setTraversalBudget(refinementPolicy.getBudgetForPass(passNum)); - Collection curFlowsToSet = null; - FlowsToComputer computer = null; - try { - while (true) { - try { - computer = new FlowsToComputer(ikAndState); - computer.compute(); - curFlowsToSet = computer.getComputedFlowsToSet(); - // System.err.println("completed pass"); - if (DEBUG) { - System.err.println("traversed " + getNumNodesTraversed() + " nodes"); - System.err.println("FLOWS-TO SET " + curFlowsToSet); - } - break; - } catch (StatesMergedException e) { - if (DEBUG) { - System.err.println("restarting..."); - } - } - } - } catch (BudgetExceededException e) { - - } - if (curFlowsToSet != null) { - if (lastFlowsToSet == null) { - lastFlowsToSet = curFlowsToSet; - } else if (lastFlowsToSet.size() > curFlowsToSet.size()) { - // got a more precise set - assert removeStates(lastFlowsToSet).containsAll(removeStates(curFlowsToSet)); - lastFlowsToSet = curFlowsToSet; - } else { - // new set size is >= lastP2Set, so don't update - // TODO what is wrong with this assertion?!? --MS - // assert removeStates(curFlowsToSet).containsAll(removeStates(lastFlowsToSet)); - } - // TODO add predicate support - if (curFlowsToSet.isEmpty() /* || passesPred(curFlowsToSet, ikeyPred) */) { - succeeded = true; - break; - } - } - // if we get here, means either budget for pass was exceeded, - // or points-to set wasn't good enough - // so, start new pass, if more refinement to do - if (!refinementPolicy.nextPass()) { - break; - } - } - PointsToResult result = null; - if (succeeded) { - result = PointsToResult.SUCCESS; - } else if (passNum == numPasses) { - // we ran all the passes without succeeding and - // without the refinement policy giving up - result = PointsToResult.BUDGETEXCEEDED; - } else { - if (lastFlowsToSet != null) { - result = PointsToResult.NOMOREREFINE; - } else { - // we stopped before the maximum number of passes, but we never - // actually finished a pass, so we count this as BUDGETEXCEEDED - result = PointsToResult.BUDGETEXCEEDED; - } - } - return Pair.make(result, lastFlowsToSet == null ? null : removeStates(lastFlowsToSet)); - } - - /** - * Closure indicating how to handle copies between {@link PointerKey}s. - * - * @author Manu Sridharan - * - */ - private static abstract class CopyHandler { - - abstract void handle(PointerKeyAndState src, PointerKey dst, IFlowLabel label); - } - - /** - * Representation of a statement storing a value into a field. - * - * @author Manu Sridharan - * - */ - private static final class StoreEdge { - // - // Represents statement of the form base.field = val - - final PointerKeyAndState base; - - final IField field; - - final PointerKeyAndState val; - - @Override - public int hashCode() { - final int PRIME = 31; - int result = 1; - result = PRIME * result + val.hashCode(); - result = PRIME * result + field.hashCode(); - result = PRIME * result + base.hashCode(); - return result; - } - - @Override - public boolean equals(Object obj) { - if (this == obj) - return true; - if (obj == null) - return false; - if (getClass() != obj.getClass()) - return false; - final StoreEdge other = (StoreEdge) obj; - if (!val.equals(other.val)) - return false; - if (!field.equals(other.field)) - return false; - if (!base.equals(other.base)) - return false; - return true; - } - - public StoreEdge(final PointerKeyAndState base, final IField field, final PointerKeyAndState val) { - this.base = base; - this.field = field; - this.val = val; - } - - } - - /** - * Representation of a field read. - * - * @author Manu Sridharan - * - */ - private static final class LoadEdge { - // Represents statements of the form val = base.field - final PointerKeyAndState base; - - final IField field; - - final PointerKeyAndState val; - - @Override - public String toString() { - return val + " := " + base + ", field " + field; - } - - @Override - public int hashCode() { - final int PRIME = 31; - int result = 1; - result = PRIME * result + val.hashCode(); - result = PRIME * result + field.hashCode(); - result = PRIME * result + base.hashCode(); - return result; - } - - @Override - public boolean equals(Object obj) { - if (this == obj) - return true; - if (obj == null) - return false; - if (getClass() != obj.getClass()) - return false; - final LoadEdge other = (LoadEdge) obj; - if (!val.equals(other.val)) - return false; - if (!field.equals(other.field)) - return false; - if (!base.equals(other.base)) - return false; - return true; - } - - public LoadEdge(final PointerKeyAndState base, final IField field, final PointerKeyAndState val) { - this.base = base; - this.field = field; - this.val = val; - } - - } - - /** - * Points-to analysis algorithm code. - * - * Pseudocode in Chapter 5 of Manu Sridharan's dissertation. - * - * @author Manu Sridharan - * - */ - protected class PointsToComputer { - - protected final PointerKeyAndState queriedPkAndState; - - /** - * map from pointer key to states in which the key's points-to set was queried - */ - private final MultiMap pointsToQueried = HashSetMultiMap.make(); - - /** - * map from pointer key to states in which a tracked points-to set for the key was computed - */ - private final MultiMap trackedQueried = HashSetMultiMap.make(); - - /** - * forward worklist: for initially processing points-to queries - */ - private final Collection initWorklist = new LinkedHashSet(); - - /** - * worklist for variables whose points-to set has been updated - */ - private final Collection pointsToWorklist = new LinkedHashSet(); - - /** - * worklist for variables whose tracked points-to set has been updated - */ - private final Collection trackedPointsToWorklist = new LinkedHashSet(); - - /** - * maps a pointer key to those on-the-fly virtual calls for which it is the receiver - */ - private final MultiMap pkToOTFCalls = HashSetMultiMap.make(); - - /** - * cache of the targets discovered for a call site during on-the-fly call graph construction - */ - private final MultiMap callToOTFTargets = ArraySetMultiMap.make(); - - // alloc nodes to the fields we're looking to match on them, - // matching getfield with putfield - private final MultiMap forwInstKeyToFields = HashSetMultiMap.make(); - - // matching putfield_bar with getfield_bar - private final MultiMap backInstKeyToFields = HashSetMultiMap.make(); - - // points-to sets and tracked points-to sets - protected final Map pkToP2Set = HashMapFactory.make(); - - protected final Map pkToTrackedSet = HashMapFactory.make(); - - private final Map instFieldKeyToP2Set = HashMapFactory.make(); - - private final Map instFieldKeyToTrackedSet = HashMapFactory.make(); - - /** - * for numbering {@link InstanceKey}, {@link State} pairs - */ - protected final OrdinalSetMapping ikAndStates = MutableMapping.make(); - - private final MutableIntSetFactory intSetFactory = new MutableSparseIntSetFactory(); // new - - // BitVectorIntSetFactory(); - - /** - * tracks all field stores encountered during traversal - */ - private final HashSet encounteredStores = HashSetFactory.make(); - - /** - * tracks all field loads encountered during traversal - */ - private final HashSet encounteredLoads = HashSetFactory.make(); - - /** - * use this with care! only for subclasses that aren't computing points-to information exactly (e.g., {@link FlowsToComputer}) - */ - protected PointsToComputer() { - queriedPkAndState = null; - } - - protected PointsToComputer(PointerKey pk) { - queriedPkAndState = new PointerKeyAndState(pk, stateMachine.getStartState()); - } - - protected PointsToComputer(PointerKeyAndState pkAndState) { - this.queriedPkAndState = pkAndState; - } - - private OrdinalSet makeOrdinalSet(IntSet intSet) { - // make a copy here, to avoid comodification during iteration - // TODO remove the copying, do it only at necessary call sites - return new OrdinalSet(intSetFactory.makeCopy(intSet), ikAndStates); - } - - /** - * get a points-to set that has already been computed via some previous call to {@link #compute()}; does _not_ do any fresh - * demand-driven computation. - */ - public Collection getComputedP2Set(PointerKeyAndState queried) { - return Iterator2Collection.toSet(makeOrdinalSet(find(pkToP2Set, queried)).iterator()); - // return Iterator2Collection.toSet(new MapIterator(makeOrdinalSet( - // find(pkToP2Set, new PointerKeyAndState(lpk, stateMachine.getStartState()))).iterator(), - // new Function() { - // - // public InstanceKey apply(InstanceKeyAndState object) { - // return object.getInstanceKey(); - // } - // - // })); - } - - protected boolean addAllToP2Set(Map p2setMap, PointerKeyAndState pkAndState, IntSet vals, - IFlowLabel label) { - final PointerKey pk = pkAndState.getPointerKey(); - if (pk instanceof FilteredPointerKey) { - if (DEBUG) { - System.err.println("handling filtered pointer key " + pk); - } - final TypeFilter typeFilter = ((FilteredPointerKey) pk).getTypeFilter(); - vals = updateValsForFilter(vals, typeFilter); - } - if (label instanceof IFlowLabelWithFilter) { - TypeFilter typeFilter = ((IFlowLabelWithFilter) label).getFilter(); - if (typeFilter != null) { - vals = updateValsForFilter(vals, typeFilter); - } - } - boolean added = findOrCreate(p2setMap, pkAndState).addAll(vals); - // final boolean added = p2setMap.putAll(pkAndState, vals); - if (DEBUG && added) { - System.err.println("POINTS-TO ADDITION TO PK " + pkAndState + ":"); - for (InstanceKeyAndState ikAndState : makeOrdinalSet(vals)) { - System.err.println(ikAndState); - } - System.err.println("*************"); - } - return added; - - } - - private IntSet updateValsForFilter(IntSet vals, final TypeFilter typeFilter) { - if (typeFilter instanceof SingleClassFilter) { - final IClass concreteType = ((SingleClassFilter) typeFilter).getConcreteType(); - final MutableIntSet tmp = intSetFactory.make(); - vals.foreach(new IntSetAction() { - - public void act(int x) { - InstanceKeyAndState ikAndState = ikAndStates.getMappedObject(x); - if (cha.isAssignableFrom(concreteType, ikAndState.getInstanceKey().getConcreteType())) { - tmp.add(x); - } - } - - }); - vals = tmp; - } else if (typeFilter instanceof MultipleClassesFilter) { - final MutableIntSet tmp = intSetFactory.make(); - vals.foreach(new IntSetAction() { - - public void act(int x) { - InstanceKeyAndState ikAndState = ikAndStates.getMappedObject(x); - for (IClass t : ((MultipleClassesFilter) typeFilter).getConcreteTypes()) { - if (cha.isAssignableFrom(t, ikAndState.getInstanceKey().getConcreteType())) { - tmp.add(x); - } - } - } - - }); - vals = tmp; - } else if (typeFilter instanceof SingleInstanceFilter) { - final InstanceKey theOnlyInstanceKey = ((SingleInstanceFilter) typeFilter).getInstance(); - final MutableIntSet tmp = intSetFactory.make(); - vals.foreach(new IntSetAction() { - - public void act(int x) { - InstanceKeyAndState ikAndState = ikAndStates.getMappedObject(x); - if (ikAndState.getInstanceKey().equals(theOnlyInstanceKey)) { - tmp.add(x); - } - } - - }); - vals = tmp; - } else { - Assertions.UNREACHABLE(); - } - return vals; - } - - protected void compute() { - final CGNode node = ((LocalPointerKey) queriedPkAndState.getPointerKey()).getNode(); - if (hasNullIR(node)) { - return; - } - g.addSubgraphForNode(node); - addToInitWorklist(queriedPkAndState); - worklistLoop(); - } - - protected void worklistLoop() { - do { - while (!initWorklist.isEmpty() || !pointsToWorklist.isEmpty() || !trackedPointsToWorklist.isEmpty()) { - handleInitWorklist(); - handlePointsToWorklist(); - handleTrackedPointsToWorklist(); - } - makePassOverFieldStmts(); - } while (!initWorklist.isEmpty() || !pointsToWorklist.isEmpty() || !trackedPointsToWorklist.isEmpty()); - } - - void handleCopy(final PointerKeyAndState curPkAndState, final PointerKey succPk, final IFlowLabel label) { - assert !label.isBarred(); - State curState = curPkAndState.getState(); - doTransition(curState, label, new Function() { - - public Object apply(State nextState) { - PointerKeyAndState succPkAndState = new PointerKeyAndState(succPk, nextState); - handleCopy(curPkAndState, succPkAndState, label); - return null; - } - - }); - } - - void handleCopy(PointerKeyAndState curPkAndState, PointerKeyAndState succPkAndState, IFlowLabel label) { - if (!addToInitWorklist(succPkAndState)) { - // handle like x = y with Y updated - if (addAllToP2Set(pkToP2Set, curPkAndState, find(pkToP2Set, succPkAndState), label)) { - addToPToWorklist(curPkAndState); - } - } - - } - - void handleAllCopies(PointerKeyAndState curPk, Iterator succNodes, IFlowLabel label) { - while (succNodes.hasNext()) { - handleCopy(curPk, (PointerKey) succNodes.next(), label); - } - } - - /** - * @param label the label of the edge from curPk to predPk (must be barred) - * @return those {@link PointerKeyAndState}s whose points-to sets have been queried, such that the {@link PointerKey} is predPk, - * and transitioning from its state on label.bar() yields the state of curPkAndState - */ - protected Collection matchingPToQueried(PointerKeyAndState curPkAndState, PointerKey predPk, - IFlowLabel label) { - Collection ret = ArraySet.make(); - assert label.isBarred(); - IFlowLabel unbarredLabel = label.bar(); - final State curState = curPkAndState.getState(); - Set predPkStates = pointsToQueried.get(predPk); - for (State predState : predPkStates) { - State transState = stateMachine.transition(predState, unbarredLabel); - if (transState.equals(curState)) { - // we have a winner! - ret.add(new PointerKeyAndState(predPk, predState)); - } - } - return ret; - } - - Collection matchingTrackedQueried(PointerKeyAndState curPkAndState, PointerKey succPk, IFlowLabel label) { - Collection ret = ArraySet.make(); - assert label.isBarred(); - final State curState = curPkAndState.getState(); - Set succPkStates = trackedQueried.get(succPk); - for (State succState : succPkStates) { - State transState = stateMachine.transition(succState, label); - if (transState.equals(curState)) { - ret.add(new PointerKeyAndState(succPk, succState)); - } - } - return ret; - } - - protected void handleBackCopy(PointerKeyAndState curPkAndState, PointerKey predPk, IFlowLabel label) { - for (PointerKeyAndState predPkAndState : matchingPToQueried(curPkAndState, predPk, label)) { - if (addAllToP2Set(pkToP2Set, predPkAndState, find(pkToP2Set, curPkAndState), label)) { - addToPToWorklist(predPkAndState); - } - } - } - - void handleAllBackCopies(PointerKeyAndState curPkAndState, Iterator predNodes, IFlowLabel label) { - while (predNodes.hasNext()) { - handleBackCopy(curPkAndState, (PointerKey) predNodes.next(), label); - } - } - - /** - * should only be called when pk's points-to set has just been updated. add pk to the points-to worklist, and re-propagate and - * calls that had pk as the receiver. - */ - void addToPToWorklist(PointerKeyAndState pkAndState) { - pointsToWorklist.add(pkAndState); - Set otfCalls = pkToOTFCalls.get(pkAndState); - for (CallerSiteContext callSiteAndCGNode : otfCalls) { - propTargets(pkAndState, callSiteAndCGNode); - } - } - - boolean addToInitWorklist(PointerKeyAndState pkAndState) { - if (pointsToQueried.put(pkAndState.getPointerKey(), pkAndState.getState())) { - if (pkAndState.getPointerKey() instanceof AbstractLocalPointerKey) { - CGNode node = ((AbstractLocalPointerKey) pkAndState.getPointerKey()).getNode(); - if (!g.hasSubgraphForNode(node)) { - assert false : "missing constraints for " + node; - } - } - if (DEBUG) { - // System.err.println("adding to init_ " + pkAndState); - } - initWorklist.add(pkAndState); - // if (pkAndStates.getMappedIndex(pkAndState) == -1) { - // pkAndStates.add(pkAndState); - // } - return true; - } - return false; - } - - protected void addToTrackedPToWorklist(PointerKeyAndState pkAndState) { - if (pkAndState.getPointerKey() instanceof AbstractLocalPointerKey) { - CGNode node = ((AbstractLocalPointerKey) pkAndState.getPointerKey()).getNode(); - if (!g.hasSubgraphForNode(node)) { - assert false : "missing constraints for " + node; - } - } - if (DEBUG) { - // System.err.println("adding to tracked points-to " + pkAndState); - } - trackedQueried.put(pkAndState.getPointerKey(), pkAndState.getState()); - trackedPointsToWorklist.add(pkAndState); - } - - /** - * Adds new targets for a virtual call, based on the points-to set of the receiver, and propagates values for the parameters / - * return value of the new targets. NOTE: this method will not do any propagation for virtual call targets that have - * already been discovered. - * - * @param receiverAndState the receiver - * @param callSiteAndCGNode the call - */ - void propTargets(PointerKeyAndState receiverAndState, CallerSiteContext callSiteAndCGNode) { - final CGNode caller = callSiteAndCGNode.getCaller(); - CallSiteReference call = callSiteAndCGNode.getCallSite(); - final State receiverState = receiverAndState.getState(); - OrdinalSet p2set = makeOrdinalSet(find(pkToP2Set, receiverAndState)); - for (InstanceKeyAndState ikAndState : p2set) { - InstanceKey ik = ikAndState.getInstanceKey(); - IMethod targetMethod = options.getMethodTargetSelector().getCalleeTarget(caller, call, ik.getConcreteType()); - if (targetMethod == null) { - // NOTE: target method can be null because we don't - // always have type filters - continue; - } - // if we've already handled this target, we can stop - if (callToOTFTargets.get(callSiteAndCGNode).contains(targetMethod)) { - continue; - } - callToOTFTargets.put(callSiteAndCGNode, targetMethod); - // TODO can we just pick one of these, rather than all of them? - // TODO handle clone() properly - Set targetCGNodes = cg.getNodes(targetMethod.getReference()); - for (final CGNode targetForCall : targetCGNodes) { - if (DEBUG) { - System.err.println("adding target " + targetForCall + " for call " + call); - } - if (hasNullIR(targetForCall)) { - continue; - } - g.addSubgraphForNode(targetForCall); - // need to check flows through parameters and returns, - // in direction of value flow and reverse - SSAAbstractInvokeInstruction[] calls = getCallInstrs(caller, call); - for (final SSAAbstractInvokeInstruction invokeInstr : calls) { - final ReturnLabel returnLabel = ReturnLabel.make(new CallerSiteContext(caller, call)); - if (invokeInstr.hasDef()) { - final PointerKeyAndState defAndState = new PointerKeyAndState(heapModel.getPointerKeyForLocal(caller, invokeInstr - .getDef()), receiverState); - final PointerKey ret = heapModel.getPointerKeyForReturnValue(targetForCall); - doTransition(receiverState, returnLabel, new Function() { - - public Object apply(State retState) { - repropCallArg(defAndState, new PointerKeyAndState(ret, retState), returnLabel.bar()); - return null; - } - - }); - } - final PointerKeyAndState exc = new PointerKeyAndState(heapModel.getPointerKeyForLocal(caller, invokeInstr - .getException()), receiverState); - final PointerKey excRet = heapModel.getPointerKeyForExceptionalReturnValue(targetForCall); - doTransition(receiverState, returnLabel, new Function() { - - public Object apply(State excRetState) { - repropCallArg(exc, new PointerKeyAndState(excRet, excRetState), returnLabel.bar()); - return null; - } - - }); - for (Iterator iter = new PointerParamValueNumIterator(targetForCall); iter.hasNext();) { - final int formalNum = iter.next(); - final int actualNum = formalNum - 1; - final ParamBarLabel paramBarLabel = ParamBarLabel.make(new CallerSiteContext(caller, call)); - doTransition(receiverState, paramBarLabel, new Function() { - - public Object apply(State formalState) { - repropCallArg( - new PointerKeyAndState(heapModel.getPointerKeyForLocal(targetForCall, formalNum), formalState), - new PointerKeyAndState(heapModel.getPointerKeyForLocal(caller, invokeInstr.getUse(actualNum)), receiverState), - paramBarLabel); - return null; - } - - }); - } - } - } - } - } - - /** - * handle possible updated flow in both directions for a call parameter - * - * @param src - * @param dst - */ - private void repropCallArg(PointerKeyAndState src, PointerKeyAndState dst, IFlowLabel dstToSrcLabel) { - if (DEBUG) { - // System.err.println("re-propping from src " + src + " to dst " + dst); - } - for (PointerKeyAndState srcToHandle : matchingPToQueried(dst, src.getPointerKey(), dstToSrcLabel)) { - handleCopy(srcToHandle, dst, dstToSrcLabel.bar()); - } - for (PointerKeyAndState dstToHandle : matchingTrackedQueried(src, dst.getPointerKey(), dstToSrcLabel)) { - IntSet trackedSet = find(pkToTrackedSet, dstToHandle); - if (!trackedSet.isEmpty()) { - if (findOrCreate(pkToTrackedSet, src).addAll(trackedSet)) { - addToTrackedPToWorklist(src); - } - } - } - } - - void handleInitWorklist() { - while (!initWorklist.isEmpty()) { - incrementNumNodesTraversed(); - final PointerKeyAndState curPkAndState = initWorklist.iterator().next(); - initWorklist.remove(curPkAndState); - final PointerKey curPk = curPkAndState.getPointerKey(); - final State curState = curPkAndState.getState(); - if (DEBUG) - System.err.println("init " + curPkAndState); - if (curPk instanceof LocalPointerKey) { - assert g.hasSubgraphForNode(((LocalPointerKey) curPk).getNode()); - } - // if (curPk instanceof LocalPointerKey) { - // Collection constantVals = - // getConstantVals((LocalPointerKey) curPk); - // if (constantVals != null) { - // for (InstanceKey ik : constantVals) { - // pkToP2Set.put(curPk, ik); - // addToPToWorklist(curPk); - // } - // } - // } - IFlowLabelVisitor v = new AbstractFlowLabelVisitor() { - - @Override - public void visitNew(NewLabel label, Object dst) { - final InstanceKey ik = (InstanceKey) dst; - if (DEBUG) { - System.err.println("alloc " + ik + " assigned to " + curPk); - } - doTransition(curState, label, new Function() { - - public Object apply(State newState) { - InstanceKeyAndState ikAndState = new InstanceKeyAndState(ik, newState); - int n = ikAndStates.add(ikAndState); - findOrCreate(pkToP2Set, curPkAndState).add(n); - addToPToWorklist(curPkAndState); - return null; - } - - }); - } - - @Override - public void visitGetField(GetFieldLabel label, Object dst) { - IField field = (label).getField(); - PointerKey loadBase = (PointerKey) dst; - if (refineFieldAccesses(field, loadBase, curPk, label, curState)) { - // if (Assertions.verifyAssertions) { - // Assertions._assert(stateMachine.transition(curState, label) == - // curState); - // } - PointerKeyAndState loadBaseAndState = new PointerKeyAndState(loadBase, curState); - addEncounteredLoad(new LoadEdge(loadBaseAndState, field, curPkAndState)); - if (!addToInitWorklist(loadBaseAndState)) { - // handle like x = y.f, with Y updated - for (InstanceKeyAndState ikAndState : makeOrdinalSet(find(pkToP2Set, loadBaseAndState))) { - trackInstanceField(ikAndState, field, forwInstKeyToFields); - } - } - } else { - handleAllCopies(curPkAndState, g.getWritesToInstanceField(loadBase, field), MatchLabel.v()); - } - } - - @Override - public void visitAssignGlobal(AssignGlobalLabel label, Object dst) { - handleAllCopies(curPkAndState, g.getWritesToStaticField((StaticFieldKey) dst), AssignGlobalLabel.v()); - } - - @Override - public void visitAssign(AssignLabel label, Object dst) { - handleCopy(curPkAndState, (PointerKey) dst, AssignLabel.noFilter()); - } - - }; - g.visitSuccs(curPk, v); - // interprocedural edges - handleForwInterproc(curPkAndState, new CopyHandler() { - - @Override - void handle(PointerKeyAndState src, PointerKey dst, IFlowLabel label) { - handleCopy(src, dst, label); - } - - }); - } - - } - - /** - * handle flow from actuals to formals, and from returned values to variables at the caller - * - * @param curPk - * @param handler - */ - private void handleForwInterproc(final PointerKeyAndState curPkAndState, final CopyHandler handler) { - PointerKey curPk = curPkAndState.getPointerKey(); - if (curPk instanceof LocalPointerKey) { - final LocalPointerKey localPk = (LocalPointerKey) curPk; - if (g.isParam(localPk)) { - // System.err.println("at param"); - final CGNode callee = localPk.getNode(); - final int paramPos = localPk.getValueNumber() - 1; - for (final CallerSiteContext callSiteAndCGNode : g.getPotentialCallers(localPk)) { - final CGNode caller = callSiteAndCGNode.getCaller(); - final CallSiteReference call = callSiteAndCGNode.getCallSite(); - // final IR ir = getIR(caller); - if (hasNullIR(caller)) - continue; - final ParamLabel paramLabel = ParamLabel.make(callSiteAndCGNode); - doTransition(curPkAndState.getState(), paramLabel, new Function() { - - private void propagateToCallee() { - // if (caller.getIR() == null) { - // return; - // } - g.addSubgraphForNode(caller); - SSAAbstractInvokeInstruction[] callInstrs = getCallInstrs(caller, call); - for (int i = 0; i < callInstrs.length; i++) { - SSAAbstractInvokeInstruction callInstr = callInstrs[i]; - PointerKey actualPk = heapModel.getPointerKeyForLocal(caller, callInstr.getUse(paramPos)); - assert g.containsNode(actualPk); - assert g.containsNode(localPk); - handler.handle(curPkAndState, actualPk, paramLabel); - } - } - - public Object apply(State callerState) { - // hack to get some actual parameter from call site - // TODO do this better - SSAAbstractInvokeInstruction[] callInstrs = getCallInstrs(caller, call); - SSAAbstractInvokeInstruction callInstr = callInstrs[0]; - PointerKey actualPk = heapModel.getPointerKeyForLocal(caller, callInstr.getUse(paramPos)); - Set possibleTargets = g.getPossibleTargets(caller, call, (LocalPointerKey) actualPk); - if (noOnTheFlyNeeded(callSiteAndCGNode, possibleTargets)) { - propagateToCallee(); - } else { - if (callToOTFTargets.get(callSiteAndCGNode).contains(callee.getMethod())) { - // already found this target as valid, so do propagation - propagateToCallee(); - } else { - // if necessary, start a query for the call site - queryCallTargets(callSiteAndCGNode, callInstrs, callerState); - } - } - return null; - } - - }); - - } - } - SSAInvokeInstruction callInstr = g.getInstrReturningTo(localPk); - if (callInstr != null) { - CGNode caller = localPk.getNode(); - boolean isExceptional = localPk.getValueNumber() == callInstr.getException(); - - CallSiteReference callSiteRef = callInstr.getCallSite(); - CallerSiteContext callSiteAndCGNode = new CallerSiteContext(caller, callSiteRef); - // get call targets - Set possibleCallees = g.getPossibleTargets(caller, callSiteRef, localPk); - - // cg.getPossibleTargets(caller, callSiteRef); - // if (DEBUG && - // callSiteRef.getDeclaredTarget().toString().indexOf("clone()") != - // -1) { - // System.err.println(possibleCallees); - // System.err.println(Iterator2Collection.toCollection(cg.getSuccNodes(caller))); - // System.err.println(Iterator2Collection.toCollection(cg.getPredNodes(possibleCallees.iterator().next()))); - // } - // construct graph for each target - if (noOnTheFlyNeeded(callSiteAndCGNode, possibleCallees)) { - for (CGNode callee : possibleCallees) { - if (hasNullIR(callee)) { - continue; - } - g.addSubgraphForNode(callee); - PointerKey retVal = isExceptional ? heapModel.getPointerKeyForExceptionalReturnValue(callee) : heapModel - .getPointerKeyForReturnValue(callee); - assert g.containsNode(retVal); - handler.handle(curPkAndState, retVal, ReturnLabel.make(callSiteAndCGNode)); - } - } else { - if (callToOTFTargets.containsKey(callSiteAndCGNode)) { - // already queried this call site - // handle existing targets - Set targetMethods = callToOTFTargets.get(callSiteAndCGNode); - for (CGNode callee : possibleCallees) { - if (targetMethods.contains(callee.getMethod())) { - if (hasNullIR(callee)) { - continue; - } - g.addSubgraphForNode(callee); - PointerKey retVal = isExceptional ? heapModel.getPointerKeyForExceptionalReturnValue(callee) : heapModel - .getPointerKeyForReturnValue(callee); - assert g.containsNode(retVal); - handler.handle(curPkAndState, retVal, ReturnLabel.make(callSiteAndCGNode)); - } - } - } else { - // if necessary, raise a query for the call site - queryCallTargets(callSiteAndCGNode, getCallInstrs(caller, callSiteAndCGNode.getCallSite()), curPkAndState.getState()); - } - } - } - } - } - - /** - * track a field of some instance key, as we are interested in statements that read or write to the field - * - * @param ikAndState - * @param field - * @param ikToFields either {@link #forwInstKeyToFields} or {@link #backInstKeyToFields} - */ - private void trackInstanceField(InstanceKeyAndState ikAndState, IField field, MultiMap ikToFields) { - ikToFields.put(ikAndState, field); - addPredsOfIKeyAndStateToTrackedPointsTo(ikAndState); - } - - private void addPredsOfIKeyAndStateToTrackedPointsTo(InstanceKeyAndState ikAndState) throws UnimplementedError { - for (Iterator iter = g.getPredNodes(ikAndState.getInstanceKey(), NewLabel.v()); iter.hasNext();) { - PointerKey ikPred = (PointerKey) iter.next(); - PointerKeyAndState ikPredAndState = new PointerKeyAndState(ikPred, ikAndState.getState()); - int mappedIndex = ikAndStates.getMappedIndex(ikAndState); - assert mappedIndex != -1; - if (findOrCreate(pkToTrackedSet, ikPredAndState).add(mappedIndex)) { - addToTrackedPToWorklist(ikPredAndState); - } - } - } - - /** - * Initiates a query for the targets of some virtual call, by asking for points-to set of receiver. NOTE: if receiver has - * already been queried, will not do any additional propagation for already-discovered virtual call targets - */ - private void queryCallTargets(CallerSiteContext callSiteAndCGNode, SSAAbstractInvokeInstruction[] callInstrs, State callerState) { - final CGNode caller = callSiteAndCGNode.getCaller(); - for (SSAAbstractInvokeInstruction callInstr : callInstrs) { - PointerKey thisArg = heapModel.getPointerKeyForLocal(caller, callInstr.getUse(0)); - PointerKeyAndState thisArgAndState = new PointerKeyAndState(thisArg, callerState); - if (pkToOTFCalls.put(thisArgAndState, callSiteAndCGNode)) { - // added the call target - final CGNode node = ((LocalPointerKey) thisArg).getNode(); - if (hasNullIR(node)) { - return; - } - g.addSubgraphForNode(node); - if (!addToInitWorklist(thisArgAndState)) { - // need to handle pk's current values for call - propTargets(thisArgAndState, callSiteAndCGNode); - } else { - if (DEBUG) { - final CallSiteReference call = callSiteAndCGNode.getCallSite(); - System.err.println("querying for targets of call " + call + " in " + caller); - } - } - } else { - // TODO: I think we can remove this call - propTargets(thisArgAndState, callSiteAndCGNode); - } - } - } - - void handlePointsToWorklist() { - while (!pointsToWorklist.isEmpty()) { - incrementNumNodesTraversed(); - final PointerKeyAndState curPkAndState = pointsToWorklist.iterator().next(); - pointsToWorklist.remove(curPkAndState); - final PointerKey curPk = curPkAndState.getPointerKey(); - final State curState = curPkAndState.getState(); - if (DEBUG) { - System.err.println("points-to " + curPkAndState); - System.err.println("***pto-set " + find(pkToP2Set, curPkAndState) + "***"); - } - IFlowLabelVisitor predVisitor = new AbstractFlowLabelVisitor() { - - @Override - public void visitPutField(PutFieldLabel label, Object dst) { - IField field = label.getField(); - PointerKey storeBase = (PointerKey) dst; - if (refineFieldAccesses(field, storeBase, curPk, label, curState)) { - // statements x.f = y, Y updated (X' not empty required) - // update Z.f for all z in X' - PointerKeyAndState storeBaseAndState = new PointerKeyAndState(storeBase, curState); - encounteredStores.add(new StoreEdge(storeBaseAndState, field, curPkAndState)); - for (InstanceKeyAndState ikAndState : makeOrdinalSet(find(pkToTrackedSet, storeBaseAndState))) { - if (forwInstKeyToFields.get(ikAndState).contains(field)) { - InstanceFieldKeyAndState ifKeyAndState = getInstFieldKey(ikAndState, field); - findOrCreate(instFieldKeyToP2Set, ifKeyAndState).addAll(find(pkToP2Set, curPkAndState)); - - } - } - } else { - handleAllBackCopies(curPkAndState, g.getReadsOfInstanceField(storeBase, field), MatchBarLabel.v()); - } - } - - @Override - public void visitGetField(GetFieldLabel label, Object dst) { - IField field = (label).getField(); - PointerKey dstPtrKey = (PointerKey) dst; - if (refineFieldAccesses(field, curPk, dstPtrKey, label, curState)) { - // statements x = y.f, Y updated - // if X queried, start tracking Y.f - PointerKeyAndState loadDefAndState = new PointerKeyAndState(dstPtrKey, curState); - addEncounteredLoad(new LoadEdge(curPkAndState, field, loadDefAndState)); - if (pointsToQueried.get(dstPtrKey).contains(curState)) { - for (InstanceKeyAndState ikAndState : makeOrdinalSet(find(pkToP2Set, curPkAndState))) { - trackInstanceField(ikAndState, field, forwInstKeyToFields); - } - } - } - } - - @Override - public void visitAssignGlobal(AssignGlobalLabel label, Object dst) { - handleAllBackCopies(curPkAndState, g.getReadsOfStaticField((StaticFieldKey) dst), label.bar()); - } - - @Override - public void visitAssign(AssignLabel label, Object dst) { - handleBackCopy(curPkAndState, (PointerKey) dst, label.bar()); - } - - }; - g.visitPreds(curPk, predVisitor); - IFlowLabelVisitor succVisitor = new AbstractFlowLabelVisitor() { - - @Override - public void visitPutField(PutFieldLabel label, Object dst) { - IField field = (label).getField(); - PointerKey dstPtrKey = (PointerKey) dst; - // pass barred label since this is for tracked points-to sets - if (refineFieldAccesses(field, curPk, dstPtrKey, label.bar(), curState)) { - // x.f = y, X updated - // if Y' non-empty, then update - // tracked set of X.f, to trace flow - // to reads - PointerKeyAndState storeDst = new PointerKeyAndState(dstPtrKey, curState); - encounteredStores.add(new StoreEdge(curPkAndState, field, storeDst)); - IntSet trackedSet = find(pkToTrackedSet, storeDst); - if (!trackedSet.isEmpty()) { - for (InstanceKeyAndState ikAndState : makeOrdinalSet(find(pkToP2Set, curPkAndState))) { - InstanceFieldKeyAndState ifk = getInstFieldKey(ikAndState, field); - findOrCreate(instFieldKeyToTrackedSet, ifk).addAll(trackedSet); - trackInstanceField(ikAndState, field, backInstKeyToFields); - } - } - } - } - }; - g.visitSuccs(curPk, succVisitor); - handleBackInterproc(curPkAndState, new CopyHandler() { - - @Override - void handle(PointerKeyAndState src, PointerKey dst, IFlowLabel label) { - handleBackCopy(src, dst, label); - } - - }, false); - } - } - - /** - * handle flow from return value to callers, or from actual to formals - * - * @param curPkAndState - * @param handler - */ - private void handleBackInterproc(final PointerKeyAndState curPkAndState, final CopyHandler handler, final boolean addGraphs) { - final PointerKey curPk = curPkAndState.getPointerKey(); - final State curState = curPkAndState.getState(); - // interprocedural edges - if (curPk instanceof ReturnValueKey) { - final ReturnValueKey returnKey = (ReturnValueKey) curPk; - if (DEBUG) { - System.err.println("return value"); - } - final CGNode callee = returnKey.getNode(); - if (DEBUG) { - System.err.println("returning from " + callee); - // System.err.println("CALL GRAPH:\n" + cg); - // System.err.println(new - // Iterator2Collection(cg.getPredNodes(cgNode))); - } - final boolean isExceptional = returnKey instanceof ExceptionReturnValueKey; - // iterate over callers - for (final CallerSiteContext callSiteAndCGNode : g.getPotentialCallers(returnKey)) { - final CGNode caller = callSiteAndCGNode.getCaller(); - if (hasNullIR(caller)) - continue; - final CallSiteReference call = callSiteAndCGNode.getCallSite(); - if (calleeSubGraphMissingAndShouldNotBeAdded(addGraphs, callee, curPkAndState)) { - continue; - } - final ReturnBarLabel returnBarLabel = ReturnBarLabel.make(callSiteAndCGNode); - doTransition(curState, returnBarLabel, new Function() { - - private void propagateToCaller() { - // if (caller.getIR() == null) { - // return; - // } - g.addSubgraphForNode(caller); - SSAAbstractInvokeInstruction[] callInstrs = getCallInstrs(caller, call); - for (int i = 0; i < callInstrs.length; i++) { - SSAAbstractInvokeInstruction callInstr = callInstrs[i]; - PointerKey returnAtCallerKey = heapModel.getPointerKeyForLocal(caller, isExceptional ? callInstr.getException() - : callInstr.getDef()); - assert g.containsNode(returnAtCallerKey); - assert g.containsNode(returnKey); - handler.handle(curPkAndState, returnAtCallerKey, returnBarLabel); - } - } - - public Object apply(State callerState) { - // if (DEBUG) { - // System.err.println("caller " + caller); - // } - SSAAbstractInvokeInstruction[] callInstrs = getCallInstrs(caller, call); - SSAAbstractInvokeInstruction callInstr = callInstrs[0]; - PointerKey returnAtCallerKey = heapModel.getPointerKeyForLocal(caller, isExceptional ? callInstr.getException() - : callInstr.getDef()); - Set possibleTargets = g.getPossibleTargets(caller, call, (LocalPointerKey) returnAtCallerKey); - if (noOnTheFlyNeeded(callSiteAndCGNode, possibleTargets)) { - propagateToCaller(); - } else { - if (callToOTFTargets.get(callSiteAndCGNode).contains(callee.getMethod())) { - // already found this target as valid, so do propagation - propagateToCaller(); - } else { - // if necessary, start a query for the call site - queryCallTargets(callSiteAndCGNode, callInstrs, callerState); - } - } - return null; - } - - }); - } - } - if (curPk instanceof LocalPointerKey) { - LocalPointerKey localPk = (LocalPointerKey) curPk; - CGNode caller = localPk.getNode(); - // from actual parameter to callee - for (Iterator iter = g.getInstrsPassingParam(localPk); iter.hasNext();) { - SSAInvokeInstruction callInstr = iter.next(); - for (int i = 0; i < callInstr.getNumberOfUses(); i++) { - if (localPk.getValueNumber() != callInstr.getUse(i)) - continue; - CallSiteReference callSiteRef = callInstr.getCallSite(); - CallerSiteContext callSiteAndCGNode = new CallerSiteContext(caller, callSiteRef); - // get call targets - Set possibleCallees = g.getPossibleTargets(caller, callSiteRef, localPk); - // construct graph for each target - if (noOnTheFlyNeeded(callSiteAndCGNode, possibleCallees)) { - for (CGNode callee : possibleCallees) { - if (calleeSubGraphMissingAndShouldNotBeAdded(addGraphs, callee, curPkAndState)) { - continue; - } - if (hasNullIR(callee)) { - continue; - } - g.addSubgraphForNode(callee); - PointerKey paramVal = heapModel.getPointerKeyForLocal(callee, i + 1); - assert g.containsNode(paramVal); - handler.handle(curPkAndState, paramVal, ParamBarLabel.make(callSiteAndCGNode)); - } - } else { - if (callToOTFTargets.containsKey(callSiteAndCGNode)) { - // already queried this call site - // handle existing targets - Set targetMethods = callToOTFTargets.get(callSiteAndCGNode); - for (CGNode callee : possibleCallees) { - if (targetMethods.contains(callee.getMethod())) { - if (hasNullIR(callee)) { - continue; - } - g.addSubgraphForNode(callee); - PointerKey paramVal = heapModel.getPointerKeyForLocal(callee, i + 1); - assert g.containsNode(paramVal); - handler.handle(curPkAndState, paramVal, ParamBarLabel.make(callSiteAndCGNode)); - } - } - } else { - // if necessary, raise a query for the call site - queryCallTargets(callSiteAndCGNode, getCallInstrs(caller, callSiteAndCGNode.getCallSite()), curState); - } - } - } - } - } - } - - /** - * when doing backward interprocedural propagation, is it true that we should not add a graph representation for a callee _and_ - * that the subgraph for the callee is missing? - * - * @param addGraphs whether graphs should always be added - * @param callee - * @param pkAndState - * @return - */ - protected boolean calleeSubGraphMissingAndShouldNotBeAdded(boolean addGraphs, CGNode callee, PointerKeyAndState pkAndState) { - return !addGraphs && !g.hasSubgraphForNode(callee); - } - - public void handleTrackedPointsToWorklist() { - // if (Assertions.verifyAssertions) { - // Assertions._assert(trackedPointsToWorklist.isEmpty() || refineFields); - // } - while (!trackedPointsToWorklist.isEmpty()) { - incrementNumNodesTraversed(); - final PointerKeyAndState curPkAndState = trackedPointsToWorklist.iterator().next(); - trackedPointsToWorklist.remove(curPkAndState); - final PointerKey curPk = curPkAndState.getPointerKey(); - final State curState = curPkAndState.getState(); - if (DEBUG) - System.err.println("tracked points-to " + curPkAndState); - final MutableIntSet trackedSet = find(pkToTrackedSet, curPkAndState); - IFlowLabelVisitor succVisitor = new AbstractFlowLabelVisitor() { - - @Override - public void visitPutField(PutFieldLabel label, Object dst) { - // statements x.f = y, X' updated, f in map - // query y; if already queried, add Y to Z.f for all - // z in X' - IField field = label.getField(); - PointerKey dstPtrKey = (PointerKey) dst; - if (refineFieldAccesses(field, curPk, dstPtrKey, label, curState)) { - for (InstanceKeyAndState ikAndState : makeOrdinalSet(trackedSet)) { - boolean needField = forwInstKeyToFields.get(ikAndState).contains(field); - PointerKeyAndState storeDst = new PointerKeyAndState(dstPtrKey, curState); - encounteredStores.add(new StoreEdge(curPkAndState, field, storeDst)); - if (needField) { - if (!addToInitWorklist(storeDst)) { - InstanceFieldKeyAndState ifk = getInstFieldKey(ikAndState, field); - findOrCreate(instFieldKeyToP2Set, ifk).addAll(find(pkToP2Set, storeDst)); - } - } - } - } - } - }; - g.visitSuccs(curPk, succVisitor); - IFlowLabelVisitor predVisitor = new AbstractFlowLabelVisitor() { - - @Override - public void visitAssignGlobal(final AssignGlobalLabel label, Object dst) { - for (Iterator readIter = g.getReadsOfStaticField((StaticFieldKey) dst); readIter.hasNext();) { - final PointerKey predPk = (PointerKey) readIter.next(); - doTransition(curState, AssignGlobalBarLabel.v(), new Function() { - - public Object apply(State predPkState) { - PointerKeyAndState predPkAndState = new PointerKeyAndState(predPk, predPkState); - handleTrackedPred(trackedSet, predPkAndState, AssignGlobalBarLabel.v()); - return null; - } - - }); - } - } - - @Override - public void visitPutField(PutFieldLabel label, Object dst) { - IField field = label.getField(); - PointerKey storeBase = (PointerKey) dst; - // bar label since this is for tracked points-to sets - if (refineFieldAccesses(field, storeBase, curPk, label.bar(), curState)) { - PointerKeyAndState storeBaseAndState = new PointerKeyAndState(storeBase, curState); - encounteredStores.add(new StoreEdge(storeBaseAndState, field, curPkAndState)); - if (!addToInitWorklist(storeBaseAndState)) { - for (InstanceKeyAndState ikAndState : makeOrdinalSet(find(pkToP2Set, storeBaseAndState))) { - InstanceFieldKeyAndState ifk = getInstFieldKey(ikAndState, field); - findOrCreate(instFieldKeyToTrackedSet, ifk).addAll(trackedSet); - trackInstanceField(ikAndState, field, backInstKeyToFields); - } - } - } else { - // send to all getfield sources - for (Iterator readIter = g.getReadsOfInstanceField(storeBase, field); readIter.hasNext();) { - final PointerKey predPk = readIter.next(); - doTransition(curState, MatchBarLabel.v(), new Function() { - - public Object apply(State predPkState) { - PointerKeyAndState predPkAndState = new PointerKeyAndState(predPk, predPkState); - handleTrackedPred(trackedSet, predPkAndState, MatchBarLabel.v()); - return null; - } - - }); - } - - } - } - - @Override - public void visitGetField(GetFieldLabel label, Object dst) { - IField field = label.getField(); - PointerKey dstPtrKey = (PointerKey) dst; - // x = y.f, Y' updated - // bar label since this is for tracked points-to sets - if (refineFieldAccesses(field, curPk, dstPtrKey, label.bar(), curState)) { - for (InstanceKeyAndState ikAndState : makeOrdinalSet(trackedSet)) { - // tracking value written into ik.field - boolean needField = backInstKeyToFields.get(ikAndState).contains(field); - PointerKeyAndState loadedVal = new PointerKeyAndState(dstPtrKey, curState); - addEncounteredLoad(new LoadEdge(curPkAndState, field, loadedVal)); - if (needField) { - InstanceFieldKeyAndState ifk = getInstFieldKey(ikAndState, field); - // use an assign bar label with no filter here, since filtering only happens at casts - handleTrackedPred(find(instFieldKeyToTrackedSet, ifk), loadedVal, AssignBarLabel.noFilter()); - } - } - } - } - - @Override - public void visitAssign(final AssignLabel label, Object dst) { - final PointerKey predPk = (PointerKey) dst; - doTransition(curState, label.bar(), new Function() { - - public Object apply(State predPkState) { - PointerKeyAndState predPkAndState = new PointerKeyAndState(predPk, predPkState); - handleTrackedPred(trackedSet, predPkAndState, label.bar()); - return null; - } - - }); - } - - }; - g.visitPreds(curPk, predVisitor); - handleBackInterproc(curPkAndState, new CopyHandler() { - - @Override - void handle(PointerKeyAndState src, final PointerKey dst, final IFlowLabel label) { - assert src == curPkAndState; - doTransition(curState, label, new Function() { - public Object apply(State dstState) { - PointerKeyAndState dstAndState = new PointerKeyAndState(dst, dstState); - handleTrackedPred(trackedSet, dstAndState, label); - return null; - } - - }); - } - - }, true); - } - } - - private void addEncounteredLoad(LoadEdge loadEdge) { - if (encounteredLoads.add(loadEdge)) { - // if (DEBUG) { - // System.err.println("encountered load edge " + loadEdge); - // } - } - } - - public void makePassOverFieldStmts() { - for (StoreEdge storeEdge : encounteredStores) { - PointerKeyAndState storedValAndState = storeEdge.val; - IField field = storeEdge.field; - PointerKeyAndState baseAndState = storeEdge.base; - // x.f = y, X' updated - // for each z in X' such that f in z's map, - // add Y to Z.f - IntSet trackedSet = find(pkToTrackedSet, baseAndState); - for (InstanceKeyAndState ikAndState : makeOrdinalSet(trackedSet)) { - if (forwInstKeyToFields.get(ikAndState).contains(field)) { - if (!addToInitWorklist(storedValAndState)) { - InstanceFieldKeyAndState ifk = getInstFieldKey(ikAndState, field); - findOrCreate(instFieldKeyToP2Set, ifk).addAll(find(pkToP2Set, storedValAndState)); - } - } - } - } - for (LoadEdge loadEdge : encounteredLoads) { - PointerKeyAndState loadedValAndState = loadEdge.val; - IField field = loadEdge.field; - PointerKey basePointerKey = loadEdge.base.getPointerKey(); - State loadDstState = loadedValAndState.getState(); - PointerKeyAndState baseAndStateToHandle = new PointerKeyAndState(basePointerKey, loadDstState); - boolean basePointerOkay = pointsToQueried.get(basePointerKey).contains(loadDstState) - || !pointsToQueried.get(loadedValAndState.getPointerKey()).contains(loadDstState) - || initWorklist.contains(loadedValAndState); - // if (!basePointerOkay) { - // System.err.println("ASSERTION WILL FAIL"); - // System.err.println("QUERIED: " + queriedPkAndStates); - // } - if (!basePointerOkay) { - // remove this assertion, since we now allow multiple queries --MS - // Assertions._assert(false, "queried " + loadedValAndState + " but not " + baseAndStateToHandle); - } - final IntSet curP2Set = find(pkToP2Set, baseAndStateToHandle); - // int startSize = curP2Set.size(); - // int curSize = -1; - for (InstanceKeyAndState ikAndState : makeOrdinalSet(curP2Set)) { - // curSize = curP2Set.size(); - // if (Assertions.verifyAssertions) { - // Assertions._assert(startSize == curSize); - // } - InstanceFieldKeyAndState ifk = getInstFieldKey(ikAndState, field); - // make sure we've actually queried the def'd val before adding to its points-to set - if (pointsToQueried.get(loadedValAndState.getPointerKey()).contains(loadedValAndState.getState())) { - // just pass no label assign filter since no type-based filtering can be - // done here - if (addAllToP2Set(pkToP2Set, loadedValAndState, find(instFieldKeyToP2Set, ifk), AssignLabel.noFilter())) { - if (DEBUG) { - System.err.println("from load edge " + loadEdge); - } - addToPToWorklist(loadedValAndState); - } - } - } - // } - // x = y.f, Y' updated - PointerKeyAndState baseAndState = loadEdge.base; - for (InstanceKeyAndState ikAndState : makeOrdinalSet(find(pkToTrackedSet, baseAndState))) { - if (backInstKeyToFields.get(ikAndState).contains(field)) { - // tracking value written into ik.field - InstanceFieldKeyAndState ifk = getInstFieldKey(ikAndState, field); - if (findOrCreate(pkToTrackedSet, loadedValAndState).addAll(find(instFieldKeyToTrackedSet, ifk))) { - if (DEBUG) { - System.err.println("from load edge " + loadEdge); - } - addToTrackedPToWorklist(loadedValAndState); - } - } - } - } - } - - private InstanceFieldKeyAndState getInstFieldKey(InstanceKeyAndState ikAndState, IField field) { - return new InstanceFieldKeyAndState(new InstanceFieldKey(ikAndState.getInstanceKey(), field), ikAndState.getState()); - } - - protected MutableIntSet findOrCreate(Map M, K key) { - MutableIntSet result = M.get(key); - if (result == null) { - result = intSetFactory.make(); - M.put(key, result); - } - return result; - } - - private final MutableIntSet emptySet = intSetFactory.make(); - - protected MutableIntSet find(Map M, K key) { - MutableIntSet result = M.get(key); - if (result == null) { - result = emptySet; - } - return result; - } - - /** - * Handle a predecessor when processing some tracked locations - * - * @param curTrackedSet the tracked locations - * @param predPkAndState the predecessor - */ - protected boolean handleTrackedPred(final MutableIntSet curTrackedSet, PointerKeyAndState predPkAndState, IFlowLabel label) { - if (addAllToP2Set(pkToTrackedSet, predPkAndState, curTrackedSet, label)) { - addToTrackedPToWorklist(predPkAndState); - return true; - } - return false; - } - } - - private SSAAbstractInvokeInstruction[] getCallInstrs(CGNode node, CallSiteReference site) { - return node.getIR().getCalls(site); - } - - private boolean hasNullIR(CGNode node) { - boolean ret = node.getMethod().isNative(); - assert node.getIR() != null || ret; - return ret; - } - - private Object doTransition(State curState, IFlowLabel label, Function func) { - State nextState = stateMachine.transition(curState, label); - Object ret = null; - if (nextState != StateMachine.ERROR) { - ret = func.apply(nextState); - } else { - // System.err.println("filtered at edge " + label); - } - return ret; - } - - public StateMachineFactory getStateMachineFactory() { - return stateMachineFactory; - } - - public void setStateMachineFactory(StateMachineFactory stateMachineFactory) { - this.stateMachineFactory = stateMachineFactory; - } - - public RefinementPolicyFactory getRefinementPolicyFactory() { - return refinementPolicyFactory; - } - - public void setRefinementPolicyFactory(RefinementPolicyFactory refinementPolicyFactory) { - this.refinementPolicyFactory = refinementPolicyFactory; - } - - /** - * we are looking for an instance key flowing to pk that violates pred. - * - * @param pk - * @param pred - * @param pa - */ - @SuppressWarnings("unused") - private boolean doTopLevelTraversal(PointerKey pk, final Predicate pred, final PointsToComputer ptoComputer, - PointerAnalysis pa) { - final Set visited = HashSetFactory.make(); - final LinkedList worklist = new LinkedList(); - - class Helper { - - /** - * cache of the targets discovered for a call site during on-the-fly call graph construction - */ - private final MultiMap callToOTFTargets = ArraySetMultiMap.make(); - - void propagate(PointerKeyAndState pkAndState) { - if (visited.add(pkAndState)) { - assert graphContainsNode(pkAndState.getPointerKey()); - worklist.addLast(pkAndState); - } - } - - private boolean graphContainsNode(PointerKey pointerKey) { - if (pointerKey instanceof LocalPointerKey) { - LocalPointerKey lpk = (LocalPointerKey) pointerKey; - return g.hasSubgraphForNode(lpk.getNode()); - } - return true; - } - - private Collection getOTFTargets(CallerSiteContext callSiteAndCGNode, SSAAbstractInvokeInstruction[] callInstrs, - State callerState) { - if (DEBUG_TOPLEVEL) { - System.err.println("toplevel refining call site " + callSiteAndCGNode); - } - final CallSiteReference call = callSiteAndCGNode.getCallSite(); - final CGNode caller = callSiteAndCGNode.getCaller(); - Collection result = HashSetFactory.make(); - for (SSAAbstractInvokeInstruction callInstr : callInstrs) { - PointerKey thisArg = heapModel.getPointerKeyForLocal(caller, callInstr.getUse(0)); - PointerKeyAndState thisArgAndState = new PointerKeyAndState(thisArg, callerState); - OrdinalSet thisPToSet = getPToSetFromComputer(ptoComputer, thisArgAndState); - for (InstanceKeyAndState ikAndState : thisPToSet) { - InstanceKey ik = ikAndState.getInstanceKey(); - IMethod targetMethod = options.getMethodTargetSelector().getCalleeTarget(caller, call, ik.getConcreteType()); - if (targetMethod == null) { - // NOTE: target method can be null because we don't - // always have type filters - continue; - } - result.add(targetMethod); - } - } - return result; - } - - public void handleTopLevelForwInterproc(PointerKeyAndState curPkAndState) { - PointerKey curPk = curPkAndState.getPointerKey(); - final State curState = curPkAndState.getState(); - if (curPk instanceof LocalPointerKey) { - final LocalPointerKey localPk = (LocalPointerKey) curPk; - if (g.isParam(localPk)) { - // System.err.println("at param"); - final CGNode callee = localPk.getNode(); - final int paramPos = localPk.getValueNumber() - 1; - for (final CallerSiteContext callSiteAndCGNode : g.getPotentialCallers(localPk)) { - final CGNode caller = callSiteAndCGNode.getCaller(); - final CallSiteReference call = callSiteAndCGNode.getCallSite(); - // final IR ir = getIR(caller); - if (hasNullIR(caller)) - continue; - final ParamLabel paramLabel = ParamLabel.make(callSiteAndCGNode); - doTransition(curPkAndState.getState(), paramLabel, new Function() { - - private void propagateToCallee() { - // if (caller.getIR() == null) { - // return; - // } - g.addSubgraphForNode(caller); - SSAAbstractInvokeInstruction[] callInstrs = getCallInstrs(caller, call); - for (int i = 0; i < callInstrs.length; i++) { - SSAAbstractInvokeInstruction callInstr = callInstrs[i]; - final PointerKey actualPk = heapModel.getPointerKeyForLocal(caller, callInstr.getUse(paramPos)); - assert g.containsNode(actualPk); - assert g.containsNode(localPk); - doTransition(curState, paramLabel, new Function() { - public Object apply(State nextState) { - propagate(new PointerKeyAndState(actualPk, nextState)); - return null; - } - - }); - } - } - - public Object apply(State callerState) { - // hack to get some actual parameter from call site - // TODO do this better - SSAAbstractInvokeInstruction[] callInstrs = getCallInstrs(caller, call); - SSAAbstractInvokeInstruction callInstr = callInstrs[0]; - PointerKey actualPk = heapModel.getPointerKeyForLocal(caller, callInstr.getUse(paramPos)); - Set possibleTargets = g.getPossibleTargets(caller, call, (LocalPointerKey) actualPk); - if (noOnTheFlyNeeded(callSiteAndCGNode, possibleTargets)) { - propagateToCallee(); - } else { - Collection otfTargets = getOTFTargets(callSiteAndCGNode, callInstrs, callerState); - if (otfTargets.contains(callee.getMethod())) { - // already found this target as valid, so do propagation - propagateToCallee(); - } - } - return null; - } - - }); - - } - } - SSAInvokeInstruction callInstr = g.getInstrReturningTo(localPk); - if (callInstr != null) { - CGNode caller = localPk.getNode(); - boolean isExceptional = localPk.getValueNumber() == callInstr.getException(); - - CallSiteReference callSiteRef = callInstr.getCallSite(); - CallerSiteContext callSiteAndCGNode = new CallerSiteContext(caller, callSiteRef); - // get call targets - Set possibleCallees = g.getPossibleTargets(caller, callSiteRef, localPk); - if (noOnTheFlyNeeded(callSiteAndCGNode, possibleCallees)) { - for (CGNode callee : possibleCallees) { - if (hasNullIR(callee)) { - continue; - } - g.addSubgraphForNode(callee); - final PointerKey retVal = isExceptional ? heapModel.getPointerKeyForExceptionalReturnValue(callee) : heapModel - .getPointerKeyForReturnValue(callee); - assert g.containsNode(retVal); - doTransition(curState, ReturnLabel.make(callSiteAndCGNode), new Function() { - - public Object apply(State nextState) { - propagate(new PointerKeyAndState(retVal, nextState)); - return null; - } - - }); - } - } else { - Collection otfTargets = getOTFTargets(callSiteAndCGNode, getCallInstrs(caller, callSiteAndCGNode - .getCallSite()), curPkAndState.getState()); - for (CGNode callee : possibleCallees) { - if (otfTargets.contains(callee.getMethod())) { - if (hasNullIR(callee)) { - continue; - } - g.addSubgraphForNode(callee); - final PointerKey retVal = isExceptional ? heapModel.getPointerKeyForExceptionalReturnValue(callee) : heapModel - .getPointerKeyForReturnValue(callee); - assert g.containsNode(retVal); - doTransition(curState, ReturnLabel.make(callSiteAndCGNode), new Function() { - - public Object apply(State nextState) { - propagate(new PointerKeyAndState(retVal, nextState)); - return null; - } - - }); - } - } - } - } - } - - } - - private OrdinalSet getPToSetFromComputer(final PointsToComputer ptoComputer, - PointerKeyAndState pointerKeyAndState) { - // make sure relevant constraints have been added - if (pointerKeyAndState.getPointerKey() instanceof LocalPointerKey) { - LocalPointerKey lpk = (LocalPointerKey) pointerKeyAndState.getPointerKey(); - g.addSubgraphForNode(lpk.getNode()); - } - // add pointerKeyAndState to init worklist - ptoComputer.addToInitWorklist(pointerKeyAndState); - // run worklist algorithm - ptoComputer.worklistLoop(); - // suck out the points-to set - final MutableIntSet intP2Set = ptoComputer.pkToP2Set.get(pointerKeyAndState); - if (intP2Set == null) { - // null if empty p2set - return OrdinalSet.empty(); - } else { - return ptoComputer.makeOrdinalSet(intP2Set); - } - } - - private void computeFlowsTo(PointsToComputer ptoComputer, OrdinalSet basePToSet) { - for (InstanceKeyAndState ikAndState : basePToSet) { - ptoComputer.addPredsOfIKeyAndStateToTrackedPointsTo(ikAndState); - } - // run worklist loop - assert ptoComputer.initWorklist.isEmpty(); - assert ptoComputer.pointsToWorklist.isEmpty(); - ptoComputer.worklistLoop(); - } - - private Collection getFlowedToStates(PointsToComputer ptoComputer, OrdinalSet basePToSet, - PointerKey putfieldBase) { - Collection result = HashSetFactory.make(); - Set trackedStates = ptoComputer.trackedQueried.get(putfieldBase); - for (State trackedState : trackedStates) { - PointerKeyAndState pkAndState = new PointerKeyAndState(putfieldBase, trackedState); - if (ptoComputer.makeOrdinalSet(ptoComputer.pkToTrackedSet.get(pkAndState)).containsAny(basePToSet)) { - result.add(trackedState); - } - } - // for (PointerKeyAndState pkAndState : ptoComputer.pkToTrackedSet.keySet()) { - // if (pkAndState.getPointerKey().equals(putfieldBase)) { - // if (ptoComputer.makeOrdinalSet(ptoComputer.pkToTrackedSet.get(pkAndState)).containsAny(basePToSet)) { - // result.add(pkAndState.getState()); - // } - // } - // } - return result; - } - - } - final Helper h = new Helper(); - PointerKeyAndState initPkAndState = new PointerKeyAndState(pk, stateMachine.getStartState()); - if (pk instanceof LocalPointerKey) { - g.addSubgraphForNode(((LocalPointerKey) pk).getNode()); - } - h.propagate(initPkAndState); - while (!worklist.isEmpty()) { - incrementNumNodesTraversed(); - PointerKeyAndState curPkAndState = worklist.removeFirst(); - final PointerKey curPk = curPkAndState.getPointerKey(); - final State curState = curPkAndState.getState(); - // if predicate holds for pre-computed points-to set of curPk, we are done - if (DEBUG_TOPLEVEL) { - System.err.println("toplevel pkAndState " + curPkAndState); - } - if (predHoldsForPk(curPk, pred, pa)) { - if (DEBUG_TOPLEVEL) { - System.err.println("predicate holds"); - } - continue; - } - // otherwise, traverse new, assign, assign global, param, return, match edges - class MyFlowLabelVisitor extends AbstractFlowLabelVisitor { - - boolean foundBadInstanceKey; - - @Override - public void visitNew(NewLabel label, Object dst) { - // TODO Auto-generated method stub - - final InstanceKey ik = (InstanceKey) dst; - if (DEBUG_TOPLEVEL) { - System.err.println("toplevel alloc " + ik + " assigned to " + curPk); - } - doTransition(curState, label, new Function() { - - public Object apply(State newState) { - // just check if ik violates the pred - if (!pred.test(ik)) { - foundBadInstanceKey = true; - } - return null; - } - - }); - } - - @Override - public void visitGetField(GetFieldLabel label, Object dst) { - IField field = (label).getField(); - PointerKey loadBase = (PointerKey) dst; - if (refineFieldAccesses(field, loadBase, curPk, label, curState)) { - if (DEBUG_TOPLEVEL) { - System.err.println("toplevel refining for read of " + field); - } - // find points-to set of base pointer - OrdinalSet basePToSet = h.getPToSetFromComputer(ptoComputer, new PointerKeyAndState(loadBase, - curState)); - if (DEBUG_TOPLEVEL) { - System.err.println("toplevel base pointer p2set " + basePToSet); - } - // find "flows-to sets" of pointed-to instance keys - h.computeFlowsTo(ptoComputer, basePToSet); - if (DEBUG_TOPLEVEL) { - System.err.println("toplevel finished computing flows to"); - } - // for each putfield base pointer, if flowed-to, then propagate written pointer key - for (MemoryAccess fieldWrite : getWrites(field, loadBase)) { - Collection> baseAndStoredPairs = getBaseAndStored(fieldWrite, field); - if (baseAndStoredPairs == null) { - continue; - } - for (Pair p : baseAndStoredPairs) { - PointerKey base = p.fst; - PointerKey stored = p.snd; - Collection reachedFlowStates = h.getFlowedToStates(ptoComputer, basePToSet, base); - for (State nextState : reachedFlowStates) { - if (DEBUG_TOPLEVEL) { - System.err.println("toplevel alias with base " + base + " in state " + nextState); - } - h.propagate(new PointerKeyAndState(stored, nextState)); - } - } - } - } else { // use match edges - for (Iterator writesToInstanceField = g.getWritesToInstanceField(loadBase, field); writesToInstanceField - .hasNext();) { - final PointerKey writtenPk = writesToInstanceField.next(); - doTransition(curState, MatchLabel.v(), new Function() { - - public Object apply(State nextState) { - h.propagate(new PointerKeyAndState(writtenPk, nextState)); - return null; - } - - }); - } - } - } - - private Collection> getBaseAndStored(MemoryAccess fieldWrite, IField field) { - final CGNode node = fieldWrite.getNode(); - // an optimization; if node is not represented in our constraint graph, then we could not possibly - // have discovered flow to the base pointer - if (!g.hasSubgraphForNode(node)) { - return null; - } - IR ir = node.getIR(); - PointerKey base = null, stored = null; - if (field == ArrayContents.v()) { - final SSAInstruction instruction = ir.getInstructions()[fieldWrite.getInstructionIndex()]; - if (instruction == null) { - return null; - } - if (instruction instanceof SSANewInstruction) { - return DemandPointerFlowGraph.getInfoForNewMultiDim((SSANewInstruction) instruction, heapModel, fieldWrite.getNode()).arrStoreInstrs; - } - SSAArrayStoreInstruction s = (SSAArrayStoreInstruction) instruction; - base = heapModel.getPointerKeyForLocal(fieldWrite.getNode(), s.getArrayRef()); - stored = heapModel.getPointerKeyForLocal(fieldWrite.getNode(), s.getValue()); - } else { - SSAPutInstruction s = (SSAPutInstruction) ir.getInstructions()[fieldWrite.getInstructionIndex()]; - if (s == null) { - return null; - } - base = heapModel.getPointerKeyForLocal(fieldWrite.getNode(), s.getRef()); - stored = heapModel.getPointerKeyForLocal(fieldWrite.getNode(), s.getVal()); - } - return Collections.singleton(Pair.make(base, stored)); - } - - private Collection getWrites(IField field, PointerKey loadBase) { - final PointerKey convertedBase = convertToHeapModel(loadBase, mam.getHeapModel()); - if (field == ArrayContents.v()) { - return mam.getArrayWrites(loadBase); - } else { - return mam.getFieldWrites(convertedBase, field); - } - } - - @Override - public void visitAssignGlobal(AssignGlobalLabel label, Object dst) { - for (Iterator writesToStaticField = g.getWritesToStaticField((StaticFieldKey) dst); writesToStaticField - .hasNext();) { - final PointerKey writtenPk = (PointerKey) writesToStaticField.next(); - doTransition(curState, label, new Function() { - - public Object apply(State nextState) { - h.propagate(new PointerKeyAndState(writtenPk, nextState)); - return null; - } - - }); - - } - } - - @Override - public void visitAssign(AssignLabel label, Object dst) { - final PointerKey succPk = (PointerKey) dst; - doTransition(curState, label, new Function() { - - public Object apply(State nextState) { - h.propagate(new PointerKeyAndState(succPk, nextState)); - return null; - } - - }); - } - - } - MyFlowLabelVisitor v = new MyFlowLabelVisitor(); - g.visitSuccs(curPk, v); - if (v.foundBadInstanceKey) { - // found an instance key violating the pred - return false; - } - h.handleTopLevelForwInterproc(curPkAndState); - } - return true; - } - - private boolean predHoldsForPk(PointerKey curPk, Predicate pred, PointerAnalysis pa) { - PointerKey curPkForPAHeapModel = convertToHeapModel(curPk, pa.getHeapModel()); - OrdinalSet pointsToSet = pa.getPointsToSet(curPkForPAHeapModel); - for (InstanceKey ik : pointsToSet) { - if (!pred.test(ik)) { - return false; - } - } - return true; - } - - private PointerKey convertToHeapModel(PointerKey curPk, HeapModel heapModel) { - return AbstractFlowGraph.convertPointerKeyToHeapModel(curPk, heapModel); - } - - private boolean refineFieldAccesses(IField field, PointerKey basePtr, PointerKey val, IFlowLabel label, State state) { - boolean shouldRefine = refinementPolicy.getFieldRefinePolicy().shouldRefine(field, basePtr, val, label, state); - if (DEBUG) { - if (shouldRefine) { - System.err.println("refining access to " + field); - } else { - System.err.println("using match for access to " + field); - } - } - return shouldRefine; - } - - private boolean noOnTheFlyNeeded(CallerSiteContext call, Set possibleTargets) { - // NOTE: if we want to be more precise for queries in dead code, - // we shouldn't rely on possibleTargets here (since there may be - // zero targets) - if (!refinementPolicy.getCallGraphRefinePolicy().shouldRefine(call)) { - return true; - } - // here we compute the number of unique *method* targets, as opposed to call graph nodes. - // if we have a context-sensitive call graph, with many targets representing clones of - // the same method, we don't want to count the clones twice - Set methodTargets = new HashSet(); - for (CGNode node : possibleTargets) { - methodTargets.add(node.getMethod()); - } - return methodTargets.size() <= 1; - } - - /** - * used to compute "flows-to sets," i.e., all the pointers that can point to some instance key - * - */ - protected class FlowsToComputer extends PointsToComputer { - - private final InstanceKeyAndState queriedIkAndState; - - private final int queriedIkAndStateNum; - - /** - * holds the desired flows-to set - */ - private final Collection theFlowsToSet = HashSetFactory.make(); - - public FlowsToComputer(InstanceKeyAndState ikAndState) { - this.queriedIkAndState = ikAndState; - this.queriedIkAndStateNum = ikAndStates.add(queriedIkAndState); - } - - @Override - protected void compute() { - // seed the points-to worklist - - InstanceKey ik = queriedIkAndState.getInstanceKey(); - g.addSubgraphForNode(((InstanceKeyWithNode) ik).getNode()); - for (Object pred : Iterator2Iterable.make(g.getPredNodes(ik, NewLabel.v()))) { - PointerKey predPk = (PointerKey) pred; - PointerKeyAndState predPkAndState = new PointerKeyAndState(predPk, queriedIkAndState.getState()); - theFlowsToSet.add(predPkAndState); - findOrCreate(pkToTrackedSet, predPkAndState).add(queriedIkAndStateNum); - addToTrackedPToWorklist(predPkAndState); - } - worklistLoop(); - } - - public Collection getComputedFlowsToSet() { - return theFlowsToSet; - } - - /** - * also update the flows-to set of interest if necessary - */ - @Override - protected boolean handleTrackedPred(MutableIntSet curTrackedSet, PointerKeyAndState predPkAndState, IFlowLabel label) { - boolean result = super.handleTrackedPred(curTrackedSet, predPkAndState, label); - if (result && find(pkToTrackedSet, predPkAndState).contains(queriedIkAndStateNum)) { - theFlowsToSet.add(predPkAndState); - } - return result; - } - - } - -} +/******************************************************************************* + * 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. + * + * This file is a derivative of code released by the University of + * California under the terms listed below. + * + * Refinement Analysis Tools is Copyright (c) 2007 The Regents of the + * University of California (Regents). Provided that this notice and + * the following two paragraphs are included in any distribution of + * Refinement Analysis Tools or its derivative work, Regents agrees + * not to assert any of Regents' copyright rights in Refinement + * Analysis Tools against recipient for recipient's reproduction, + * preparation of derivative works, public display, public + * performance, distribution or sublicensing of Refinement Analysis + * Tools and derivative works, in source code and object code form. + * This agreement not to assert does not confer, by implication, + * estoppel, or otherwise any license or rights in any intellectual + * property of Regents, including, but not limited to, any patents + * of Regents or Regents' employees. + * + * IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, + * INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, + * INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE + * AND ITS DOCUMENTATION, EVEN IF REGENTS HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE AND FURTHER DISCLAIMS ANY STATUTORY + * WARRANTY OF NON-INFRINGEMENT. THE SOFTWARE AND ACCOMPANYING + * DOCUMENTATION, IF ANY, PROVIDED HEREUNDER IS PROVIDED "AS + * IS". REGENTS HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, + * UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + */ +package com.ibm.wala.demandpa.alg; + +import java.util.Collection; +import java.util.Collections; +import java.util.HashSet; +import java.util.Iterator; +import java.util.LinkedHashSet; +import java.util.LinkedList; +import java.util.Map; +import java.util.Set; + +import com.ibm.wala.analysis.reflection.InstanceKeyWithNode; +import com.ibm.wala.classLoader.CallSiteReference; +import com.ibm.wala.classLoader.IClass; +import com.ibm.wala.classLoader.IField; +import com.ibm.wala.classLoader.IMethod; +import com.ibm.wala.classLoader.ShrikeBTMethod; +import com.ibm.wala.demandpa.alg.refinepolicy.NeverRefineCGPolicy; +import com.ibm.wala.demandpa.alg.refinepolicy.NeverRefineFieldsPolicy; +import com.ibm.wala.demandpa.alg.refinepolicy.RefinementPolicy; +import com.ibm.wala.demandpa.alg.refinepolicy.RefinementPolicyFactory; +import com.ibm.wala.demandpa.alg.refinepolicy.SinglePassRefinementPolicy; +import com.ibm.wala.demandpa.alg.statemachine.StateMachine; +import com.ibm.wala.demandpa.alg.statemachine.StateMachine.State; +import com.ibm.wala.demandpa.alg.statemachine.StateMachineFactory; +import com.ibm.wala.demandpa.alg.statemachine.StatesMergedException; +import com.ibm.wala.demandpa.flowgraph.AbstractFlowGraph; +import com.ibm.wala.demandpa.flowgraph.AbstractFlowLabelVisitor; +import com.ibm.wala.demandpa.flowgraph.AssignBarLabel; +import com.ibm.wala.demandpa.flowgraph.AssignGlobalBarLabel; +import com.ibm.wala.demandpa.flowgraph.AssignGlobalLabel; +import com.ibm.wala.demandpa.flowgraph.AssignLabel; +import com.ibm.wala.demandpa.flowgraph.DemandPointerFlowGraph; +import com.ibm.wala.demandpa.flowgraph.GetFieldLabel; +import com.ibm.wala.demandpa.flowgraph.IFlowGraph; +import com.ibm.wala.demandpa.flowgraph.IFlowLabel; +import com.ibm.wala.demandpa.flowgraph.IFlowLabel.IFlowLabelVisitor; +import com.ibm.wala.demandpa.flowgraph.IFlowLabelWithFilter; +import com.ibm.wala.demandpa.flowgraph.MatchBarLabel; +import com.ibm.wala.demandpa.flowgraph.MatchLabel; +import com.ibm.wala.demandpa.flowgraph.NewLabel; +import com.ibm.wala.demandpa.flowgraph.ParamBarLabel; +import com.ibm.wala.demandpa.flowgraph.ParamLabel; +import com.ibm.wala.demandpa.flowgraph.PutFieldLabel; +import com.ibm.wala.demandpa.flowgraph.ReturnBarLabel; +import com.ibm.wala.demandpa.flowgraph.ReturnLabel; +import com.ibm.wala.demandpa.util.ArrayContents; +import com.ibm.wala.demandpa.util.MemoryAccess; +import com.ibm.wala.demandpa.util.MemoryAccessMap; +import com.ibm.wala.demandpa.util.PointerParamValueNumIterator; +import com.ibm.wala.ipa.callgraph.AnalysisOptions; +import com.ibm.wala.ipa.callgraph.CGNode; +import com.ibm.wala.ipa.callgraph.CallGraph; +import com.ibm.wala.ipa.callgraph.propagation.AbstractLocalPointerKey; +import com.ibm.wala.ipa.callgraph.propagation.FilteredPointerKey; +import com.ibm.wala.ipa.callgraph.propagation.FilteredPointerKey.MultipleClassesFilter; +import com.ibm.wala.ipa.callgraph.propagation.FilteredPointerKey.SingleClassFilter; +import com.ibm.wala.ipa.callgraph.propagation.FilteredPointerKey.SingleInstanceFilter; +import com.ibm.wala.ipa.callgraph.propagation.FilteredPointerKey.TypeFilter; +import com.ibm.wala.ipa.callgraph.propagation.HeapModel; +import com.ibm.wala.ipa.callgraph.propagation.InstanceFieldKey; +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.callgraph.propagation.ReturnValueKey; +import com.ibm.wala.ipa.callgraph.propagation.StaticFieldKey; +import com.ibm.wala.ipa.callgraph.propagation.cfa.CallerSiteContext; +import com.ibm.wala.ipa.callgraph.propagation.cfa.ExceptionReturnValueKey; +import com.ibm.wala.ipa.cha.IClassHierarchy; +import com.ibm.wala.shrikeBT.IInstruction; +import com.ibm.wala.shrikeCT.InvalidClassFileException; +import com.ibm.wala.ssa.IR; +import com.ibm.wala.ssa.SSAAbstractInvokeInstruction; +import com.ibm.wala.ssa.SSAArrayStoreInstruction; +import com.ibm.wala.ssa.SSAInstruction; +import com.ibm.wala.ssa.SSAInvokeInstruction; +import com.ibm.wala.ssa.SSANewInstruction; +import com.ibm.wala.ssa.SSAPutInstruction; +import com.ibm.wala.util.Predicate; +import com.ibm.wala.util.collections.ArraySet; +import com.ibm.wala.util.collections.ArraySetMultiMap; +import com.ibm.wala.util.collections.HashMapFactory; +import com.ibm.wala.util.collections.HashSetFactory; +import com.ibm.wala.util.collections.HashSetMultiMap; +import com.ibm.wala.util.collections.Iterator2Collection; +import com.ibm.wala.util.collections.Iterator2Iterable; +import com.ibm.wala.util.collections.MapIterator; +import com.ibm.wala.util.collections.MultiMap; +import com.ibm.wala.util.collections.Pair; +import com.ibm.wala.util.collections.Util; +import com.ibm.wala.util.debug.Assertions; +import com.ibm.wala.util.debug.UnimplementedError; +import com.ibm.wala.util.functions.Function; +import com.ibm.wala.util.intset.IntSet; +import com.ibm.wala.util.intset.IntSetAction; +import com.ibm.wala.util.intset.MutableIntSet; +import com.ibm.wala.util.intset.MutableIntSetFactory; +import com.ibm.wala.util.intset.MutableMapping; +import com.ibm.wala.util.intset.MutableSparseIntSetFactory; +import com.ibm.wala.util.intset.OrdinalSet; +import com.ibm.wala.util.intset.OrdinalSetMapping; + +/** + * Demand-driven refinement-based points-to analysis. + */ +public class DemandRefinementPointsTo extends AbstractDemandPointsTo { + + private static final boolean DEBUG = false; + + private static final boolean DEBUG_TOPLEVEL = false; + + private static final boolean PARANOID = false; + + private static final boolean MEASURE_MEMORY_USAGE = false; + + protected final IFlowGraph g; + + private StateMachineFactory stateMachineFactory; + + /** + * the state machine for additional filtering of paths + */ + private StateMachine stateMachine; + + protected RefinementPolicy refinementPolicy; + + private RefinementPolicyFactory refinementPolicyFactory; + + public RefinementPolicy getRefinementPolicy() { + return refinementPolicy; + } + + private DemandRefinementPointsTo(CallGraph cg, ThisFilteringHeapModel model, MemoryAccessMap fam, IClassHierarchy cha, + AnalysisOptions options, StateMachineFactory stateMachineFactory, IFlowGraph flowGraph) { + super(cg, model, fam, cha, options); + this.stateMachineFactory = stateMachineFactory; + g = flowGraph; + this.refinementPolicyFactory = new SinglePassRefinementPolicy.Factory(new NeverRefineFieldsPolicy(), new NeverRefineCGPolicy()); + sanityCheckCG(); + } + + private void sanityCheckCG() { + if (PARANOID) { + for (CGNode callee : cg) { + for (Iterator predNodes = cg.getPredNodes(callee); predNodes.hasNext();) { + CGNode caller = predNodes.next(); + for (Iterator iterator = cg.getPossibleSites(caller, callee); iterator.hasNext();) { + CallSiteReference site = iterator.next(); + try { + caller.getIR().getCalls(site); + } catch (IllegalArgumentException e) { + System.err.println(caller + " is pred of " + callee); + System.err.println("no calls at site " + site); + System.err.println(caller.getIR()); + if (caller.getMethod() instanceof ShrikeBTMethod) { + try { + IInstruction[] instructions = ((ShrikeBTMethod) caller.getMethod()).getInstructions(); + for (int i = 0; i < instructions.length; i++) { + System.err.println(i + ": " + instructions[i]); + } + } catch (InvalidClassFileException e1) { + // TODO Auto-generated catch block + e1.printStackTrace(); + } + } + Assertions.UNREACHABLE(); + } + } + } + } + } + } + + /** + * Possible results of a query. + * + * @see DemandRefinementPointsTo#getPointsTo(PointerKey, Predicate) + * @author manu + * + */ + public static enum PointsToResult { + /** + * The points-to set result satisfies the supplied {@link Predicate} + */ + SUCCESS, + /** + * The {@link RefinementPolicy} indicated that no more refinement was possible, and on at least one refinement pass the + * budget was not exhausted + */ + NOMOREREFINE, + /** + * The budget specified in the {@link RefinementPolicy} was exceeded on all refinement passes + */ + BUDGETEXCEEDED + }; + + /** + * re-initialize state for a new query + */ + protected void startNewQuery() { + // re-init the refinement policy + refinementPolicy = refinementPolicyFactory.make(); + // re-init the state machine + stateMachine = stateMachineFactory.make(); + } + + /** + * compute a points-to set for a pointer key, aiming to satisfy some predicate + * + * @param pk the pointer key + * @param ikeyPred the desired predicate that each instance key in the points-to set should ideally satisfy + * @return a pair consisting of (1) a {@link PointsToResult} indicating whether a points-to set satisfying the predicate was + * computed, and (2) the last computed points-to set for the variable (possibly null if no points-to set + * could be computed in the budget) + * @throws IllegalArgumentException if pk is not a {@link LocalPointerKey}; to eventually be fixed + */ + public Pair> getPointsTo(PointerKey pk, Predicate ikeyPred) + throws IllegalArgumentException { + Pair> p = getPointsToWithStates(pk, ikeyPred); + final Collection p2SetWithStates = p.snd; + Collection finalP2Set = removeStates(p2SetWithStates); + return Pair.make(p.fst, finalP2Set); + } + + /** + * @param pk + * @param ikeyPred + * @return + */ + private Pair> getPointsToWithStates(PointerKey pk, Predicate ikeyPred) { + if (!(pk instanceof com.ibm.wala.ipa.callgraph.propagation.LocalPointerKey)) { + throw new IllegalArgumentException("only locals for now"); + } + LocalPointerKey queriedPk = (LocalPointerKey) pk; + if (DEBUG) { + System.err.println("answering query for " + pk); + } + startNewQuery(); + Pair> p = outerRefinementLoop(new PointerKeyAndState(queriedPk, stateMachine + .getStartState()), ikeyPred); + return p; + } + + /** + * Unwrap a Collection of WithState objects, returning a Collection containing the wrapped objects + */ + private static Collection removeStates(final Collection> p2SetWithStates) { + Collection finalP2Set = Iterator2Collection.toSet(new MapIterator, T>(p2SetWithStates.iterator(), + new Function, T>() { + + public T apply(WithState object) { + return object.getWrapped(); + } + })); + return finalP2Set; + } + + /** + * create a demand points-to analysis runner + * + * @param cg the underlying call graph for the analysis + * @param model the heap model to be used for the analysis + * @param mam indicates what code reads or writes each field + * @param cha + * @param options + * @param stateMachineFactory factory for state machines to track additional properties like calling context + */ + public static DemandRefinementPointsTo makeWithDefaultFlowGraph(CallGraph cg, HeapModel model, MemoryAccessMap mam, + IClassHierarchy cha, AnalysisOptions options, StateMachineFactory stateMachineFactory) { + final ThisFilteringHeapModel thisFilteringHeapModel = new ThisFilteringHeapModel(model, cha); + return new DemandRefinementPointsTo(cg, thisFilteringHeapModel, mam, cha, options, stateMachineFactory, + new DemandPointerFlowGraph(cg, thisFilteringHeapModel, mam, cha)); + } + + private Pair> outerRefinementLoop(PointerKeyAndState queried, + Predicate ikeyPred) { + Collection lastP2Set = null; + boolean succeeded = false; + int numPasses = refinementPolicy.getNumPasses(); + int passNum = 0; + for (; passNum < numPasses; passNum++) { + setNumNodesTraversed(0); + setTraversalBudget(refinementPolicy.getBudgetForPass(passNum)); + Collection curP2Set = null; + PointsToComputer computer = null; + boolean completedPassInBudget = false; + try { + while (true) { + try { + computer = new PointsToComputer(queried); + computer.compute(); + curP2Set = computer.getComputedP2Set(queried); + // System.err.println("completed pass"); + if (DEBUG) { + System.err.println("traversed " + getNumNodesTraversed() + " nodes"); + System.err.println("POINTS-TO SET " + curP2Set); + } + completedPassInBudget = true; + break; + } catch (StatesMergedException e) { + if (DEBUG) { + System.err.println("restarting..."); + } + } + } + } catch (BudgetExceededException e) { + + } + if (curP2Set != null) { + if (lastP2Set == null) { + lastP2Set = curP2Set; + } else if (lastP2Set.size() > curP2Set.size()) { + // got a more precise set + assert removeStates(lastP2Set).containsAll(removeStates(curP2Set)); + lastP2Set = curP2Set; + } else { + // new set size is >= lastP2Set, so don't update + assert removeStates(curP2Set).containsAll(removeStates(lastP2Set)); + } + if (curP2Set.isEmpty() || passesPred(curP2Set, ikeyPred)) { + // we did it! + // if (curP2Set.isEmpty()) { + // System.err.println("EMPTY PTO SET"); + // } + succeeded = true; + break; + } else if (completedPassInBudget) { + } + } + // if we get here, means either budget for pass was exceeded, + // or points-to set wasn't good enough + // so, start new pass, if more refinement to do + if (!refinementPolicy.nextPass()) { + break; + } + } + PointsToResult result = null; + if (succeeded) { + result = PointsToResult.SUCCESS; + } else if (passNum == numPasses) { + // we ran all the passes without succeeding and + // without the refinement policy giving up + result = PointsToResult.BUDGETEXCEEDED; + } else { + if (lastP2Set != null) { + result = PointsToResult.NOMOREREFINE; + } else { + // we stopped before the maximum number of passes, but we never + // actually finished a pass, so we count this as BUDGETEXCEEDED + result = PointsToResult.BUDGETEXCEEDED; + } + } + return Pair.make(result, lastP2Set); + } + + /** + * to measure memory usage + */ + public long lastQueryMemoryUse; + + /** + * check if the points-to set of a variable passes some predicate, without necessarily computing the whole points-to set + * + * @param pk the pointer key + * @param ikeyPred the desired predicate that each instance key in the points-to set should ideally satisfy + * @param pa a pre-computed points-to analysis + * @return a {@link PointsToResult} indicating whether a points-to set satisfying the predicate was computed + * @throws IllegalArgumentException if pk is not a {@link LocalPointerKey}; to eventually be fixed + */ + public PointsToResult pointsToPassesPred(PointerKey pk, Predicate ikeyPred, PointerAnalysis pa) + throws IllegalArgumentException { + if (!(pk instanceof com.ibm.wala.ipa.callgraph.propagation.LocalPointerKey)) { + throw new IllegalArgumentException("only locals for now"); + } + LocalPointerKey queriedPk = (LocalPointerKey) pk; + if (DEBUG) { + System.err.println("answering query for " + pk); + } + boolean succeeded = false; + startNewQuery(); + int numPasses = refinementPolicy.getNumPasses(); + int passNum = 0; + boolean completedSomePass = false; + if (MEASURE_MEMORY_USAGE) { + lastQueryMemoryUse = -1; + } + for (; passNum < numPasses; passNum++) { + setNumNodesTraversed(0); + setTraversalBudget(refinementPolicy.getBudgetForPass(passNum)); + boolean completedPassInBudget = false; + boolean passed = false; + long initialMemory = 0; + try { + while (true) { + try { + if (MEASURE_MEMORY_USAGE) { + initialMemory = Util.getUsedMemory(); + } + PointsToComputer computer = new PointsToComputer(queriedPk); + passed = doTopLevelTraversal(queriedPk, ikeyPred, computer, pa); + // System.err.println("completed pass"); + if (DEBUG) { + System.err.println("traversed " + getNumNodesTraversed() + " nodes"); + } + completedPassInBudget = true; + completedSomePass = true; + break; + } catch (StatesMergedException e) { + if (DEBUG) { + System.err.println("restarting..."); + } + } finally { + if (MEASURE_MEMORY_USAGE) { + long memoryAfterPass = Util.getUsedMemory(); + assert initialMemory != 0; + long usedByPass = memoryAfterPass - initialMemory; + if (usedByPass > lastQueryMemoryUse) { + lastQueryMemoryUse = usedByPass; + if (usedByPass > 20000000) { + System.err.println("DOH!"); + System.exit(1); + } + } + } + + } + } + } catch (BudgetExceededException e) { + + } + if (completedPassInBudget) { + if (passed) { + succeeded = true; + break; + } + } + // if we get here, means either budget for pass was exceeded, + // or points-to set wasn't good enough + // so, start new pass, if more refinement to do + if (!refinementPolicy.nextPass()) { + break; + } + } + PointsToResult result = null; + if (succeeded) { + result = PointsToResult.SUCCESS; + } else if (passNum == numPasses) { + // we ran all the passes without succeeding and + // without the refinement policy giving up + result = PointsToResult.BUDGETEXCEEDED; + } else { + result = completedSomePass ? PointsToResult.NOMOREREFINE : PointsToResult.BUDGETEXCEEDED; + } + if (MEASURE_MEMORY_USAGE) { + System.err.println("memory " + lastQueryMemoryUse); + } + return result; + } + + /** + * do all instance keys in p2set pass ikeyPred? + */ + private boolean passesPred(Collection curP2Set, final Predicate ikeyPred) { + return Util.forAll(curP2Set, new Predicate() { + + @Override + public boolean test(InstanceKeyAndState t) { + return ikeyPred.test(t.getInstanceKey()); + } + }); + } + + /** + * @return the points-to set of pk, or null if the points-to set can't be computed in the allocated + * budget + */ + public Collection getPointsTo(PointerKey pk) { + return getPointsTo(pk, Predicate. falsePred()).snd; + } + + /** + * @return the points-to set of pk, including the {@link State}s attached to the {@link InstanceKey}s, or + * null if the points-to set can't be computed in the allocated budget + */ + public Collection getPointsToWithStates(PointerKey pk) { + return getPointsToWithStates(pk, Predicate. falsePred()).snd; + } + + /** + * get all the pointer keys that some instance key can flow to + * + * @return a pair consisting of (1) a {@link PointsToResult} indicating whether a flows-to set was computed, and (2) the last + * computed flows-to set for the instance key (possibly null if no flows-to set could be computed in the + * budget) + */ + public Pair> getFlowsTo(InstanceKey ik) { + startNewQuery(); + return getFlowsToInternal(new InstanceKeyAndState(ik, stateMachine.getStartState())); + } + + /** + * get all the pointer keys that some instance key with state can flow to + * + * @return a pair consisting of (1) a {@link PointsToResult} indicating whether a flows-to set was computed, and (2) the last + * computed flows-to set for the instance key (possibly null if no flows-to set could be computed in the + * budget) + */ + public Pair> getFlowsTo(InstanceKeyAndState ikAndState) { + startNewQuery(); + return getFlowsToInternal(ikAndState); + } + + /** + * @param ik + * @return + */ + private Pair> getFlowsToInternal(InstanceKeyAndState ikAndState) { + InstanceKey ik = ikAndState.getInstanceKey(); + if (!(ik instanceof InstanceKeyWithNode)) { + assert false : "TODO: handle " + ik.getClass(); + } + if (DEBUG) { + System.err.println("answering flows-to query for " + ikAndState); + } + Collection lastFlowsToSet = null; + boolean succeeded = false; + int numPasses = refinementPolicy.getNumPasses(); + int passNum = 0; + for (; passNum < numPasses; passNum++) { + setNumNodesTraversed(0); + setTraversalBudget(refinementPolicy.getBudgetForPass(passNum)); + Collection curFlowsToSet = null; + FlowsToComputer computer = null; + try { + while (true) { + try { + computer = new FlowsToComputer(ikAndState); + computer.compute(); + curFlowsToSet = computer.getComputedFlowsToSet(); + // System.err.println("completed pass"); + if (DEBUG) { + System.err.println("traversed " + getNumNodesTraversed() + " nodes"); + System.err.println("FLOWS-TO SET " + curFlowsToSet); + } + break; + } catch (StatesMergedException e) { + if (DEBUG) { + System.err.println("restarting..."); + } + } + } + } catch (BudgetExceededException e) { + + } + if (curFlowsToSet != null) { + if (lastFlowsToSet == null) { + lastFlowsToSet = curFlowsToSet; + } else if (lastFlowsToSet.size() > curFlowsToSet.size()) { + // got a more precise set + assert removeStates(lastFlowsToSet).containsAll(removeStates(curFlowsToSet)); + lastFlowsToSet = curFlowsToSet; + } else { + // new set size is >= lastP2Set, so don't update + // TODO what is wrong with this assertion?!? --MS + // assert removeStates(curFlowsToSet).containsAll(removeStates(lastFlowsToSet)); + } + // TODO add predicate support + if (curFlowsToSet.isEmpty() /* || passesPred(curFlowsToSet, ikeyPred) */) { + succeeded = true; + break; + } + } + // if we get here, means either budget for pass was exceeded, + // or points-to set wasn't good enough + // so, start new pass, if more refinement to do + if (!refinementPolicy.nextPass()) { + break; + } + } + PointsToResult result = null; + if (succeeded) { + result = PointsToResult.SUCCESS; + } else if (passNum == numPasses) { + // we ran all the passes without succeeding and + // without the refinement policy giving up + result = PointsToResult.BUDGETEXCEEDED; + } else { + if (lastFlowsToSet != null) { + result = PointsToResult.NOMOREREFINE; + } else { + // we stopped before the maximum number of passes, but we never + // actually finished a pass, so we count this as BUDGETEXCEEDED + result = PointsToResult.BUDGETEXCEEDED; + } + } + return Pair.make(result, lastFlowsToSet == null ? null : removeStates(lastFlowsToSet)); + } + + /** + * Closure indicating how to handle copies between {@link PointerKey}s. + * + * @author Manu Sridharan + * + */ + private static abstract class CopyHandler { + + abstract void handle(PointerKeyAndState src, PointerKey dst, IFlowLabel label); + } + + /** + * Representation of a statement storing a value into a field. + * + * @author Manu Sridharan + * + */ + private static final class StoreEdge { + // + // Represents statement of the form base.field = val + + final PointerKeyAndState base; + + final IField field; + + final PointerKeyAndState val; + + @Override + public int hashCode() { + final int PRIME = 31; + int result = 1; + result = PRIME * result + val.hashCode(); + result = PRIME * result + field.hashCode(); + result = PRIME * result + base.hashCode(); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + final StoreEdge other = (StoreEdge) obj; + if (!val.equals(other.val)) + return false; + if (!field.equals(other.field)) + return false; + if (!base.equals(other.base)) + return false; + return true; + } + + public StoreEdge(final PointerKeyAndState base, final IField field, final PointerKeyAndState val) { + this.base = base; + this.field = field; + this.val = val; + } + + } + + /** + * Representation of a field read. + * + * @author Manu Sridharan + * + */ + private static final class LoadEdge { + // Represents statements of the form val = base.field + final PointerKeyAndState base; + + final IField field; + + final PointerKeyAndState val; + + @Override + public String toString() { + return val + " := " + base + ", field " + field; + } + + @Override + public int hashCode() { + final int PRIME = 31; + int result = 1; + result = PRIME * result + val.hashCode(); + result = PRIME * result + field.hashCode(); + result = PRIME * result + base.hashCode(); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + final LoadEdge other = (LoadEdge) obj; + if (!val.equals(other.val)) + return false; + if (!field.equals(other.field)) + return false; + if (!base.equals(other.base)) + return false; + return true; + } + + public LoadEdge(final PointerKeyAndState base, final IField field, final PointerKeyAndState val) { + this.base = base; + this.field = field; + this.val = val; + } + + } + + /** + * Points-to analysis algorithm code. + * + * Pseudocode in Chapter 5 of Manu Sridharan's dissertation. + * + * @author Manu Sridharan + * + */ + protected class PointsToComputer { + + protected final PointerKeyAndState queriedPkAndState; + + /** + * map from pointer key to states in which the key's points-to set was queried + */ + private final MultiMap pointsToQueried = HashSetMultiMap.make(); + + /** + * map from pointer key to states in which a tracked points-to set for the key was computed + */ + private final MultiMap trackedQueried = HashSetMultiMap.make(); + + /** + * forward worklist: for initially processing points-to queries + */ + private final Collection initWorklist = new LinkedHashSet(); + + /** + * worklist for variables whose points-to set has been updated + */ + private final Collection pointsToWorklist = new LinkedHashSet(); + + /** + * worklist for variables whose tracked points-to set has been updated + */ + private final Collection trackedPointsToWorklist = new LinkedHashSet(); + + /** + * maps a pointer key to those on-the-fly virtual calls for which it is the receiver + */ + private final MultiMap pkToOTFCalls = HashSetMultiMap.make(); + + /** + * cache of the targets discovered for a call site during on-the-fly call graph construction + */ + private final MultiMap callToOTFTargets = ArraySetMultiMap.make(); + + // alloc nodes to the fields we're looking to match on them, + // matching getfield with putfield + private final MultiMap forwInstKeyToFields = HashSetMultiMap.make(); + + // matching putfield_bar with getfield_bar + private final MultiMap backInstKeyToFields = HashSetMultiMap.make(); + + // points-to sets and tracked points-to sets + protected final Map pkToP2Set = HashMapFactory.make(); + + protected final Map pkToTrackedSet = HashMapFactory.make(); + + private final Map instFieldKeyToP2Set = HashMapFactory.make(); + + private final Map instFieldKeyToTrackedSet = HashMapFactory.make(); + + /** + * for numbering {@link InstanceKey}, {@link State} pairs + */ + protected final OrdinalSetMapping ikAndStates = MutableMapping.make(); + + private final MutableIntSetFactory intSetFactory = new MutableSparseIntSetFactory(); // new + + // BitVectorIntSetFactory(); + + /** + * tracks all field stores encountered during traversal + */ + private final HashSet encounteredStores = HashSetFactory.make(); + + /** + * tracks all field loads encountered during traversal + */ + private final HashSet encounteredLoads = HashSetFactory.make(); + + /** + * use this with care! only for subclasses that aren't computing points-to information exactly (e.g., {@link FlowsToComputer}) + */ + protected PointsToComputer() { + queriedPkAndState = null; + } + + protected PointsToComputer(PointerKey pk) { + queriedPkAndState = new PointerKeyAndState(pk, stateMachine.getStartState()); + } + + protected PointsToComputer(PointerKeyAndState pkAndState) { + this.queriedPkAndState = pkAndState; + } + + private OrdinalSet makeOrdinalSet(IntSet intSet) { + // make a copy here, to avoid comodification during iteration + // TODO remove the copying, do it only at necessary call sites + return new OrdinalSet(intSetFactory.makeCopy(intSet), ikAndStates); + } + + /** + * get a points-to set that has already been computed via some previous call to {@link #compute()}; does _not_ do any fresh + * demand-driven computation. + */ + public Collection getComputedP2Set(PointerKeyAndState queried) { + return Iterator2Collection.toSet(makeOrdinalSet(find(pkToP2Set, queried)).iterator()); + // return Iterator2Collection.toSet(new MapIterator(makeOrdinalSet( + // find(pkToP2Set, new PointerKeyAndState(lpk, stateMachine.getStartState()))).iterator(), + // new Function() { + // + // public InstanceKey apply(InstanceKeyAndState object) { + // return object.getInstanceKey(); + // } + // + // })); + } + + protected boolean addAllToP2Set(Map p2setMap, PointerKeyAndState pkAndState, IntSet vals, + IFlowLabel label) { + final PointerKey pk = pkAndState.getPointerKey(); + if (pk instanceof FilteredPointerKey) { + if (DEBUG) { + System.err.println("handling filtered pointer key " + pk); + } + final TypeFilter typeFilter = ((FilteredPointerKey) pk).getTypeFilter(); + vals = updateValsForFilter(vals, typeFilter); + } + if (label instanceof IFlowLabelWithFilter) { + TypeFilter typeFilter = ((IFlowLabelWithFilter) label).getFilter(); + if (typeFilter != null) { + vals = updateValsForFilter(vals, typeFilter); + } + } + boolean added = findOrCreate(p2setMap, pkAndState).addAll(vals); + // final boolean added = p2setMap.putAll(pkAndState, vals); + if (DEBUG && added) { + System.err.println("POINTS-TO ADDITION TO PK " + pkAndState + ":"); + for (InstanceKeyAndState ikAndState : makeOrdinalSet(vals)) { + System.err.println(ikAndState); + } + System.err.println("*************"); + } + return added; + + } + + private IntSet updateValsForFilter(IntSet vals, final TypeFilter typeFilter) { + if (typeFilter instanceof SingleClassFilter) { + final IClass concreteType = ((SingleClassFilter) typeFilter).getConcreteType(); + final MutableIntSet tmp = intSetFactory.make(); + vals.foreach(new IntSetAction() { + + public void act(int x) { + InstanceKeyAndState ikAndState = ikAndStates.getMappedObject(x); + if (cha.isAssignableFrom(concreteType, ikAndState.getInstanceKey().getConcreteType())) { + tmp.add(x); + } + } + + }); + vals = tmp; + } else if (typeFilter instanceof MultipleClassesFilter) { + final MutableIntSet tmp = intSetFactory.make(); + vals.foreach(new IntSetAction() { + + public void act(int x) { + InstanceKeyAndState ikAndState = ikAndStates.getMappedObject(x); + for (IClass t : ((MultipleClassesFilter) typeFilter).getConcreteTypes()) { + if (cha.isAssignableFrom(t, ikAndState.getInstanceKey().getConcreteType())) { + tmp.add(x); + } + } + } + + }); + vals = tmp; + } else if (typeFilter instanceof SingleInstanceFilter) { + final InstanceKey theOnlyInstanceKey = ((SingleInstanceFilter) typeFilter).getInstance(); + final MutableIntSet tmp = intSetFactory.make(); + vals.foreach(new IntSetAction() { + + public void act(int x) { + InstanceKeyAndState ikAndState = ikAndStates.getMappedObject(x); + if (ikAndState.getInstanceKey().equals(theOnlyInstanceKey)) { + tmp.add(x); + } + } + + }); + vals = tmp; + } else { + Assertions.UNREACHABLE(); + } + return vals; + } + + protected void compute() { + final CGNode node = ((LocalPointerKey) queriedPkAndState.getPointerKey()).getNode(); + if (hasNullIR(node)) { + return; + } + g.addSubgraphForNode(node); + addToInitWorklist(queriedPkAndState); + worklistLoop(); + } + + protected void worklistLoop() { + do { + while (!initWorklist.isEmpty() || !pointsToWorklist.isEmpty() || !trackedPointsToWorklist.isEmpty()) { + handleInitWorklist(); + handlePointsToWorklist(); + handleTrackedPointsToWorklist(); + } + makePassOverFieldStmts(); + } while (!initWorklist.isEmpty() || !pointsToWorklist.isEmpty() || !trackedPointsToWorklist.isEmpty()); + } + + void handleCopy(final PointerKeyAndState curPkAndState, final PointerKey succPk, final IFlowLabel label) { + assert !label.isBarred(); + State curState = curPkAndState.getState(); + doTransition(curState, label, new Function() { + + public Object apply(State nextState) { + PointerKeyAndState succPkAndState = new PointerKeyAndState(succPk, nextState); + handleCopy(curPkAndState, succPkAndState, label); + return null; + } + + }); + } + + void handleCopy(PointerKeyAndState curPkAndState, PointerKeyAndState succPkAndState, IFlowLabel label) { + if (!addToInitWorklist(succPkAndState)) { + // handle like x = y with Y updated + if (addAllToP2Set(pkToP2Set, curPkAndState, find(pkToP2Set, succPkAndState), label)) { + addToPToWorklist(curPkAndState); + } + } + + } + + void handleAllCopies(PointerKeyAndState curPk, Iterator succNodes, IFlowLabel label) { + while (succNodes.hasNext()) { + handleCopy(curPk, (PointerKey) succNodes.next(), label); + } + } + + /** + * @param label the label of the edge from curPk to predPk (must be barred) + * @return those {@link PointerKeyAndState}s whose points-to sets have been queried, such that the {@link PointerKey} is predPk, + * and transitioning from its state on label.bar() yields the state of curPkAndState + */ + protected Collection matchingPToQueried(PointerKeyAndState curPkAndState, PointerKey predPk, + IFlowLabel label) { + Collection ret = ArraySet.make(); + assert label.isBarred(); + IFlowLabel unbarredLabel = label.bar(); + final State curState = curPkAndState.getState(); + Set predPkStates = pointsToQueried.get(predPk); + for (State predState : predPkStates) { + State transState = stateMachine.transition(predState, unbarredLabel); + if (transState.equals(curState)) { + // we have a winner! + ret.add(new PointerKeyAndState(predPk, predState)); + } + } + return ret; + } + + Collection matchingTrackedQueried(PointerKeyAndState curPkAndState, PointerKey succPk, IFlowLabel label) { + Collection ret = ArraySet.make(); + assert label.isBarred(); + final State curState = curPkAndState.getState(); + Set succPkStates = trackedQueried.get(succPk); + for (State succState : succPkStates) { + State transState = stateMachine.transition(succState, label); + if (transState.equals(curState)) { + ret.add(new PointerKeyAndState(succPk, succState)); + } + } + return ret; + } + + protected void handleBackCopy(PointerKeyAndState curPkAndState, PointerKey predPk, IFlowLabel label) { + for (PointerKeyAndState predPkAndState : matchingPToQueried(curPkAndState, predPk, label)) { + if (addAllToP2Set(pkToP2Set, predPkAndState, find(pkToP2Set, curPkAndState), label)) { + addToPToWorklist(predPkAndState); + } + } + } + + void handleAllBackCopies(PointerKeyAndState curPkAndState, Iterator predNodes, IFlowLabel label) { + while (predNodes.hasNext()) { + handleBackCopy(curPkAndState, (PointerKey) predNodes.next(), label); + } + } + + /** + * should only be called when pk's points-to set has just been updated. add pk to the points-to worklist, and re-propagate and + * calls that had pk as the receiver. + */ + void addToPToWorklist(PointerKeyAndState pkAndState) { + pointsToWorklist.add(pkAndState); + Set otfCalls = pkToOTFCalls.get(pkAndState); + for (CallerSiteContext callSiteAndCGNode : otfCalls) { + propTargets(pkAndState, callSiteAndCGNode); + } + } + + boolean addToInitWorklist(PointerKeyAndState pkAndState) { + if (pointsToQueried.put(pkAndState.getPointerKey(), pkAndState.getState())) { + if (pkAndState.getPointerKey() instanceof AbstractLocalPointerKey) { + CGNode node = ((AbstractLocalPointerKey) pkAndState.getPointerKey()).getNode(); + if (!g.hasSubgraphForNode(node)) { + assert false : "missing constraints for " + node; + } + } + if (DEBUG) { + // System.err.println("adding to init_ " + pkAndState); + } + initWorklist.add(pkAndState); + // if (pkAndStates.getMappedIndex(pkAndState) == -1) { + // pkAndStates.add(pkAndState); + // } + return true; + } + return false; + } + + protected void addToTrackedPToWorklist(PointerKeyAndState pkAndState) { + if (pkAndState.getPointerKey() instanceof AbstractLocalPointerKey) { + CGNode node = ((AbstractLocalPointerKey) pkAndState.getPointerKey()).getNode(); + if (!g.hasSubgraphForNode(node)) { + assert false : "missing constraints for " + node; + } + } + if (DEBUG) { + // System.err.println("adding to tracked points-to " + pkAndState); + } + trackedQueried.put(pkAndState.getPointerKey(), pkAndState.getState()); + trackedPointsToWorklist.add(pkAndState); + } + + /** + * Adds new targets for a virtual call, based on the points-to set of the receiver, and propagates values for the parameters / + * return value of the new targets. NOTE: this method will not do any propagation for virtual call targets that have + * already been discovered. + * + * @param receiverAndState the receiver + * @param callSiteAndCGNode the call + */ + void propTargets(PointerKeyAndState receiverAndState, CallerSiteContext callSiteAndCGNode) { + final CGNode caller = callSiteAndCGNode.getCaller(); + CallSiteReference call = callSiteAndCGNode.getCallSite(); + final State receiverState = receiverAndState.getState(); + OrdinalSet p2set = makeOrdinalSet(find(pkToP2Set, receiverAndState)); + for (InstanceKeyAndState ikAndState : p2set) { + InstanceKey ik = ikAndState.getInstanceKey(); + IMethod targetMethod = options.getMethodTargetSelector().getCalleeTarget(caller, call, ik.getConcreteType()); + if (targetMethod == null) { + // NOTE: target method can be null because we don't + // always have type filters + continue; + } + // if we've already handled this target, we can stop + if (callToOTFTargets.get(callSiteAndCGNode).contains(targetMethod)) { + continue; + } + callToOTFTargets.put(callSiteAndCGNode, targetMethod); + // TODO can we just pick one of these, rather than all of them? + // TODO handle clone() properly + Set targetCGNodes = cg.getNodes(targetMethod.getReference()); + for (final CGNode targetForCall : targetCGNodes) { + if (DEBUG) { + System.err.println("adding target " + targetForCall + " for call " + call); + } + if (hasNullIR(targetForCall)) { + continue; + } + g.addSubgraphForNode(targetForCall); + // need to check flows through parameters and returns, + // in direction of value flow and reverse + SSAAbstractInvokeInstruction[] calls = getCallInstrs(caller, call); + for (final SSAAbstractInvokeInstruction invokeInstr : calls) { + final ReturnLabel returnLabel = ReturnLabel.make(new CallerSiteContext(caller, call)); + if (invokeInstr.hasDef()) { + final PointerKeyAndState defAndState = new PointerKeyAndState(heapModel.getPointerKeyForLocal(caller, invokeInstr + .getDef()), receiverState); + final PointerKey ret = heapModel.getPointerKeyForReturnValue(targetForCall); + doTransition(receiverState, returnLabel, new Function() { + + public Object apply(State retState) { + repropCallArg(defAndState, new PointerKeyAndState(ret, retState), returnLabel.bar()); + return null; + } + + }); + } + final PointerKeyAndState exc = new PointerKeyAndState(heapModel.getPointerKeyForLocal(caller, invokeInstr + .getException()), receiverState); + final PointerKey excRet = heapModel.getPointerKeyForExceptionalReturnValue(targetForCall); + doTransition(receiverState, returnLabel, new Function() { + + public Object apply(State excRetState) { + repropCallArg(exc, new PointerKeyAndState(excRet, excRetState), returnLabel.bar()); + return null; + } + + }); + for (Iterator iter = new PointerParamValueNumIterator(targetForCall); iter.hasNext();) { + final int formalNum = iter.next(); + final int actualNum = formalNum - 1; + final ParamBarLabel paramBarLabel = ParamBarLabel.make(new CallerSiteContext(caller, call)); + doTransition(receiverState, paramBarLabel, new Function() { + + public Object apply(State formalState) { + repropCallArg( + new PointerKeyAndState(heapModel.getPointerKeyForLocal(targetForCall, formalNum), formalState), + new PointerKeyAndState(heapModel.getPointerKeyForLocal(caller, invokeInstr.getUse(actualNum)), receiverState), + paramBarLabel); + return null; + } + + }); + } + } + } + } + } + + /** + * handle possible updated flow in both directions for a call parameter + * + * @param src + * @param dst + */ + private void repropCallArg(PointerKeyAndState src, PointerKeyAndState dst, IFlowLabel dstToSrcLabel) { + if (DEBUG) { + // System.err.println("re-propping from src " + src + " to dst " + dst); + } + for (PointerKeyAndState srcToHandle : matchingPToQueried(dst, src.getPointerKey(), dstToSrcLabel)) { + handleCopy(srcToHandle, dst, dstToSrcLabel.bar()); + } + for (PointerKeyAndState dstToHandle : matchingTrackedQueried(src, dst.getPointerKey(), dstToSrcLabel)) { + IntSet trackedSet = find(pkToTrackedSet, dstToHandle); + if (!trackedSet.isEmpty()) { + if (findOrCreate(pkToTrackedSet, src).addAll(trackedSet)) { + addToTrackedPToWorklist(src); + } + } + } + } + + void handleInitWorklist() { + while (!initWorklist.isEmpty()) { + incrementNumNodesTraversed(); + final PointerKeyAndState curPkAndState = initWorklist.iterator().next(); + initWorklist.remove(curPkAndState); + final PointerKey curPk = curPkAndState.getPointerKey(); + final State curState = curPkAndState.getState(); + if (DEBUG) + System.err.println("init " + curPkAndState); + if (curPk instanceof LocalPointerKey) { + assert g.hasSubgraphForNode(((LocalPointerKey) curPk).getNode()); + } + // if (curPk instanceof LocalPointerKey) { + // Collection constantVals = + // getConstantVals((LocalPointerKey) curPk); + // if (constantVals != null) { + // for (InstanceKey ik : constantVals) { + // pkToP2Set.put(curPk, ik); + // addToPToWorklist(curPk); + // } + // } + // } + IFlowLabelVisitor v = new AbstractFlowLabelVisitor() { + + @Override + public void visitNew(NewLabel label, Object dst) { + final InstanceKey ik = (InstanceKey) dst; + if (DEBUG) { + System.err.println("alloc " + ik + " assigned to " + curPk); + } + doTransition(curState, label, new Function() { + + public Object apply(State newState) { + InstanceKeyAndState ikAndState = new InstanceKeyAndState(ik, newState); + int n = ikAndStates.add(ikAndState); + findOrCreate(pkToP2Set, curPkAndState).add(n); + addToPToWorklist(curPkAndState); + return null; + } + + }); + } + + @Override + public void visitGetField(GetFieldLabel label, Object dst) { + IField field = (label).getField(); + PointerKey loadBase = (PointerKey) dst; + if (refineFieldAccesses(field, loadBase, curPk, label, curState)) { + // if (Assertions.verifyAssertions) { + // Assertions._assert(stateMachine.transition(curState, label) == + // curState); + // } + PointerKeyAndState loadBaseAndState = new PointerKeyAndState(loadBase, curState); + addEncounteredLoad(new LoadEdge(loadBaseAndState, field, curPkAndState)); + if (!addToInitWorklist(loadBaseAndState)) { + // handle like x = y.f, with Y updated + for (InstanceKeyAndState ikAndState : makeOrdinalSet(find(pkToP2Set, loadBaseAndState))) { + trackInstanceField(ikAndState, field, forwInstKeyToFields); + } + } + } else { + handleAllCopies(curPkAndState, g.getWritesToInstanceField(loadBase, field), MatchLabel.v()); + } + } + + @Override + public void visitAssignGlobal(AssignGlobalLabel label, Object dst) { + handleAllCopies(curPkAndState, g.getWritesToStaticField((StaticFieldKey) dst), AssignGlobalLabel.v()); + } + + @Override + public void visitAssign(AssignLabel label, Object dst) { + handleCopy(curPkAndState, (PointerKey) dst, AssignLabel.noFilter()); + } + + }; + g.visitSuccs(curPk, v); + // interprocedural edges + handleForwInterproc(curPkAndState, new CopyHandler() { + + @Override + void handle(PointerKeyAndState src, PointerKey dst, IFlowLabel label) { + handleCopy(src, dst, label); + } + + }); + } + + } + + /** + * handle flow from actuals to formals, and from returned values to variables at the caller + * + * @param curPk + * @param handler + */ + private void handleForwInterproc(final PointerKeyAndState curPkAndState, final CopyHandler handler) { + PointerKey curPk = curPkAndState.getPointerKey(); + if (curPk instanceof LocalPointerKey) { + final LocalPointerKey localPk = (LocalPointerKey) curPk; + if (g.isParam(localPk)) { + // System.err.println("at param"); + final CGNode callee = localPk.getNode(); + final int paramPos = localPk.getValueNumber() - 1; + for (final CallerSiteContext callSiteAndCGNode : g.getPotentialCallers(localPk)) { + final CGNode caller = callSiteAndCGNode.getCaller(); + final CallSiteReference call = callSiteAndCGNode.getCallSite(); + // final IR ir = getIR(caller); + if (hasNullIR(caller)) + continue; + final ParamLabel paramLabel = ParamLabel.make(callSiteAndCGNode); + doTransition(curPkAndState.getState(), paramLabel, new Function() { + + private void propagateToCallee() { + // if (caller.getIR() == null) { + // return; + // } + g.addSubgraphForNode(caller); + SSAAbstractInvokeInstruction[] callInstrs = getCallInstrs(caller, call); + for (int i = 0; i < callInstrs.length; i++) { + SSAAbstractInvokeInstruction callInstr = callInstrs[i]; + PointerKey actualPk = heapModel.getPointerKeyForLocal(caller, callInstr.getUse(paramPos)); + assert g.containsNode(actualPk); + assert g.containsNode(localPk); + handler.handle(curPkAndState, actualPk, paramLabel); + } + } + + public Object apply(State callerState) { + // hack to get some actual parameter from call site + // TODO do this better + SSAAbstractInvokeInstruction[] callInstrs = getCallInstrs(caller, call); + SSAAbstractInvokeInstruction callInstr = callInstrs[0]; + PointerKey actualPk = heapModel.getPointerKeyForLocal(caller, callInstr.getUse(paramPos)); + Set possibleTargets = g.getPossibleTargets(caller, call, (LocalPointerKey) actualPk); + if (noOnTheFlyNeeded(callSiteAndCGNode, possibleTargets)) { + propagateToCallee(); + } else { + if (callToOTFTargets.get(callSiteAndCGNode).contains(callee.getMethod())) { + // already found this target as valid, so do propagation + propagateToCallee(); + } else { + // if necessary, start a query for the call site + queryCallTargets(callSiteAndCGNode, callInstrs, callerState); + } + } + return null; + } + + }); + + } + } + SSAInvokeInstruction callInstr = g.getInstrReturningTo(localPk); + if (callInstr != null) { + CGNode caller = localPk.getNode(); + boolean isExceptional = localPk.getValueNumber() == callInstr.getException(); + + CallSiteReference callSiteRef = callInstr.getCallSite(); + CallerSiteContext callSiteAndCGNode = new CallerSiteContext(caller, callSiteRef); + // get call targets + Set possibleCallees = g.getPossibleTargets(caller, callSiteRef, localPk); + + // cg.getPossibleTargets(caller, callSiteRef); + // if (DEBUG && + // callSiteRef.getDeclaredTarget().toString().indexOf("clone()") != + // -1) { + // System.err.println(possibleCallees); + // System.err.println(Iterator2Collection.toCollection(cg.getSuccNodes(caller))); + // System.err.println(Iterator2Collection.toCollection(cg.getPredNodes(possibleCallees.iterator().next()))); + // } + // construct graph for each target + if (noOnTheFlyNeeded(callSiteAndCGNode, possibleCallees)) { + for (CGNode callee : possibleCallees) { + if (hasNullIR(callee)) { + continue; + } + g.addSubgraphForNode(callee); + PointerKey retVal = isExceptional ? heapModel.getPointerKeyForExceptionalReturnValue(callee) : heapModel + .getPointerKeyForReturnValue(callee); + assert g.containsNode(retVal); + handler.handle(curPkAndState, retVal, ReturnLabel.make(callSiteAndCGNode)); + } + } else { + if (callToOTFTargets.containsKey(callSiteAndCGNode)) { + // already queried this call site + // handle existing targets + Set targetMethods = callToOTFTargets.get(callSiteAndCGNode); + for (CGNode callee : possibleCallees) { + if (targetMethods.contains(callee.getMethod())) { + if (hasNullIR(callee)) { + continue; + } + g.addSubgraphForNode(callee); + PointerKey retVal = isExceptional ? heapModel.getPointerKeyForExceptionalReturnValue(callee) : heapModel + .getPointerKeyForReturnValue(callee); + assert g.containsNode(retVal); + handler.handle(curPkAndState, retVal, ReturnLabel.make(callSiteAndCGNode)); + } + } + } else { + // if necessary, raise a query for the call site + queryCallTargets(callSiteAndCGNode, getCallInstrs(caller, callSiteAndCGNode.getCallSite()), curPkAndState.getState()); + } + } + } + } + } + + /** + * track a field of some instance key, as we are interested in statements that read or write to the field + * + * @param ikAndState + * @param field + * @param ikToFields either {@link #forwInstKeyToFields} or {@link #backInstKeyToFields} + */ + private void trackInstanceField(InstanceKeyAndState ikAndState, IField field, MultiMap ikToFields) { + ikToFields.put(ikAndState, field); + addPredsOfIKeyAndStateToTrackedPointsTo(ikAndState); + } + + private void addPredsOfIKeyAndStateToTrackedPointsTo(InstanceKeyAndState ikAndState) throws UnimplementedError { + for (Iterator iter = g.getPredNodes(ikAndState.getInstanceKey(), NewLabel.v()); iter.hasNext();) { + PointerKey ikPred = (PointerKey) iter.next(); + PointerKeyAndState ikPredAndState = new PointerKeyAndState(ikPred, ikAndState.getState()); + int mappedIndex = ikAndStates.getMappedIndex(ikAndState); + assert mappedIndex != -1; + if (findOrCreate(pkToTrackedSet, ikPredAndState).add(mappedIndex)) { + addToTrackedPToWorklist(ikPredAndState); + } + } + } + + /** + * Initiates a query for the targets of some virtual call, by asking for points-to set of receiver. NOTE: if receiver has + * already been queried, will not do any additional propagation for already-discovered virtual call targets + */ + private void queryCallTargets(CallerSiteContext callSiteAndCGNode, SSAAbstractInvokeInstruction[] callInstrs, State callerState) { + final CGNode caller = callSiteAndCGNode.getCaller(); + for (SSAAbstractInvokeInstruction callInstr : callInstrs) { + PointerKey thisArg = heapModel.getPointerKeyForLocal(caller, callInstr.getUse(0)); + PointerKeyAndState thisArgAndState = new PointerKeyAndState(thisArg, callerState); + if (pkToOTFCalls.put(thisArgAndState, callSiteAndCGNode)) { + // added the call target + final CGNode node = ((LocalPointerKey) thisArg).getNode(); + if (hasNullIR(node)) { + return; + } + g.addSubgraphForNode(node); + if (!addToInitWorklist(thisArgAndState)) { + // need to handle pk's current values for call + propTargets(thisArgAndState, callSiteAndCGNode); + } else { + if (DEBUG) { + final CallSiteReference call = callSiteAndCGNode.getCallSite(); + System.err.println("querying for targets of call " + call + " in " + caller); + } + } + } else { + // TODO: I think we can remove this call + propTargets(thisArgAndState, callSiteAndCGNode); + } + } + } + + void handlePointsToWorklist() { + while (!pointsToWorklist.isEmpty()) { + incrementNumNodesTraversed(); + final PointerKeyAndState curPkAndState = pointsToWorklist.iterator().next(); + pointsToWorklist.remove(curPkAndState); + final PointerKey curPk = curPkAndState.getPointerKey(); + final State curState = curPkAndState.getState(); + if (DEBUG) { + System.err.println("points-to " + curPkAndState); + System.err.println("***pto-set " + find(pkToP2Set, curPkAndState) + "***"); + } + IFlowLabelVisitor predVisitor = new AbstractFlowLabelVisitor() { + + @Override + public void visitPutField(PutFieldLabel label, Object dst) { + IField field = label.getField(); + PointerKey storeBase = (PointerKey) dst; + if (refineFieldAccesses(field, storeBase, curPk, label, curState)) { + // statements x.f = y, Y updated (X' not empty required) + // update Z.f for all z in X' + PointerKeyAndState storeBaseAndState = new PointerKeyAndState(storeBase, curState); + encounteredStores.add(new StoreEdge(storeBaseAndState, field, curPkAndState)); + for (InstanceKeyAndState ikAndState : makeOrdinalSet(find(pkToTrackedSet, storeBaseAndState))) { + if (forwInstKeyToFields.get(ikAndState).contains(field)) { + InstanceFieldKeyAndState ifKeyAndState = getInstFieldKey(ikAndState, field); + findOrCreate(instFieldKeyToP2Set, ifKeyAndState).addAll(find(pkToP2Set, curPkAndState)); + + } + } + } else { + handleAllBackCopies(curPkAndState, g.getReadsOfInstanceField(storeBase, field), MatchBarLabel.v()); + } + } + + @Override + public void visitGetField(GetFieldLabel label, Object dst) { + IField field = (label).getField(); + PointerKey dstPtrKey = (PointerKey) dst; + if (refineFieldAccesses(field, curPk, dstPtrKey, label, curState)) { + // statements x = y.f, Y updated + // if X queried, start tracking Y.f + PointerKeyAndState loadDefAndState = new PointerKeyAndState(dstPtrKey, curState); + addEncounteredLoad(new LoadEdge(curPkAndState, field, loadDefAndState)); + if (pointsToQueried.get(dstPtrKey).contains(curState)) { + for (InstanceKeyAndState ikAndState : makeOrdinalSet(find(pkToP2Set, curPkAndState))) { + trackInstanceField(ikAndState, field, forwInstKeyToFields); + } + } + } + } + + @Override + public void visitAssignGlobal(AssignGlobalLabel label, Object dst) { + handleAllBackCopies(curPkAndState, g.getReadsOfStaticField((StaticFieldKey) dst), label.bar()); + } + + @Override + public void visitAssign(AssignLabel label, Object dst) { + handleBackCopy(curPkAndState, (PointerKey) dst, label.bar()); + } + + }; + g.visitPreds(curPk, predVisitor); + IFlowLabelVisitor succVisitor = new AbstractFlowLabelVisitor() { + + @Override + public void visitPutField(PutFieldLabel label, Object dst) { + IField field = (label).getField(); + PointerKey dstPtrKey = (PointerKey) dst; + // pass barred label since this is for tracked points-to sets + if (refineFieldAccesses(field, curPk, dstPtrKey, label.bar(), curState)) { + // x.f = y, X updated + // if Y' non-empty, then update + // tracked set of X.f, to trace flow + // to reads + PointerKeyAndState storeDst = new PointerKeyAndState(dstPtrKey, curState); + encounteredStores.add(new StoreEdge(curPkAndState, field, storeDst)); + IntSet trackedSet = find(pkToTrackedSet, storeDst); + if (!trackedSet.isEmpty()) { + for (InstanceKeyAndState ikAndState : makeOrdinalSet(find(pkToP2Set, curPkAndState))) { + InstanceFieldKeyAndState ifk = getInstFieldKey(ikAndState, field); + findOrCreate(instFieldKeyToTrackedSet, ifk).addAll(trackedSet); + trackInstanceField(ikAndState, field, backInstKeyToFields); + } + } + } + } + }; + g.visitSuccs(curPk, succVisitor); + handleBackInterproc(curPkAndState, new CopyHandler() { + + @Override + void handle(PointerKeyAndState src, PointerKey dst, IFlowLabel label) { + handleBackCopy(src, dst, label); + } + + }, false); + } + } + + /** + * handle flow from return value to callers, or from actual to formals + * + * @param curPkAndState + * @param handler + */ + private void handleBackInterproc(final PointerKeyAndState curPkAndState, final CopyHandler handler, final boolean addGraphs) { + final PointerKey curPk = curPkAndState.getPointerKey(); + final State curState = curPkAndState.getState(); + // interprocedural edges + if (curPk instanceof ReturnValueKey) { + final ReturnValueKey returnKey = (ReturnValueKey) curPk; + if (DEBUG) { + System.err.println("return value"); + } + final CGNode callee = returnKey.getNode(); + if (DEBUG) { + System.err.println("returning from " + callee); + // System.err.println("CALL GRAPH:\n" + cg); + // System.err.println(new + // Iterator2Collection(cg.getPredNodes(cgNode))); + } + final boolean isExceptional = returnKey instanceof ExceptionReturnValueKey; + // iterate over callers + for (final CallerSiteContext callSiteAndCGNode : g.getPotentialCallers(returnKey)) { + final CGNode caller = callSiteAndCGNode.getCaller(); + if (hasNullIR(caller)) + continue; + final CallSiteReference call = callSiteAndCGNode.getCallSite(); + if (calleeSubGraphMissingAndShouldNotBeAdded(addGraphs, callee, curPkAndState)) { + continue; + } + final ReturnBarLabel returnBarLabel = ReturnBarLabel.make(callSiteAndCGNode); + doTransition(curState, returnBarLabel, new Function() { + + private void propagateToCaller() { + // if (caller.getIR() == null) { + // return; + // } + g.addSubgraphForNode(caller); + SSAAbstractInvokeInstruction[] callInstrs = getCallInstrs(caller, call); + for (int i = 0; i < callInstrs.length; i++) { + SSAAbstractInvokeInstruction callInstr = callInstrs[i]; + PointerKey returnAtCallerKey = heapModel.getPointerKeyForLocal(caller, isExceptional ? callInstr.getException() + : callInstr.getDef()); + assert g.containsNode(returnAtCallerKey); + assert g.containsNode(returnKey); + handler.handle(curPkAndState, returnAtCallerKey, returnBarLabel); + } + } + + public Object apply(State callerState) { + // if (DEBUG) { + // System.err.println("caller " + caller); + // } + SSAAbstractInvokeInstruction[] callInstrs = getCallInstrs(caller, call); + SSAAbstractInvokeInstruction callInstr = callInstrs[0]; + PointerKey returnAtCallerKey = heapModel.getPointerKeyForLocal(caller, isExceptional ? callInstr.getException() + : callInstr.getDef()); + Set possibleTargets = g.getPossibleTargets(caller, call, (LocalPointerKey) returnAtCallerKey); + if (noOnTheFlyNeeded(callSiteAndCGNode, possibleTargets)) { + propagateToCaller(); + } else { + if (callToOTFTargets.get(callSiteAndCGNode).contains(callee.getMethod())) { + // already found this target as valid, so do propagation + propagateToCaller(); + } else { + // if necessary, start a query for the call site + queryCallTargets(callSiteAndCGNode, callInstrs, callerState); + } + } + return null; + } + + }); + } + } + if (curPk instanceof LocalPointerKey) { + LocalPointerKey localPk = (LocalPointerKey) curPk; + CGNode caller = localPk.getNode(); + // from actual parameter to callee + for (Iterator iter = g.getInstrsPassingParam(localPk); iter.hasNext();) { + SSAInvokeInstruction callInstr = iter.next(); + for (int i = 0; i < callInstr.getNumberOfUses(); i++) { + if (localPk.getValueNumber() != callInstr.getUse(i)) + continue; + CallSiteReference callSiteRef = callInstr.getCallSite(); + CallerSiteContext callSiteAndCGNode = new CallerSiteContext(caller, callSiteRef); + // get call targets + Set possibleCallees = g.getPossibleTargets(caller, callSiteRef, localPk); + // construct graph for each target + if (noOnTheFlyNeeded(callSiteAndCGNode, possibleCallees)) { + for (CGNode callee : possibleCallees) { + if (calleeSubGraphMissingAndShouldNotBeAdded(addGraphs, callee, curPkAndState)) { + continue; + } + if (hasNullIR(callee)) { + continue; + } + g.addSubgraphForNode(callee); + PointerKey paramVal = heapModel.getPointerKeyForLocal(callee, i + 1); + assert g.containsNode(paramVal); + handler.handle(curPkAndState, paramVal, ParamBarLabel.make(callSiteAndCGNode)); + } + } else { + if (callToOTFTargets.containsKey(callSiteAndCGNode)) { + // already queried this call site + // handle existing targets + Set targetMethods = callToOTFTargets.get(callSiteAndCGNode); + for (CGNode callee : possibleCallees) { + if (targetMethods.contains(callee.getMethod())) { + if (hasNullIR(callee)) { + continue; + } + g.addSubgraphForNode(callee); + PointerKey paramVal = heapModel.getPointerKeyForLocal(callee, i + 1); + assert g.containsNode(paramVal); + handler.handle(curPkAndState, paramVal, ParamBarLabel.make(callSiteAndCGNode)); + } + } + } else { + // if necessary, raise a query for the call site + queryCallTargets(callSiteAndCGNode, getCallInstrs(caller, callSiteAndCGNode.getCallSite()), curState); + } + } + } + } + } + } + + /** + * when doing backward interprocedural propagation, is it true that we should not add a graph representation for a callee _and_ + * that the subgraph for the callee is missing? + * + * @param addGraphs whether graphs should always be added + * @param callee + * @param pkAndState + * @return + */ + protected boolean calleeSubGraphMissingAndShouldNotBeAdded(boolean addGraphs, CGNode callee, PointerKeyAndState pkAndState) { + return !addGraphs && !g.hasSubgraphForNode(callee); + } + + public void handleTrackedPointsToWorklist() { + // if (Assertions.verifyAssertions) { + // Assertions._assert(trackedPointsToWorklist.isEmpty() || refineFields); + // } + while (!trackedPointsToWorklist.isEmpty()) { + incrementNumNodesTraversed(); + final PointerKeyAndState curPkAndState = trackedPointsToWorklist.iterator().next(); + trackedPointsToWorklist.remove(curPkAndState); + final PointerKey curPk = curPkAndState.getPointerKey(); + final State curState = curPkAndState.getState(); + if (DEBUG) + System.err.println("tracked points-to " + curPkAndState); + final MutableIntSet trackedSet = find(pkToTrackedSet, curPkAndState); + IFlowLabelVisitor succVisitor = new AbstractFlowLabelVisitor() { + + @Override + public void visitPutField(PutFieldLabel label, Object dst) { + // statements x.f = y, X' updated, f in map + // query y; if already queried, add Y to Z.f for all + // z in X' + IField field = label.getField(); + PointerKey dstPtrKey = (PointerKey) dst; + if (refineFieldAccesses(field, curPk, dstPtrKey, label, curState)) { + for (InstanceKeyAndState ikAndState : makeOrdinalSet(trackedSet)) { + boolean needField = forwInstKeyToFields.get(ikAndState).contains(field); + PointerKeyAndState storeDst = new PointerKeyAndState(dstPtrKey, curState); + encounteredStores.add(new StoreEdge(curPkAndState, field, storeDst)); + if (needField) { + if (!addToInitWorklist(storeDst)) { + InstanceFieldKeyAndState ifk = getInstFieldKey(ikAndState, field); + findOrCreate(instFieldKeyToP2Set, ifk).addAll(find(pkToP2Set, storeDst)); + } + } + } + } + } + }; + g.visitSuccs(curPk, succVisitor); + IFlowLabelVisitor predVisitor = new AbstractFlowLabelVisitor() { + + @Override + public void visitAssignGlobal(final AssignGlobalLabel label, Object dst) { + for (Iterator readIter = g.getReadsOfStaticField((StaticFieldKey) dst); readIter.hasNext();) { + final PointerKey predPk = (PointerKey) readIter.next(); + doTransition(curState, AssignGlobalBarLabel.v(), new Function() { + + public Object apply(State predPkState) { + PointerKeyAndState predPkAndState = new PointerKeyAndState(predPk, predPkState); + handleTrackedPred(trackedSet, predPkAndState, AssignGlobalBarLabel.v()); + return null; + } + + }); + } + } + + @Override + public void visitPutField(PutFieldLabel label, Object dst) { + IField field = label.getField(); + PointerKey storeBase = (PointerKey) dst; + // bar label since this is for tracked points-to sets + if (refineFieldAccesses(field, storeBase, curPk, label.bar(), curState)) { + PointerKeyAndState storeBaseAndState = new PointerKeyAndState(storeBase, curState); + encounteredStores.add(new StoreEdge(storeBaseAndState, field, curPkAndState)); + if (!addToInitWorklist(storeBaseAndState)) { + for (InstanceKeyAndState ikAndState : makeOrdinalSet(find(pkToP2Set, storeBaseAndState))) { + InstanceFieldKeyAndState ifk = getInstFieldKey(ikAndState, field); + findOrCreate(instFieldKeyToTrackedSet, ifk).addAll(trackedSet); + trackInstanceField(ikAndState, field, backInstKeyToFields); + } + } + } else { + // send to all getfield sources + for (Iterator readIter = g.getReadsOfInstanceField(storeBase, field); readIter.hasNext();) { + final PointerKey predPk = readIter.next(); + doTransition(curState, MatchBarLabel.v(), new Function() { + + public Object apply(State predPkState) { + PointerKeyAndState predPkAndState = new PointerKeyAndState(predPk, predPkState); + handleTrackedPred(trackedSet, predPkAndState, MatchBarLabel.v()); + return null; + } + + }); + } + + } + } + + @Override + public void visitGetField(GetFieldLabel label, Object dst) { + IField field = label.getField(); + PointerKey dstPtrKey = (PointerKey) dst; + // x = y.f, Y' updated + // bar label since this is for tracked points-to sets + if (refineFieldAccesses(field, curPk, dstPtrKey, label.bar(), curState)) { + for (InstanceKeyAndState ikAndState : makeOrdinalSet(trackedSet)) { + // tracking value written into ik.field + boolean needField = backInstKeyToFields.get(ikAndState).contains(field); + PointerKeyAndState loadedVal = new PointerKeyAndState(dstPtrKey, curState); + addEncounteredLoad(new LoadEdge(curPkAndState, field, loadedVal)); + if (needField) { + InstanceFieldKeyAndState ifk = getInstFieldKey(ikAndState, field); + // use an assign bar label with no filter here, since filtering only happens at casts + handleTrackedPred(find(instFieldKeyToTrackedSet, ifk), loadedVal, AssignBarLabel.noFilter()); + } + } + } + } + + @Override + public void visitAssign(final AssignLabel label, Object dst) { + final PointerKey predPk = (PointerKey) dst; + doTransition(curState, label.bar(), new Function() { + + public Object apply(State predPkState) { + PointerKeyAndState predPkAndState = new PointerKeyAndState(predPk, predPkState); + handleTrackedPred(trackedSet, predPkAndState, label.bar()); + return null; + } + + }); + } + + }; + g.visitPreds(curPk, predVisitor); + handleBackInterproc(curPkAndState, new CopyHandler() { + + @Override + void handle(PointerKeyAndState src, final PointerKey dst, final IFlowLabel label) { + assert src == curPkAndState; + doTransition(curState, label, new Function() { + public Object apply(State dstState) { + PointerKeyAndState dstAndState = new PointerKeyAndState(dst, dstState); + handleTrackedPred(trackedSet, dstAndState, label); + return null; + } + + }); + } + + }, true); + } + } + + private void addEncounteredLoad(LoadEdge loadEdge) { + if (encounteredLoads.add(loadEdge)) { + // if (DEBUG) { + // System.err.println("encountered load edge " + loadEdge); + // } + } + } + + public void makePassOverFieldStmts() { + for (StoreEdge storeEdge : encounteredStores) { + PointerKeyAndState storedValAndState = storeEdge.val; + IField field = storeEdge.field; + PointerKeyAndState baseAndState = storeEdge.base; + // x.f = y, X' updated + // for each z in X' such that f in z's map, + // add Y to Z.f + IntSet trackedSet = find(pkToTrackedSet, baseAndState); + for (InstanceKeyAndState ikAndState : makeOrdinalSet(trackedSet)) { + if (forwInstKeyToFields.get(ikAndState).contains(field)) { + if (!addToInitWorklist(storedValAndState)) { + InstanceFieldKeyAndState ifk = getInstFieldKey(ikAndState, field); + findOrCreate(instFieldKeyToP2Set, ifk).addAll(find(pkToP2Set, storedValAndState)); + } + } + } + } + for (LoadEdge loadEdge : encounteredLoads) { + PointerKeyAndState loadedValAndState = loadEdge.val; + IField field = loadEdge.field; + PointerKey basePointerKey = loadEdge.base.getPointerKey(); + State loadDstState = loadedValAndState.getState(); + PointerKeyAndState baseAndStateToHandle = new PointerKeyAndState(basePointerKey, loadDstState); + boolean basePointerOkay = pointsToQueried.get(basePointerKey).contains(loadDstState) + || !pointsToQueried.get(loadedValAndState.getPointerKey()).contains(loadDstState) + || initWorklist.contains(loadedValAndState); + // if (!basePointerOkay) { + // System.err.println("ASSERTION WILL FAIL"); + // System.err.println("QUERIED: " + queriedPkAndStates); + // } + if (!basePointerOkay) { + // remove this assertion, since we now allow multiple queries --MS + // Assertions._assert(false, "queried " + loadedValAndState + " but not " + baseAndStateToHandle); + } + final IntSet curP2Set = find(pkToP2Set, baseAndStateToHandle); + // int startSize = curP2Set.size(); + // int curSize = -1; + for (InstanceKeyAndState ikAndState : makeOrdinalSet(curP2Set)) { + // curSize = curP2Set.size(); + // if (Assertions.verifyAssertions) { + // Assertions._assert(startSize == curSize); + // } + InstanceFieldKeyAndState ifk = getInstFieldKey(ikAndState, field); + // make sure we've actually queried the def'd val before adding to its points-to set + if (pointsToQueried.get(loadedValAndState.getPointerKey()).contains(loadedValAndState.getState())) { + // just pass no label assign filter since no type-based filtering can be + // done here + if (addAllToP2Set(pkToP2Set, loadedValAndState, find(instFieldKeyToP2Set, ifk), AssignLabel.noFilter())) { + if (DEBUG) { + System.err.println("from load edge " + loadEdge); + } + addToPToWorklist(loadedValAndState); + } + } + } + // } + // x = y.f, Y' updated + PointerKeyAndState baseAndState = loadEdge.base; + for (InstanceKeyAndState ikAndState : makeOrdinalSet(find(pkToTrackedSet, baseAndState))) { + if (backInstKeyToFields.get(ikAndState).contains(field)) { + // tracking value written into ik.field + InstanceFieldKeyAndState ifk = getInstFieldKey(ikAndState, field); + if (findOrCreate(pkToTrackedSet, loadedValAndState).addAll(find(instFieldKeyToTrackedSet, ifk))) { + if (DEBUG) { + System.err.println("from load edge " + loadEdge); + } + addToTrackedPToWorklist(loadedValAndState); + } + } + } + } + } + + private InstanceFieldKeyAndState getInstFieldKey(InstanceKeyAndState ikAndState, IField field) { + return new InstanceFieldKeyAndState(new InstanceFieldKey(ikAndState.getInstanceKey(), field), ikAndState.getState()); + } + + protected MutableIntSet findOrCreate(Map M, K key) { + MutableIntSet result = M.get(key); + if (result == null) { + result = intSetFactory.make(); + M.put(key, result); + } + return result; + } + + private final MutableIntSet emptySet = intSetFactory.make(); + + protected MutableIntSet find(Map M, K key) { + MutableIntSet result = M.get(key); + if (result == null) { + result = emptySet; + } + return result; + } + + /** + * Handle a predecessor when processing some tracked locations + * + * @param curTrackedSet the tracked locations + * @param predPkAndState the predecessor + */ + protected boolean handleTrackedPred(final MutableIntSet curTrackedSet, PointerKeyAndState predPkAndState, IFlowLabel label) { + if (addAllToP2Set(pkToTrackedSet, predPkAndState, curTrackedSet, label)) { + addToTrackedPToWorklist(predPkAndState); + return true; + } + return false; + } + } + + private SSAAbstractInvokeInstruction[] getCallInstrs(CGNode node, CallSiteReference site) { + return node.getIR().getCalls(site); + } + + private boolean hasNullIR(CGNode node) { + boolean ret = node.getMethod().isNative(); + assert node.getIR() != null || ret; + return ret; + } + + private Object doTransition(State curState, IFlowLabel label, Function func) { + State nextState = stateMachine.transition(curState, label); + Object ret = null; + if (nextState != StateMachine.ERROR) { + ret = func.apply(nextState); + } else { + // System.err.println("filtered at edge " + label); + } + return ret; + } + + public StateMachineFactory getStateMachineFactory() { + return stateMachineFactory; + } + + public void setStateMachineFactory(StateMachineFactory stateMachineFactory) { + this.stateMachineFactory = stateMachineFactory; + } + + public RefinementPolicyFactory getRefinementPolicyFactory() { + return refinementPolicyFactory; + } + + public void setRefinementPolicyFactory(RefinementPolicyFactory refinementPolicyFactory) { + this.refinementPolicyFactory = refinementPolicyFactory; + } + + /** + * we are looking for an instance key flowing to pk that violates pred. + * + * @param pk + * @param pred + * @param pa + */ + @SuppressWarnings("unused") + private boolean doTopLevelTraversal(PointerKey pk, final Predicate pred, final PointsToComputer ptoComputer, + PointerAnalysis pa) { + final Set visited = HashSetFactory.make(); + final LinkedList worklist = new LinkedList(); + + class Helper { + + /** + * cache of the targets discovered for a call site during on-the-fly call graph construction + */ + private final MultiMap callToOTFTargets = ArraySetMultiMap.make(); + + void propagate(PointerKeyAndState pkAndState) { + if (visited.add(pkAndState)) { + assert graphContainsNode(pkAndState.getPointerKey()); + worklist.addLast(pkAndState); + } + } + + private boolean graphContainsNode(PointerKey pointerKey) { + if (pointerKey instanceof LocalPointerKey) { + LocalPointerKey lpk = (LocalPointerKey) pointerKey; + return g.hasSubgraphForNode(lpk.getNode()); + } + return true; + } + + private Collection getOTFTargets(CallerSiteContext callSiteAndCGNode, SSAAbstractInvokeInstruction[] callInstrs, + State callerState) { + if (DEBUG_TOPLEVEL) { + System.err.println("toplevel refining call site " + callSiteAndCGNode); + } + final CallSiteReference call = callSiteAndCGNode.getCallSite(); + final CGNode caller = callSiteAndCGNode.getCaller(); + Collection result = HashSetFactory.make(); + for (SSAAbstractInvokeInstruction callInstr : callInstrs) { + PointerKey thisArg = heapModel.getPointerKeyForLocal(caller, callInstr.getUse(0)); + PointerKeyAndState thisArgAndState = new PointerKeyAndState(thisArg, callerState); + OrdinalSet thisPToSet = getPToSetFromComputer(ptoComputer, thisArgAndState); + for (InstanceKeyAndState ikAndState : thisPToSet) { + InstanceKey ik = ikAndState.getInstanceKey(); + IMethod targetMethod = options.getMethodTargetSelector().getCalleeTarget(caller, call, ik.getConcreteType()); + if (targetMethod == null) { + // NOTE: target method can be null because we don't + // always have type filters + continue; + } + result.add(targetMethod); + } + } + return result; + } + + public void handleTopLevelForwInterproc(PointerKeyAndState curPkAndState) { + PointerKey curPk = curPkAndState.getPointerKey(); + final State curState = curPkAndState.getState(); + if (curPk instanceof LocalPointerKey) { + final LocalPointerKey localPk = (LocalPointerKey) curPk; + if (g.isParam(localPk)) { + // System.err.println("at param"); + final CGNode callee = localPk.getNode(); + final int paramPos = localPk.getValueNumber() - 1; + for (final CallerSiteContext callSiteAndCGNode : g.getPotentialCallers(localPk)) { + final CGNode caller = callSiteAndCGNode.getCaller(); + final CallSiteReference call = callSiteAndCGNode.getCallSite(); + // final IR ir = getIR(caller); + if (hasNullIR(caller)) + continue; + final ParamLabel paramLabel = ParamLabel.make(callSiteAndCGNode); + doTransition(curPkAndState.getState(), paramLabel, new Function() { + + private void propagateToCallee() { + // if (caller.getIR() == null) { + // return; + // } + g.addSubgraphForNode(caller); + SSAAbstractInvokeInstruction[] callInstrs = getCallInstrs(caller, call); + for (int i = 0; i < callInstrs.length; i++) { + SSAAbstractInvokeInstruction callInstr = callInstrs[i]; + final PointerKey actualPk = heapModel.getPointerKeyForLocal(caller, callInstr.getUse(paramPos)); + assert g.containsNode(actualPk); + assert g.containsNode(localPk); + doTransition(curState, paramLabel, new Function() { + public Object apply(State nextState) { + propagate(new PointerKeyAndState(actualPk, nextState)); + return null; + } + + }); + } + } + + public Object apply(State callerState) { + // hack to get some actual parameter from call site + // TODO do this better + SSAAbstractInvokeInstruction[] callInstrs = getCallInstrs(caller, call); + SSAAbstractInvokeInstruction callInstr = callInstrs[0]; + PointerKey actualPk = heapModel.getPointerKeyForLocal(caller, callInstr.getUse(paramPos)); + Set possibleTargets = g.getPossibleTargets(caller, call, (LocalPointerKey) actualPk); + if (noOnTheFlyNeeded(callSiteAndCGNode, possibleTargets)) { + propagateToCallee(); + } else { + Collection otfTargets = getOTFTargets(callSiteAndCGNode, callInstrs, callerState); + if (otfTargets.contains(callee.getMethod())) { + // already found this target as valid, so do propagation + propagateToCallee(); + } + } + return null; + } + + }); + + } + } + SSAInvokeInstruction callInstr = g.getInstrReturningTo(localPk); + if (callInstr != null) { + CGNode caller = localPk.getNode(); + boolean isExceptional = localPk.getValueNumber() == callInstr.getException(); + + CallSiteReference callSiteRef = callInstr.getCallSite(); + CallerSiteContext callSiteAndCGNode = new CallerSiteContext(caller, callSiteRef); + // get call targets + Set possibleCallees = g.getPossibleTargets(caller, callSiteRef, localPk); + if (noOnTheFlyNeeded(callSiteAndCGNode, possibleCallees)) { + for (CGNode callee : possibleCallees) { + if (hasNullIR(callee)) { + continue; + } + g.addSubgraphForNode(callee); + final PointerKey retVal = isExceptional ? heapModel.getPointerKeyForExceptionalReturnValue(callee) : heapModel + .getPointerKeyForReturnValue(callee); + assert g.containsNode(retVal); + doTransition(curState, ReturnLabel.make(callSiteAndCGNode), new Function() { + + public Object apply(State nextState) { + propagate(new PointerKeyAndState(retVal, nextState)); + return null; + } + + }); + } + } else { + Collection otfTargets = getOTFTargets(callSiteAndCGNode, getCallInstrs(caller, callSiteAndCGNode + .getCallSite()), curPkAndState.getState()); + for (CGNode callee : possibleCallees) { + if (otfTargets.contains(callee.getMethod())) { + if (hasNullIR(callee)) { + continue; + } + g.addSubgraphForNode(callee); + final PointerKey retVal = isExceptional ? heapModel.getPointerKeyForExceptionalReturnValue(callee) : heapModel + .getPointerKeyForReturnValue(callee); + assert g.containsNode(retVal); + doTransition(curState, ReturnLabel.make(callSiteAndCGNode), new Function() { + + public Object apply(State nextState) { + propagate(new PointerKeyAndState(retVal, nextState)); + return null; + } + + }); + } + } + } + } + } + + } + + private OrdinalSet getPToSetFromComputer(final PointsToComputer ptoComputer, + PointerKeyAndState pointerKeyAndState) { + // make sure relevant constraints have been added + if (pointerKeyAndState.getPointerKey() instanceof LocalPointerKey) { + LocalPointerKey lpk = (LocalPointerKey) pointerKeyAndState.getPointerKey(); + g.addSubgraphForNode(lpk.getNode()); + } + // add pointerKeyAndState to init worklist + ptoComputer.addToInitWorklist(pointerKeyAndState); + // run worklist algorithm + ptoComputer.worklistLoop(); + // suck out the points-to set + final MutableIntSet intP2Set = ptoComputer.pkToP2Set.get(pointerKeyAndState); + if (intP2Set == null) { + // null if empty p2set + return OrdinalSet.empty(); + } else { + return ptoComputer.makeOrdinalSet(intP2Set); + } + } + + private void computeFlowsTo(PointsToComputer ptoComputer, OrdinalSet basePToSet) { + for (InstanceKeyAndState ikAndState : basePToSet) { + ptoComputer.addPredsOfIKeyAndStateToTrackedPointsTo(ikAndState); + } + // run worklist loop + assert ptoComputer.initWorklist.isEmpty(); + assert ptoComputer.pointsToWorklist.isEmpty(); + ptoComputer.worklistLoop(); + } + + private Collection getFlowedToStates(PointsToComputer ptoComputer, OrdinalSet basePToSet, + PointerKey putfieldBase) { + Collection result = HashSetFactory.make(); + Set trackedStates = ptoComputer.trackedQueried.get(putfieldBase); + for (State trackedState : trackedStates) { + PointerKeyAndState pkAndState = new PointerKeyAndState(putfieldBase, trackedState); + if (ptoComputer.makeOrdinalSet(ptoComputer.pkToTrackedSet.get(pkAndState)).containsAny(basePToSet)) { + result.add(trackedState); + } + } + // for (PointerKeyAndState pkAndState : ptoComputer.pkToTrackedSet.keySet()) { + // if (pkAndState.getPointerKey().equals(putfieldBase)) { + // if (ptoComputer.makeOrdinalSet(ptoComputer.pkToTrackedSet.get(pkAndState)).containsAny(basePToSet)) { + // result.add(pkAndState.getState()); + // } + // } + // } + return result; + } + + } + final Helper h = new Helper(); + PointerKeyAndState initPkAndState = new PointerKeyAndState(pk, stateMachine.getStartState()); + if (pk instanceof LocalPointerKey) { + g.addSubgraphForNode(((LocalPointerKey) pk).getNode()); + } + h.propagate(initPkAndState); + while (!worklist.isEmpty()) { + incrementNumNodesTraversed(); + PointerKeyAndState curPkAndState = worklist.removeFirst(); + final PointerKey curPk = curPkAndState.getPointerKey(); + final State curState = curPkAndState.getState(); + // if predicate holds for pre-computed points-to set of curPk, we are done + if (DEBUG_TOPLEVEL) { + System.err.println("toplevel pkAndState " + curPkAndState); + } + if (predHoldsForPk(curPk, pred, pa)) { + if (DEBUG_TOPLEVEL) { + System.err.println("predicate holds"); + } + continue; + } + // otherwise, traverse new, assign, assign global, param, return, match edges + class MyFlowLabelVisitor extends AbstractFlowLabelVisitor { + + boolean foundBadInstanceKey; + + @Override + public void visitNew(NewLabel label, Object dst) { + // TODO Auto-generated method stub + + final InstanceKey ik = (InstanceKey) dst; + if (DEBUG_TOPLEVEL) { + System.err.println("toplevel alloc " + ik + " assigned to " + curPk); + } + doTransition(curState, label, new Function() { + + public Object apply(State newState) { + // just check if ik violates the pred + if (!pred.test(ik)) { + foundBadInstanceKey = true; + } + return null; + } + + }); + } + + @Override + public void visitGetField(GetFieldLabel label, Object dst) { + IField field = (label).getField(); + PointerKey loadBase = (PointerKey) dst; + if (refineFieldAccesses(field, loadBase, curPk, label, curState)) { + if (DEBUG_TOPLEVEL) { + System.err.println("toplevel refining for read of " + field); + } + // find points-to set of base pointer + OrdinalSet basePToSet = h.getPToSetFromComputer(ptoComputer, new PointerKeyAndState(loadBase, + curState)); + if (DEBUG_TOPLEVEL) { + System.err.println("toplevel base pointer p2set " + basePToSet); + } + // find "flows-to sets" of pointed-to instance keys + h.computeFlowsTo(ptoComputer, basePToSet); + if (DEBUG_TOPLEVEL) { + System.err.println("toplevel finished computing flows to"); + } + // for each putfield base pointer, if flowed-to, then propagate written pointer key + for (MemoryAccess fieldWrite : getWrites(field, loadBase)) { + Collection> baseAndStoredPairs = getBaseAndStored(fieldWrite, field); + if (baseAndStoredPairs == null) { + continue; + } + for (Pair p : baseAndStoredPairs) { + PointerKey base = p.fst; + PointerKey stored = p.snd; + Collection reachedFlowStates = h.getFlowedToStates(ptoComputer, basePToSet, base); + for (State nextState : reachedFlowStates) { + if (DEBUG_TOPLEVEL) { + System.err.println("toplevel alias with base " + base + " in state " + nextState); + } + h.propagate(new PointerKeyAndState(stored, nextState)); + } + } + } + } else { // use match edges + for (Iterator writesToInstanceField = g.getWritesToInstanceField(loadBase, field); writesToInstanceField + .hasNext();) { + final PointerKey writtenPk = writesToInstanceField.next(); + doTransition(curState, MatchLabel.v(), new Function() { + + public Object apply(State nextState) { + h.propagate(new PointerKeyAndState(writtenPk, nextState)); + return null; + } + + }); + } + } + } + + private Collection> getBaseAndStored(MemoryAccess fieldWrite, IField field) { + final CGNode node = fieldWrite.getNode(); + // an optimization; if node is not represented in our constraint graph, then we could not possibly + // have discovered flow to the base pointer + if (!g.hasSubgraphForNode(node)) { + return null; + } + IR ir = node.getIR(); + PointerKey base = null, stored = null; + if (field == ArrayContents.v()) { + final SSAInstruction instruction = ir.getInstructions()[fieldWrite.getInstructionIndex()]; + if (instruction == null) { + return null; + } + if (instruction instanceof SSANewInstruction) { + return DemandPointerFlowGraph.getInfoForNewMultiDim((SSANewInstruction) instruction, heapModel, fieldWrite.getNode()).arrStoreInstrs; + } + SSAArrayStoreInstruction s = (SSAArrayStoreInstruction) instruction; + base = heapModel.getPointerKeyForLocal(fieldWrite.getNode(), s.getArrayRef()); + stored = heapModel.getPointerKeyForLocal(fieldWrite.getNode(), s.getValue()); + } else { + SSAPutInstruction s = (SSAPutInstruction) ir.getInstructions()[fieldWrite.getInstructionIndex()]; + if (s == null) { + return null; + } + base = heapModel.getPointerKeyForLocal(fieldWrite.getNode(), s.getRef()); + stored = heapModel.getPointerKeyForLocal(fieldWrite.getNode(), s.getVal()); + } + return Collections.singleton(Pair.make(base, stored)); + } + + private Collection getWrites(IField field, PointerKey loadBase) { + final PointerKey convertedBase = convertToHeapModel(loadBase, mam.getHeapModel()); + if (field == ArrayContents.v()) { + return mam.getArrayWrites(loadBase); + } else { + return mam.getFieldWrites(convertedBase, field); + } + } + + @Override + public void visitAssignGlobal(AssignGlobalLabel label, Object dst) { + for (Iterator writesToStaticField = g.getWritesToStaticField((StaticFieldKey) dst); writesToStaticField + .hasNext();) { + final PointerKey writtenPk = (PointerKey) writesToStaticField.next(); + doTransition(curState, label, new Function() { + + public Object apply(State nextState) { + h.propagate(new PointerKeyAndState(writtenPk, nextState)); + return null; + } + + }); + + } + } + + @Override + public void visitAssign(AssignLabel label, Object dst) { + final PointerKey succPk = (PointerKey) dst; + doTransition(curState, label, new Function() { + + public Object apply(State nextState) { + h.propagate(new PointerKeyAndState(succPk, nextState)); + return null; + } + + }); + } + + } + MyFlowLabelVisitor v = new MyFlowLabelVisitor(); + g.visitSuccs(curPk, v); + if (v.foundBadInstanceKey) { + // found an instance key violating the pred + return false; + } + h.handleTopLevelForwInterproc(curPkAndState); + } + return true; + } + + private boolean predHoldsForPk(PointerKey curPk, Predicate pred, PointerAnalysis pa) { + PointerKey curPkForPAHeapModel = convertToHeapModel(curPk, pa.getHeapModel()); + OrdinalSet pointsToSet = pa.getPointsToSet(curPkForPAHeapModel); + for (InstanceKey ik : pointsToSet) { + if (!pred.test(ik)) { + return false; + } + } + return true; + } + + private PointerKey convertToHeapModel(PointerKey curPk, HeapModel heapModel) { + return AbstractFlowGraph.convertPointerKeyToHeapModel(curPk, heapModel); + } + + private boolean refineFieldAccesses(IField field, PointerKey basePtr, PointerKey val, IFlowLabel label, State state) { + boolean shouldRefine = refinementPolicy.getFieldRefinePolicy().shouldRefine(field, basePtr, val, label, state); + if (DEBUG) { + if (shouldRefine) { + System.err.println("refining access to " + field); + } else { + System.err.println("using match for access to " + field); + } + } + return shouldRefine; + } + + private boolean noOnTheFlyNeeded(CallerSiteContext call, Set possibleTargets) { + // NOTE: if we want to be more precise for queries in dead code, + // we shouldn't rely on possibleTargets here (since there may be + // zero targets) + if (!refinementPolicy.getCallGraphRefinePolicy().shouldRefine(call)) { + return true; + } + // here we compute the number of unique *method* targets, as opposed to call graph nodes. + // if we have a context-sensitive call graph, with many targets representing clones of + // the same method, we don't want to count the clones twice + Set methodTargets = new HashSet(); + for (CGNode node : possibleTargets) { + methodTargets.add(node.getMethod()); + } + return methodTargets.size() <= 1; + } + + /** + * used to compute "flows-to sets," i.e., all the pointers that can point to some instance key + * + */ + protected class FlowsToComputer extends PointsToComputer { + + private final InstanceKeyAndState queriedIkAndState; + + private final int queriedIkAndStateNum; + + /** + * holds the desired flows-to set + */ + private final Collection theFlowsToSet = HashSetFactory.make(); + + public FlowsToComputer(InstanceKeyAndState ikAndState) { + this.queriedIkAndState = ikAndState; + this.queriedIkAndStateNum = ikAndStates.add(queriedIkAndState); + } + + @Override + protected void compute() { + // seed the points-to worklist + + InstanceKey ik = queriedIkAndState.getInstanceKey(); + g.addSubgraphForNode(((InstanceKeyWithNode) ik).getNode()); + for (Object pred : Iterator2Iterable.make(g.getPredNodes(ik, NewLabel.v()))) { + PointerKey predPk = (PointerKey) pred; + PointerKeyAndState predPkAndState = new PointerKeyAndState(predPk, queriedIkAndState.getState()); + theFlowsToSet.add(predPkAndState); + findOrCreate(pkToTrackedSet, predPkAndState).add(queriedIkAndStateNum); + addToTrackedPToWorklist(predPkAndState); + } + worklistLoop(); + } + + public Collection getComputedFlowsToSet() { + return theFlowsToSet; + } + + /** + * also update the flows-to set of interest if necessary + */ + @Override + protected boolean handleTrackedPred(MutableIntSet curTrackedSet, PointerKeyAndState predPkAndState, IFlowLabel label) { + boolean result = super.handleTrackedPred(curTrackedSet, predPkAndState, label); + if (result && find(pkToTrackedSet, predPkAndState).contains(queriedIkAndStateNum)) { + theFlowsToSet.add(predPkAndState); + } + return result; + } + + } + +} diff --git a/com.ibm.wala.core/src/com/ibm/wala/demandpa/alg/IDemandPointerAnalysis.java b/com.ibm.wala.core/src/com/ibm/wala/demandpa/alg/IDemandPointerAnalysis.java index 541c01ded..833acfe94 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/demandpa/alg/IDemandPointerAnalysis.java +++ b/com.ibm.wala.core/src/com/ibm/wala/demandpa/alg/IDemandPointerAnalysis.java @@ -1,63 +1,63 @@ -/******************************************************************************* - * 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. - * - * This file is a derivative of code released by the University of - * California under the terms listed below. - * - * Refinement Analysis Tools is Copyright (c) 2007 The Regents of the - * University of California (Regents). Provided that this notice and - * the following two paragraphs are included in any distribution of - * Refinement Analysis Tools or its derivative work, Regents agrees - * not to assert any of Regents' copyright rights in Refinement - * Analysis Tools against recipient for recipient's reproduction, - * preparation of derivative works, public display, public - * performance, distribution or sublicensing of Refinement Analysis - * Tools and derivative works, in source code and object code form. - * This agreement not to assert does not confer, by implication, - * estoppel, or otherwise any license or rights in any intellectual - * property of Regents, including, but not limited to, any patents - * of Regents or Regents' employees. - * - * IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, - * INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, - * INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE - * AND ITS DOCUMENTATION, EVEN IF REGENTS HAS BEEN ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE AND FURTHER DISCLAIMS ANY STATUTORY - * WARRANTY OF NON-INFRINGEMENT. THE SOFTWARE AND ACCOMPANYING - * DOCUMENTATION, IF ANY, PROVIDED HEREUNDER IS PROVIDED "AS - * IS". REGENTS HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, - * UPDATES, ENHANCEMENTS, OR MODIFICATIONS. - */ -package com.ibm.wala.demandpa.alg; - -import java.util.Collection; - -import com.ibm.wala.ipa.callgraph.CallGraph; -import com.ibm.wala.ipa.callgraph.propagation.HeapModel; -import com.ibm.wala.ipa.callgraph.propagation.InstanceKey; -import com.ibm.wala.ipa.callgraph.propagation.PointerKey; -import com.ibm.wala.ipa.cha.IClassHierarchy; - -/** - * Basic interface for a demand-driven points-to analysis. - * - * @author Manu Sridharan - * - */ -public interface IDemandPointerAnalysis { - - public HeapModel getHeapModel(); - - public CallGraph getBaseCallGraph(); - - public IClassHierarchy getClassHierarchy(); - - public Collection getPointsTo(PointerKey pk); -} +/******************************************************************************* + * 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. + * + * This file is a derivative of code released by the University of + * California under the terms listed below. + * + * Refinement Analysis Tools is Copyright (c) 2007 The Regents of the + * University of California (Regents). Provided that this notice and + * the following two paragraphs are included in any distribution of + * Refinement Analysis Tools or its derivative work, Regents agrees + * not to assert any of Regents' copyright rights in Refinement + * Analysis Tools against recipient for recipient's reproduction, + * preparation of derivative works, public display, public + * performance, distribution or sublicensing of Refinement Analysis + * Tools and derivative works, in source code and object code form. + * This agreement not to assert does not confer, by implication, + * estoppel, or otherwise any license or rights in any intellectual + * property of Regents, including, but not limited to, any patents + * of Regents or Regents' employees. + * + * IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, + * INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, + * INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE + * AND ITS DOCUMENTATION, EVEN IF REGENTS HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE AND FURTHER DISCLAIMS ANY STATUTORY + * WARRANTY OF NON-INFRINGEMENT. THE SOFTWARE AND ACCOMPANYING + * DOCUMENTATION, IF ANY, PROVIDED HEREUNDER IS PROVIDED "AS + * IS". REGENTS HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, + * UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + */ +package com.ibm.wala.demandpa.alg; + +import java.util.Collection; + +import com.ibm.wala.ipa.callgraph.CallGraph; +import com.ibm.wala.ipa.callgraph.propagation.HeapModel; +import com.ibm.wala.ipa.callgraph.propagation.InstanceKey; +import com.ibm.wala.ipa.callgraph.propagation.PointerKey; +import com.ibm.wala.ipa.cha.IClassHierarchy; + +/** + * Basic interface for a demand-driven points-to analysis. + * + * @author Manu Sridharan + * + */ +public interface IDemandPointerAnalysis { + + public HeapModel getHeapModel(); + + public CallGraph getBaseCallGraph(); + + public IClassHierarchy getClassHierarchy(); + + public Collection getPointsTo(PointerKey pk); +} diff --git a/com.ibm.wala.core/src/com/ibm/wala/demandpa/alg/InstanceFieldKeyAndState.java b/com.ibm.wala.core/src/com/ibm/wala/demandpa/alg/InstanceFieldKeyAndState.java index 10e69a9e4..fc8b56767 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/demandpa/alg/InstanceFieldKeyAndState.java +++ b/com.ibm.wala.core/src/com/ibm/wala/demandpa/alg/InstanceFieldKeyAndState.java @@ -1,55 +1,55 @@ -/******************************************************************************* - * 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. - * - * This file is a derivative of code released by the University of - * California under the terms listed below. - * - * Refinement Analysis Tools is Copyright (c) 2007 The Regents of the - * University of California (Regents). Provided that this notice and - * the following two paragraphs are included in any distribution of - * Refinement Analysis Tools or its derivative work, Regents agrees - * not to assert any of Regents' copyright rights in Refinement - * Analysis Tools against recipient for recipient's reproduction, - * preparation of derivative works, public display, public - * performance, distribution or sublicensing of Refinement Analysis - * Tools and derivative works, in source code and object code form. - * This agreement not to assert does not confer, by implication, - * estoppel, or otherwise any license or rights in any intellectual - * property of Regents, including, but not limited to, any patents - * of Regents or Regents' employees. - * - * IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, - * INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, - * INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE - * AND ITS DOCUMENTATION, EVEN IF REGENTS HAS BEEN ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE AND FURTHER DISCLAIMS ANY STATUTORY - * WARRANTY OF NON-INFRINGEMENT. THE SOFTWARE AND ACCOMPANYING - * DOCUMENTATION, IF ANY, PROVIDED HEREUNDER IS PROVIDED "AS - * IS". REGENTS HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, - * UPDATES, ENHANCEMENTS, OR MODIFICATIONS. - */ -package com.ibm.wala.demandpa.alg; - - -import com.ibm.wala.demandpa.alg.statemachine.StateMachine.State; -import com.ibm.wala.ipa.callgraph.propagation.InstanceFieldKey; - - -public class InstanceFieldKeyAndState extends WithState { - - public InstanceFieldKeyAndState(InstanceFieldKey wrapped, State state) { - super(wrapped, state); - } - - public InstanceFieldKey getInstanceFieldKey() { - return getWrapped(); - } - -} +/******************************************************************************* + * 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. + * + * This file is a derivative of code released by the University of + * California under the terms listed below. + * + * Refinement Analysis Tools is Copyright (c) 2007 The Regents of the + * University of California (Regents). Provided that this notice and + * the following two paragraphs are included in any distribution of + * Refinement Analysis Tools or its derivative work, Regents agrees + * not to assert any of Regents' copyright rights in Refinement + * Analysis Tools against recipient for recipient's reproduction, + * preparation of derivative works, public display, public + * performance, distribution or sublicensing of Refinement Analysis + * Tools and derivative works, in source code and object code form. + * This agreement not to assert does not confer, by implication, + * estoppel, or otherwise any license or rights in any intellectual + * property of Regents, including, but not limited to, any patents + * of Regents or Regents' employees. + * + * IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, + * INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, + * INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE + * AND ITS DOCUMENTATION, EVEN IF REGENTS HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE AND FURTHER DISCLAIMS ANY STATUTORY + * WARRANTY OF NON-INFRINGEMENT. THE SOFTWARE AND ACCOMPANYING + * DOCUMENTATION, IF ANY, PROVIDED HEREUNDER IS PROVIDED "AS + * IS". REGENTS HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, + * UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + */ +package com.ibm.wala.demandpa.alg; + + +import com.ibm.wala.demandpa.alg.statemachine.StateMachine.State; +import com.ibm.wala.ipa.callgraph.propagation.InstanceFieldKey; + + +public class InstanceFieldKeyAndState extends WithState { + + public InstanceFieldKeyAndState(InstanceFieldKey wrapped, State state) { + super(wrapped, state); + } + + public InstanceFieldKey getInstanceFieldKey() { + return getWrapped(); + } + +} diff --git a/com.ibm.wala.core/src/com/ibm/wala/demandpa/alg/InstanceKeyAndState.java b/com.ibm.wala.core/src/com/ibm/wala/demandpa/alg/InstanceKeyAndState.java index b6d74c3ff..3b6581b3f 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/demandpa/alg/InstanceKeyAndState.java +++ b/com.ibm.wala.core/src/com/ibm/wala/demandpa/alg/InstanceKeyAndState.java @@ -1,59 +1,59 @@ -/******************************************************************************* - * 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. - * - * This file is a derivative of code released by the University of - * California under the terms listed below. - * - * Refinement Analysis Tools is Copyright (c) 2007 The Regents of the - * University of California (Regents). Provided that this notice and - * the following two paragraphs are included in any distribution of - * Refinement Analysis Tools or its derivative work, Regents agrees - * not to assert any of Regents' copyright rights in Refinement - * Analysis Tools against recipient for recipient's reproduction, - * preparation of derivative works, public display, public - * performance, distribution or sublicensing of Refinement Analysis - * Tools and derivative works, in source code and object code form. - * This agreement not to assert does not confer, by implication, - * estoppel, or otherwise any license or rights in any intellectual - * property of Regents, including, but not limited to, any patents - * of Regents or Regents' employees. - * - * IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, - * INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, - * INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE - * AND ITS DOCUMENTATION, EVEN IF REGENTS HAS BEEN ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE AND FURTHER DISCLAIMS ANY STATUTORY - * WARRANTY OF NON-INFRINGEMENT. THE SOFTWARE AND ACCOMPANYING - * DOCUMENTATION, IF ANY, PROVIDED HEREUNDER IS PROVIDED "AS - * IS". REGENTS HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, - * UPDATES, ENHANCEMENTS, OR MODIFICATIONS. - */ -package com.ibm.wala.demandpa.alg; - - -import com.ibm.wala.demandpa.alg.statemachine.StateMachine.State; -import com.ibm.wala.ipa.callgraph.propagation.InstanceKey; - - - -/** - * @author Manu Sridharan - * - */ -public class InstanceKeyAndState extends WithState { - public InstanceKeyAndState(InstanceKey ik, State state) { - super(ik, state); - } - - public InstanceKey getInstanceKey() { - return getWrapped(); - } - -} +/******************************************************************************* + * 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. + * + * This file is a derivative of code released by the University of + * California under the terms listed below. + * + * Refinement Analysis Tools is Copyright (c) 2007 The Regents of the + * University of California (Regents). Provided that this notice and + * the following two paragraphs are included in any distribution of + * Refinement Analysis Tools or its derivative work, Regents agrees + * not to assert any of Regents' copyright rights in Refinement + * Analysis Tools against recipient for recipient's reproduction, + * preparation of derivative works, public display, public + * performance, distribution or sublicensing of Refinement Analysis + * Tools and derivative works, in source code and object code form. + * This agreement not to assert does not confer, by implication, + * estoppel, or otherwise any license or rights in any intellectual + * property of Regents, including, but not limited to, any patents + * of Regents or Regents' employees. + * + * IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, + * INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, + * INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE + * AND ITS DOCUMENTATION, EVEN IF REGENTS HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE AND FURTHER DISCLAIMS ANY STATUTORY + * WARRANTY OF NON-INFRINGEMENT. THE SOFTWARE AND ACCOMPANYING + * DOCUMENTATION, IF ANY, PROVIDED HEREUNDER IS PROVIDED "AS + * IS". REGENTS HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, + * UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + */ +package com.ibm.wala.demandpa.alg; + + +import com.ibm.wala.demandpa.alg.statemachine.StateMachine.State; +import com.ibm.wala.ipa.callgraph.propagation.InstanceKey; + + + +/** + * @author Manu Sridharan + * + */ +public class InstanceKeyAndState extends WithState { + public InstanceKeyAndState(InstanceKey ik, State state) { + super(ik, state); + } + + public InstanceKey getInstanceKey() { + return getWrapped(); + } + +} diff --git a/com.ibm.wala.core/src/com/ibm/wala/demandpa/alg/IntraProcFilter.java b/com.ibm.wala.core/src/com/ibm/wala/demandpa/alg/IntraProcFilter.java index f63ebee16..b242de4d6 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/demandpa/alg/IntraProcFilter.java +++ b/com.ibm.wala.core/src/com/ibm/wala/demandpa/alg/IntraProcFilter.java @@ -1,110 +1,110 @@ -/******************************************************************************* - * 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. - * - * This file is a derivative of code released by the University of - * California under the terms listed below. - * - * Refinement Analysis Tools is Copyright (c) 2007 The Regents of the - * University of California (Regents). Provided that this notice and - * the following two paragraphs are included in any distribution of - * Refinement Analysis Tools or its derivative work, Regents agrees - * not to assert any of Regents' copyright rights in Refinement - * Analysis Tools against recipient for recipient's reproduction, - * preparation of derivative works, public display, public - * performance, distribution or sublicensing of Refinement Analysis - * Tools and derivative works, in source code and object code form. - * This agreement not to assert does not confer, by implication, - * estoppel, or otherwise any license or rights in any intellectual - * property of Regents, including, but not limited to, any patents - * of Regents or Regents' employees. - * - * IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, - * INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, - * INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE - * AND ITS DOCUMENTATION, EVEN IF REGENTS HAS BEEN ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE AND FURTHER DISCLAIMS ANY STATUTORY - * WARRANTY OF NON-INFRINGEMENT. THE SOFTWARE AND ACCOMPANYING - * DOCUMENTATION, IF ANY, PROVIDED HEREUNDER IS PROVIDED "AS - * IS". REGENTS HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, - * UPDATES, ENHANCEMENTS, OR MODIFICATIONS. - */ -package com.ibm.wala.demandpa.alg; - -import com.ibm.wala.demandpa.alg.statemachine.StateMachine; -import com.ibm.wala.demandpa.alg.statemachine.StateMachineFactory; -import com.ibm.wala.demandpa.flowgraph.AbstractFlowLabelVisitor; -import com.ibm.wala.demandpa.flowgraph.IFlowLabel; -import com.ibm.wala.demandpa.flowgraph.ParamBarLabel; -import com.ibm.wala.demandpa.flowgraph.ParamLabel; -import com.ibm.wala.demandpa.flowgraph.ReturnBarLabel; -import com.ibm.wala.demandpa.flowgraph.ReturnLabel; - -/** - * State machine that only allows intraprocedural paths. Mainly for testing - * purposes. - * - * @author Manu Sridharan - * - */ -public class IntraProcFilter implements StateMachine { - - private static final State DUMMY = new State() { - }; - - public State getStartState() { - return DUMMY; - } - - private static class InterprocFilterVisitor extends AbstractFlowLabelVisitor { - @Override - public void visitParamBar(ParamBarLabel label, Object dst) { - interprocEdge = true; - } - - @Override - public void visitParam(ParamLabel label, Object dst) { - interprocEdge = true; - } - - @Override - public void visitReturn(ReturnLabel label, Object dst) { - interprocEdge = true; - } - - @Override - public void visitReturnBar(ReturnBarLabel label, Object dst) { - interprocEdge = true; - } - - boolean interprocEdge = false; - - } - - public State transition(State prevState, IFlowLabel label) throws IllegalArgumentException { - if (label == null) { - throw new IllegalArgumentException("label == null"); - } - // filter out all interprocedural edges - InterprocFilterVisitor v = new InterprocFilterVisitor(); - label.visit(v, null); - return v.interprocEdge ? ERROR : DUMMY; - } - - private IntraProcFilter() { - } - - public static class Factory implements StateMachineFactory { - - public StateMachine make() { - return new IntraProcFilter(); - } - - } -} +/******************************************************************************* + * 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. + * + * This file is a derivative of code released by the University of + * California under the terms listed below. + * + * Refinement Analysis Tools is Copyright (c) 2007 The Regents of the + * University of California (Regents). Provided that this notice and + * the following two paragraphs are included in any distribution of + * Refinement Analysis Tools or its derivative work, Regents agrees + * not to assert any of Regents' copyright rights in Refinement + * Analysis Tools against recipient for recipient's reproduction, + * preparation of derivative works, public display, public + * performance, distribution or sublicensing of Refinement Analysis + * Tools and derivative works, in source code and object code form. + * This agreement not to assert does not confer, by implication, + * estoppel, or otherwise any license or rights in any intellectual + * property of Regents, including, but not limited to, any patents + * of Regents or Regents' employees. + * + * IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, + * INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, + * INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE + * AND ITS DOCUMENTATION, EVEN IF REGENTS HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE AND FURTHER DISCLAIMS ANY STATUTORY + * WARRANTY OF NON-INFRINGEMENT. THE SOFTWARE AND ACCOMPANYING + * DOCUMENTATION, IF ANY, PROVIDED HEREUNDER IS PROVIDED "AS + * IS". REGENTS HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, + * UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + */ +package com.ibm.wala.demandpa.alg; + +import com.ibm.wala.demandpa.alg.statemachine.StateMachine; +import com.ibm.wala.demandpa.alg.statemachine.StateMachineFactory; +import com.ibm.wala.demandpa.flowgraph.AbstractFlowLabelVisitor; +import com.ibm.wala.demandpa.flowgraph.IFlowLabel; +import com.ibm.wala.demandpa.flowgraph.ParamBarLabel; +import com.ibm.wala.demandpa.flowgraph.ParamLabel; +import com.ibm.wala.demandpa.flowgraph.ReturnBarLabel; +import com.ibm.wala.demandpa.flowgraph.ReturnLabel; + +/** + * State machine that only allows intraprocedural paths. Mainly for testing + * purposes. + * + * @author Manu Sridharan + * + */ +public class IntraProcFilter implements StateMachine { + + private static final State DUMMY = new State() { + }; + + public State getStartState() { + return DUMMY; + } + + private static class InterprocFilterVisitor extends AbstractFlowLabelVisitor { + @Override + public void visitParamBar(ParamBarLabel label, Object dst) { + interprocEdge = true; + } + + @Override + public void visitParam(ParamLabel label, Object dst) { + interprocEdge = true; + } + + @Override + public void visitReturn(ReturnLabel label, Object dst) { + interprocEdge = true; + } + + @Override + public void visitReturnBar(ReturnBarLabel label, Object dst) { + interprocEdge = true; + } + + boolean interprocEdge = false; + + } + + public State transition(State prevState, IFlowLabel label) throws IllegalArgumentException { + if (label == null) { + throw new IllegalArgumentException("label == null"); + } + // filter out all interprocedural edges + InterprocFilterVisitor v = new InterprocFilterVisitor(); + label.visit(v, null); + return v.interprocEdge ? ERROR : DUMMY; + } + + private IntraProcFilter() { + } + + public static class Factory implements StateMachineFactory { + + public StateMachine make() { + return new IntraProcFilter(); + } + + } +} diff --git a/com.ibm.wala.core/src/com/ibm/wala/demandpa/alg/PointerKeyAndState.java b/com.ibm.wala.core/src/com/ibm/wala/demandpa/alg/PointerKeyAndState.java index c02cfdf2f..25a26761d 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/demandpa/alg/PointerKeyAndState.java +++ b/com.ibm.wala.core/src/com/ibm/wala/demandpa/alg/PointerKeyAndState.java @@ -1,59 +1,59 @@ -/******************************************************************************* - * 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. - * - * This file is a derivative of code released by the University of - * California under the terms listed below. - * - * Refinement Analysis Tools is Copyright (c) 2007 The Regents of the - * University of California (Regents). Provided that this notice and - * the following two paragraphs are included in any distribution of - * Refinement Analysis Tools or its derivative work, Regents agrees - * not to assert any of Regents' copyright rights in Refinement - * Analysis Tools against recipient for recipient's reproduction, - * preparation of derivative works, public display, public - * performance, distribution or sublicensing of Refinement Analysis - * Tools and derivative works, in source code and object code form. - * This agreement not to assert does not confer, by implication, - * estoppel, or otherwise any license or rights in any intellectual - * property of Regents, including, but not limited to, any patents - * of Regents or Regents' employees. - * - * IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, - * INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, - * INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE - * AND ITS DOCUMENTATION, EVEN IF REGENTS HAS BEEN ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE AND FURTHER DISCLAIMS ANY STATUTORY - * WARRANTY OF NON-INFRINGEMENT. THE SOFTWARE AND ACCOMPANYING - * DOCUMENTATION, IF ANY, PROVIDED HEREUNDER IS PROVIDED "AS - * IS". REGENTS HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, - * UPDATES, ENHANCEMENTS, OR MODIFICATIONS. - */ -package com.ibm.wala.demandpa.alg; - - -import com.ibm.wala.demandpa.alg.statemachine.StateMachine.State; -import com.ibm.wala.ipa.callgraph.propagation.PointerKey; - - - -/** - * @author Manu Sridharan - * - */ -public class PointerKeyAndState extends WithState { - - public PointerKeyAndState(PointerKey pk, State state) { - super(pk, state); - } - - public PointerKey getPointerKey() { - return getWrapped(); - } -} +/******************************************************************************* + * 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. + * + * This file is a derivative of code released by the University of + * California under the terms listed below. + * + * Refinement Analysis Tools is Copyright (c) 2007 The Regents of the + * University of California (Regents). Provided that this notice and + * the following two paragraphs are included in any distribution of + * Refinement Analysis Tools or its derivative work, Regents agrees + * not to assert any of Regents' copyright rights in Refinement + * Analysis Tools against recipient for recipient's reproduction, + * preparation of derivative works, public display, public + * performance, distribution or sublicensing of Refinement Analysis + * Tools and derivative works, in source code and object code form. + * This agreement not to assert does not confer, by implication, + * estoppel, or otherwise any license or rights in any intellectual + * property of Regents, including, but not limited to, any patents + * of Regents or Regents' employees. + * + * IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, + * INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, + * INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE + * AND ITS DOCUMENTATION, EVEN IF REGENTS HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE AND FURTHER DISCLAIMS ANY STATUTORY + * WARRANTY OF NON-INFRINGEMENT. THE SOFTWARE AND ACCOMPANYING + * DOCUMENTATION, IF ANY, PROVIDED HEREUNDER IS PROVIDED "AS + * IS". REGENTS HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, + * UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + */ +package com.ibm.wala.demandpa.alg; + + +import com.ibm.wala.demandpa.alg.statemachine.StateMachine.State; +import com.ibm.wala.ipa.callgraph.propagation.PointerKey; + + + +/** + * @author Manu Sridharan + * + */ +public class PointerKeyAndState extends WithState { + + public PointerKeyAndState(PointerKey pk, State state) { + super(pk, state); + } + + public PointerKey getPointerKey() { + return getWrapped(); + } +} diff --git a/com.ibm.wala.core/src/com/ibm/wala/demandpa/alg/SimpleDemandPointsTo.java b/com.ibm.wala.core/src/com/ibm/wala/demandpa/alg/SimpleDemandPointsTo.java index b58abf399..6d245a4a3 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/demandpa/alg/SimpleDemandPointsTo.java +++ b/com.ibm.wala.core/src/com/ibm/wala/demandpa/alg/SimpleDemandPointsTo.java @@ -1,106 +1,106 @@ -/******************************************************************************* - * 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. - * - * This file is a derivative of code released by the University of - * California under the terms listed below. - * - * Refinement Analysis Tools is Copyright (c) 2007 The Regents of the - * University of California (Regents). Provided that this notice and - * the following two paragraphs are included in any distribution of - * Refinement Analysis Tools or its derivative work, Regents agrees - * not to assert any of Regents' copyright rights in Refinement - * Analysis Tools against recipient for recipient's reproduction, - * preparation of derivative works, public display, public - * performance, distribution or sublicensing of Refinement Analysis - * Tools and derivative works, in source code and object code form. - * This agreement not to assert does not confer, by implication, - * estoppel, or otherwise any license or rights in any intellectual - * property of Regents, including, but not limited to, any patents - * of Regents or Regents' employees. - * - * IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, - * INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, - * INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE - * AND ITS DOCUMENTATION, EVEN IF REGENTS HAS BEEN ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE AND FURTHER DISCLAIMS ANY STATUTORY - * WARRANTY OF NON-INFRINGEMENT. THE SOFTWARE AND ACCOMPANYING - * DOCUMENTATION, IF ANY, PROVIDED HEREUNDER IS PROVIDED "AS - * IS". REGENTS HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, - * UPDATES, ENHANCEMENTS, OR MODIFICATIONS. - */ -package com.ibm.wala.demandpa.alg; - -import java.util.Collection; -import java.util.Collections; - -import com.ibm.wala.demandpa.flowgraph.SimpleDemandPointerFlowGraph; -import com.ibm.wala.demandpa.util.MemoryAccessMap; -import com.ibm.wala.ipa.callgraph.AnalysisOptions; -import com.ibm.wala.ipa.callgraph.CGNode; -import com.ibm.wala.ipa.callgraph.CallGraph; -import com.ibm.wala.ipa.callgraph.propagation.HeapModel; -import com.ibm.wala.ipa.callgraph.propagation.InstanceKey; -import com.ibm.wala.ipa.callgraph.propagation.LocalPointerKey; -import com.ibm.wala.ipa.callgraph.propagation.PointerKey; -import com.ibm.wala.ipa.cha.IClassHierarchy; -import com.ibm.wala.util.Predicate; -import com.ibm.wala.util.debug.UnimplementedError; -import com.ibm.wala.util.graph.traverse.SlowDFSDiscoverTimeIterator; - -/** - * Purely field-based, context-insensitive demand-driven points-to analysis with - * very simple implementation. - * - * @author Manu Sridharan - * - */ -public class SimpleDemandPointsTo extends AbstractDemandPointsTo { - - private static final boolean VERBOSE = false; - - public SimpleDemandPointsTo(CallGraph cg, HeapModel model, MemoryAccessMap fam, IClassHierarchy cha, AnalysisOptions options) { - super(cg, model, fam, cha, options); - } - - @SuppressWarnings("unchecked") - public Collection getPointsTo(PointerKey pk) throws IllegalArgumentException, UnimplementedError { - - if (pk == null) { - throw new IllegalArgumentException("pk == null"); - } - assert pk instanceof LocalPointerKey : "we only handle locals"; - LocalPointerKey lpk = (LocalPointerKey) pk; - // Create an (initially empty) dependence graph - SimpleDemandPointerFlowGraph g = new SimpleDemandPointerFlowGraph(cg, heapModel, mam, cha); - - // initialize the graph with the subgraph of x's method - CGNode node = lpk.getNode(); - g.addSubgraphForNode(node); - - if (!g.containsNode(pk)) { - return Collections.emptySet(); - } - - if (VERBOSE) { - System.err.println(g.toString()); - } - - Predicate iKeyFilter = new Predicate() { - @Override - public boolean test(Object o) { - return o instanceof InstanceKey; - } - }; - - SlowDFSDiscoverTimeIterator dfs = new SlowDFSDiscoverTimeIterator(g, pk); - return Predicate.filter(dfs, iKeyFilter); - } - -} +/******************************************************************************* + * 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. + * + * This file is a derivative of code released by the University of + * California under the terms listed below. + * + * Refinement Analysis Tools is Copyright (c) 2007 The Regents of the + * University of California (Regents). Provided that this notice and + * the following two paragraphs are included in any distribution of + * Refinement Analysis Tools or its derivative work, Regents agrees + * not to assert any of Regents' copyright rights in Refinement + * Analysis Tools against recipient for recipient's reproduction, + * preparation of derivative works, public display, public + * performance, distribution or sublicensing of Refinement Analysis + * Tools and derivative works, in source code and object code form. + * This agreement not to assert does not confer, by implication, + * estoppel, or otherwise any license or rights in any intellectual + * property of Regents, including, but not limited to, any patents + * of Regents or Regents' employees. + * + * IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, + * INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, + * INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE + * AND ITS DOCUMENTATION, EVEN IF REGENTS HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE AND FURTHER DISCLAIMS ANY STATUTORY + * WARRANTY OF NON-INFRINGEMENT. THE SOFTWARE AND ACCOMPANYING + * DOCUMENTATION, IF ANY, PROVIDED HEREUNDER IS PROVIDED "AS + * IS". REGENTS HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, + * UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + */ +package com.ibm.wala.demandpa.alg; + +import java.util.Collection; +import java.util.Collections; + +import com.ibm.wala.demandpa.flowgraph.SimpleDemandPointerFlowGraph; +import com.ibm.wala.demandpa.util.MemoryAccessMap; +import com.ibm.wala.ipa.callgraph.AnalysisOptions; +import com.ibm.wala.ipa.callgraph.CGNode; +import com.ibm.wala.ipa.callgraph.CallGraph; +import com.ibm.wala.ipa.callgraph.propagation.HeapModel; +import com.ibm.wala.ipa.callgraph.propagation.InstanceKey; +import com.ibm.wala.ipa.callgraph.propagation.LocalPointerKey; +import com.ibm.wala.ipa.callgraph.propagation.PointerKey; +import com.ibm.wala.ipa.cha.IClassHierarchy; +import com.ibm.wala.util.Predicate; +import com.ibm.wala.util.debug.UnimplementedError; +import com.ibm.wala.util.graph.traverse.SlowDFSDiscoverTimeIterator; + +/** + * Purely field-based, context-insensitive demand-driven points-to analysis with + * very simple implementation. + * + * @author Manu Sridharan + * + */ +public class SimpleDemandPointsTo extends AbstractDemandPointsTo { + + private static final boolean VERBOSE = false; + + public SimpleDemandPointsTo(CallGraph cg, HeapModel model, MemoryAccessMap fam, IClassHierarchy cha, AnalysisOptions options) { + super(cg, model, fam, cha, options); + } + + @SuppressWarnings("unchecked") + public Collection getPointsTo(PointerKey pk) throws IllegalArgumentException, UnimplementedError { + + if (pk == null) { + throw new IllegalArgumentException("pk == null"); + } + assert pk instanceof LocalPointerKey : "we only handle locals"; + LocalPointerKey lpk = (LocalPointerKey) pk; + // Create an (initially empty) dependence graph + SimpleDemandPointerFlowGraph g = new SimpleDemandPointerFlowGraph(cg, heapModel, mam, cha); + + // initialize the graph with the subgraph of x's method + CGNode node = lpk.getNode(); + g.addSubgraphForNode(node); + + if (!g.containsNode(pk)) { + return Collections.emptySet(); + } + + if (VERBOSE) { + System.err.println(g.toString()); + } + + Predicate iKeyFilter = new Predicate() { + @Override + public boolean test(Object o) { + return o instanceof InstanceKey; + } + }; + + SlowDFSDiscoverTimeIterator dfs = new SlowDFSDiscoverTimeIterator(g, pk); + return Predicate.filter(dfs, iKeyFilter); + } + +} diff --git a/com.ibm.wala.core/src/com/ibm/wala/demandpa/alg/WithState.java b/com.ibm.wala.core/src/com/ibm/wala/demandpa/alg/WithState.java index 14bde5570..8d7265ce0 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/demandpa/alg/WithState.java +++ b/com.ibm.wala.core/src/com/ibm/wala/demandpa/alg/WithState.java @@ -1,105 +1,105 @@ -/******************************************************************************* - * 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. - * - * This file is a derivative of code released by the University of - * California under the terms listed below. - * - * Refinement Analysis Tools is Copyright (c) 2007 The Regents of the - * University of California (Regents). Provided that this notice and - * the following two paragraphs are included in any distribution of - * Refinement Analysis Tools or its derivative work, Regents agrees - * not to assert any of Regents' copyright rights in Refinement - * Analysis Tools against recipient for recipient's reproduction, - * preparation of derivative works, public display, public - * performance, distribution or sublicensing of Refinement Analysis - * Tools and derivative works, in source code and object code form. - * This agreement not to assert does not confer, by implication, - * estoppel, or otherwise any license or rights in any intellectual - * property of Regents, including, but not limited to, any patents - * of Regents or Regents' employees. - * - * IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, - * INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, - * INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE - * AND ITS DOCUMENTATION, EVEN IF REGENTS HAS BEEN ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE AND FURTHER DISCLAIMS ANY STATUTORY - * WARRANTY OF NON-INFRINGEMENT. THE SOFTWARE AND ACCOMPANYING - * DOCUMENTATION, IF ANY, PROVIDED HEREUNDER IS PROVIDED "AS - * IS". REGENTS HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, - * UPDATES, ENHANCEMENTS, OR MODIFICATIONS. - */ -package com.ibm.wala.demandpa.alg; - -import com.ibm.wala.demandpa.alg.statemachine.StateMachine.State; - -/** - * Simple abstraction for pairing some type with a {@link State}. - */ -public abstract class WithState { - - private final T wrapped; - - private final State state; - - private final int hc; - - public WithState(final T wrapped, final State state) { - if (wrapped == null) { - throw new IllegalArgumentException("null wrapped"); - } - if (state == null) { - throw new IllegalArgumentException("null state"); - } - this.wrapped = wrapped; - this.state = state; - this.hc = 31 * state.hashCode() + wrapped.hashCode(); - } - - public State getState() { - return state; - } - - public T getWrapped() { - return wrapped; - } - - @Override - public String toString() { - return wrapped + ", STATE " + state; - } - - @Override - public int hashCode() { - return hc; - } - - @SuppressWarnings("unchecked") - @Override - public boolean equals(Object obj) { - if (this == obj) - return true; - if (obj == null) - return false; - if (getClass() != obj.getClass()) - return false; - final WithState other = (WithState) obj; - if (state == null) { - if (other.state != null) - return false; - } else if (!state.equals(other.state)) - return false; - if (wrapped == null) { - if (other.wrapped != null) - return false; - } else if (!wrapped.equals(other.wrapped)) - return false; - return true; - } -} +/******************************************************************************* + * 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. + * + * This file is a derivative of code released by the University of + * California under the terms listed below. + * + * Refinement Analysis Tools is Copyright (c) 2007 The Regents of the + * University of California (Regents). Provided that this notice and + * the following two paragraphs are included in any distribution of + * Refinement Analysis Tools or its derivative work, Regents agrees + * not to assert any of Regents' copyright rights in Refinement + * Analysis Tools against recipient for recipient's reproduction, + * preparation of derivative works, public display, public + * performance, distribution or sublicensing of Refinement Analysis + * Tools and derivative works, in source code and object code form. + * This agreement not to assert does not confer, by implication, + * estoppel, or otherwise any license or rights in any intellectual + * property of Regents, including, but not limited to, any patents + * of Regents or Regents' employees. + * + * IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, + * INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, + * INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE + * AND ITS DOCUMENTATION, EVEN IF REGENTS HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE AND FURTHER DISCLAIMS ANY STATUTORY + * WARRANTY OF NON-INFRINGEMENT. THE SOFTWARE AND ACCOMPANYING + * DOCUMENTATION, IF ANY, PROVIDED HEREUNDER IS PROVIDED "AS + * IS". REGENTS HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, + * UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + */ +package com.ibm.wala.demandpa.alg; + +import com.ibm.wala.demandpa.alg.statemachine.StateMachine.State; + +/** + * Simple abstraction for pairing some type with a {@link State}. + */ +public abstract class WithState { + + private final T wrapped; + + private final State state; + + private final int hc; + + public WithState(final T wrapped, final State state) { + if (wrapped == null) { + throw new IllegalArgumentException("null wrapped"); + } + if (state == null) { + throw new IllegalArgumentException("null state"); + } + this.wrapped = wrapped; + this.state = state; + this.hc = 31 * state.hashCode() + wrapped.hashCode(); + } + + public State getState() { + return state; + } + + public T getWrapped() { + return wrapped; + } + + @Override + public String toString() { + return wrapped + ", STATE " + state; + } + + @Override + public int hashCode() { + return hc; + } + + @SuppressWarnings("unchecked") + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + final WithState other = (WithState) obj; + if (state == null) { + if (other.state != null) + return false; + } else if (!state.equals(other.state)) + return false; + if (wrapped == null) { + if (other.wrapped != null) + return false; + } else if (!wrapped.equals(other.wrapped)) + return false; + return true; + } +} diff --git a/com.ibm.wala.core/src/com/ibm/wala/demandpa/alg/refinepolicy/AlwaysRefineCGPolicy.java b/com.ibm.wala.core/src/com/ibm/wala/demandpa/alg/refinepolicy/AlwaysRefineCGPolicy.java index 2dd52be0b..05faaa6c0 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/demandpa/alg/refinepolicy/AlwaysRefineCGPolicy.java +++ b/com.ibm.wala.core/src/com/ibm/wala/demandpa/alg/refinepolicy/AlwaysRefineCGPolicy.java @@ -1,55 +1,55 @@ -/******************************************************************************* - * 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. - * - * This file is a derivative of code released by the University of - * California under the terms listed below. - * - * Refinement Analysis Tools is Copyright (c) 2007 The Regents of the - * University of California (Regents). Provided that this notice and - * the following two paragraphs are included in any distribution of - * Refinement Analysis Tools or its derivative work, Regents agrees - * not to assert any of Regents' copyright rights in Refinement - * Analysis Tools against recipient for recipient's reproduction, - * preparation of derivative works, public display, public - * performance, distribution or sublicensing of Refinement Analysis - * Tools and derivative works, in source code and object code form. - * This agreement not to assert does not confer, by implication, - * estoppel, or otherwise any license or rights in any intellectual - * property of Regents, including, but not limited to, any patents - * of Regents or Regents' employees. - * - * IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, - * INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, - * INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE - * AND ITS DOCUMENTATION, EVEN IF REGENTS HAS BEEN ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE AND FURTHER DISCLAIMS ANY STATUTORY - * WARRANTY OF NON-INFRINGEMENT. THE SOFTWARE AND ACCOMPANYING - * DOCUMENTATION, IF ANY, PROVIDED HEREUNDER IS PROVIDED "AS - * IS". REGENTS HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, - * UPDATES, ENHANCEMENTS, OR MODIFICATIONS. - */ -package com.ibm.wala.demandpa.alg.refinepolicy; - -import com.ibm.wala.ipa.callgraph.propagation.cfa.CallerSiteContext; - -/** - * A policy that always refines the call graph. - */ -public class AlwaysRefineCGPolicy implements CallGraphRefinePolicy { - - public boolean shouldRefine(CallerSiteContext callSiteAndCGNode) { - return true; - } - - public boolean nextPass() { - return false; - } - -} +/******************************************************************************* + * 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. + * + * This file is a derivative of code released by the University of + * California under the terms listed below. + * + * Refinement Analysis Tools is Copyright (c) 2007 The Regents of the + * University of California (Regents). Provided that this notice and + * the following two paragraphs are included in any distribution of + * Refinement Analysis Tools or its derivative work, Regents agrees + * not to assert any of Regents' copyright rights in Refinement + * Analysis Tools against recipient for recipient's reproduction, + * preparation of derivative works, public display, public + * performance, distribution or sublicensing of Refinement Analysis + * Tools and derivative works, in source code and object code form. + * This agreement not to assert does not confer, by implication, + * estoppel, or otherwise any license or rights in any intellectual + * property of Regents, including, but not limited to, any patents + * of Regents or Regents' employees. + * + * IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, + * INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, + * INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE + * AND ITS DOCUMENTATION, EVEN IF REGENTS HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE AND FURTHER DISCLAIMS ANY STATUTORY + * WARRANTY OF NON-INFRINGEMENT. THE SOFTWARE AND ACCOMPANYING + * DOCUMENTATION, IF ANY, PROVIDED HEREUNDER IS PROVIDED "AS + * IS". REGENTS HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, + * UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + */ +package com.ibm.wala.demandpa.alg.refinepolicy; + +import com.ibm.wala.ipa.callgraph.propagation.cfa.CallerSiteContext; + +/** + * A policy that always refines the call graph. + */ +public class AlwaysRefineCGPolicy implements CallGraphRefinePolicy { + + public boolean shouldRefine(CallerSiteContext callSiteAndCGNode) { + return true; + } + + public boolean nextPass() { + return false; + } + +} diff --git a/com.ibm.wala.core/src/com/ibm/wala/demandpa/alg/refinepolicy/AlwaysRefineFieldsPolicy.java b/com.ibm.wala.core/src/com/ibm/wala/demandpa/alg/refinepolicy/AlwaysRefineFieldsPolicy.java index 11315102e..43efd3747 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/demandpa/alg/refinepolicy/AlwaysRefineFieldsPolicy.java +++ b/com.ibm.wala.core/src/com/ibm/wala/demandpa/alg/refinepolicy/AlwaysRefineFieldsPolicy.java @@ -1,63 +1,63 @@ -/******************************************************************************* - * 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. - * - * This file is a derivative of code released by the University of - * California under the terms listed below. - * - * Refinement Analysis Tools is Copyright (c) 2007 The Regents of the - * University of California (Regents). Provided that this notice and - * the following two paragraphs are included in any distribution of - * Refinement Analysis Tools or its derivative work, Regents agrees - * not to assert any of Regents' copyright rights in Refinement - * Analysis Tools against recipient for recipient's reproduction, - * preparation of derivative works, public display, public - * performance, distribution or sublicensing of Refinement Analysis - * Tools and derivative works, in source code and object code form. - * This agreement not to assert does not confer, by implication, - * estoppel, or otherwise any license or rights in any intellectual - * property of Regents, including, but not limited to, any patents - * of Regents or Regents' employees. - * - * IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, - * INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, - * INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE - * AND ITS DOCUMENTATION, EVEN IF REGENTS HAS BEEN ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE AND FURTHER DISCLAIMS ANY STATUTORY - * WARRANTY OF NON-INFRINGEMENT. THE SOFTWARE AND ACCOMPANYING - * DOCUMENTATION, IF ANY, PROVIDED HEREUNDER IS PROVIDED "AS - * IS". REGENTS HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, - * UPDATES, ENHANCEMENTS, OR MODIFICATIONS. - */ - -package com.ibm.wala.demandpa.alg.refinepolicy; - -import com.ibm.wala.classLoader.IField; -import com.ibm.wala.demandpa.alg.statemachine.StateMachine; -import com.ibm.wala.demandpa.flowgraph.IFlowLabel; -import com.ibm.wala.ipa.callgraph.propagation.PointerKey; - -/** - * A policy that always refines handling of field accesses by checking for an - * alias path corresponding to each match edge. - * - * @author Manu Sridharan - * - */ -public class AlwaysRefineFieldsPolicy implements FieldRefinePolicy { - - public boolean shouldRefine(IField field, PointerKey basePtr, PointerKey val, IFlowLabel label, StateMachine.State state) { - return true; - } - - public boolean nextPass() { - return false; - } - -} +/******************************************************************************* + * 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. + * + * This file is a derivative of code released by the University of + * California under the terms listed below. + * + * Refinement Analysis Tools is Copyright (c) 2007 The Regents of the + * University of California (Regents). Provided that this notice and + * the following two paragraphs are included in any distribution of + * Refinement Analysis Tools or its derivative work, Regents agrees + * not to assert any of Regents' copyright rights in Refinement + * Analysis Tools against recipient for recipient's reproduction, + * preparation of derivative works, public display, public + * performance, distribution or sublicensing of Refinement Analysis + * Tools and derivative works, in source code and object code form. + * This agreement not to assert does not confer, by implication, + * estoppel, or otherwise any license or rights in any intellectual + * property of Regents, including, but not limited to, any patents + * of Regents or Regents' employees. + * + * IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, + * INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, + * INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE + * AND ITS DOCUMENTATION, EVEN IF REGENTS HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE AND FURTHER DISCLAIMS ANY STATUTORY + * WARRANTY OF NON-INFRINGEMENT. THE SOFTWARE AND ACCOMPANYING + * DOCUMENTATION, IF ANY, PROVIDED HEREUNDER IS PROVIDED "AS + * IS". REGENTS HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, + * UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + */ + +package com.ibm.wala.demandpa.alg.refinepolicy; + +import com.ibm.wala.classLoader.IField; +import com.ibm.wala.demandpa.alg.statemachine.StateMachine; +import com.ibm.wala.demandpa.flowgraph.IFlowLabel; +import com.ibm.wala.ipa.callgraph.propagation.PointerKey; + +/** + * A policy that always refines handling of field accesses by checking for an + * alias path corresponding to each match edge. + * + * @author Manu Sridharan + * + */ +public class AlwaysRefineFieldsPolicy implements FieldRefinePolicy { + + public boolean shouldRefine(IField field, PointerKey basePtr, PointerKey val, IFlowLabel label, StateMachine.State state) { + return true; + } + + public boolean nextPass() { + return false; + } + +} diff --git a/com.ibm.wala.core/src/com/ibm/wala/demandpa/alg/refinepolicy/CallGraphRefinePolicy.java b/com.ibm.wala.core/src/com/ibm/wala/demandpa/alg/refinepolicy/CallGraphRefinePolicy.java index da135dfe8..7e011cfc9 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/demandpa/alg/refinepolicy/CallGraphRefinePolicy.java +++ b/com.ibm.wala.core/src/com/ibm/wala/demandpa/alg/refinepolicy/CallGraphRefinePolicy.java @@ -1,59 +1,59 @@ -/******************************************************************************* - * 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. - * - * This file is a derivative of code released by the University of - * California under the terms listed below. - * - * Refinement Analysis Tools is Copyright (c) 2007 The Regents of the - * University of California (Regents). Provided that this notice and - * the following two paragraphs are included in any distribution of - * Refinement Analysis Tools or its derivative work, Regents agrees - * not to assert any of Regents' copyright rights in Refinement - * Analysis Tools against recipient for recipient's reproduction, - * preparation of derivative works, public display, public - * performance, distribution or sublicensing of Refinement Analysis - * Tools and derivative works, in source code and object code form. - * This agreement not to assert does not confer, by implication, - * estoppel, or otherwise any license or rights in any intellectual - * property of Regents, including, but not limited to, any patents - * of Regents or Regents' employees. - * - * IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, - * INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, - * INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE - * AND ITS DOCUMENTATION, EVEN IF REGENTS HAS BEEN ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE AND FURTHER DISCLAIMS ANY STATUTORY - * WARRANTY OF NON-INFRINGEMENT. THE SOFTWARE AND ACCOMPANYING - * DOCUMENTATION, IF ANY, PROVIDED HEREUNDER IS PROVIDED "AS - * IS". REGENTS HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, - * UPDATES, ENHANCEMENTS, OR MODIFICATIONS. - */ -package com.ibm.wala.demandpa.alg.refinepolicy; - -import com.ibm.wala.ipa.callgraph.propagation.cfa.CallerSiteContext; - -/** - * Interface for specifying a policy for refining the call graph. - */ -public interface CallGraphRefinePolicy { - - /** - * @param callSiteAndCGNode - * @return true if the analysis should attempt to determine targets for the virtual call on-the-fly, and - * false otherwise - */ - public boolean shouldRefine(CallerSiteContext callSiteAndCGNode); - - /** - * @return true if more refinement can be done, and hence another pass can be attempted; false otherwise - */ - public boolean nextPass(); - -} +/******************************************************************************* + * 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. + * + * This file is a derivative of code released by the University of + * California under the terms listed below. + * + * Refinement Analysis Tools is Copyright (c) 2007 The Regents of the + * University of California (Regents). Provided that this notice and + * the following two paragraphs are included in any distribution of + * Refinement Analysis Tools or its derivative work, Regents agrees + * not to assert any of Regents' copyright rights in Refinement + * Analysis Tools against recipient for recipient's reproduction, + * preparation of derivative works, public display, public + * performance, distribution or sublicensing of Refinement Analysis + * Tools and derivative works, in source code and object code form. + * This agreement not to assert does not confer, by implication, + * estoppel, or otherwise any license or rights in any intellectual + * property of Regents, including, but not limited to, any patents + * of Regents or Regents' employees. + * + * IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, + * INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, + * INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE + * AND ITS DOCUMENTATION, EVEN IF REGENTS HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE AND FURTHER DISCLAIMS ANY STATUTORY + * WARRANTY OF NON-INFRINGEMENT. THE SOFTWARE AND ACCOMPANYING + * DOCUMENTATION, IF ANY, PROVIDED HEREUNDER IS PROVIDED "AS + * IS". REGENTS HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, + * UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + */ +package com.ibm.wala.demandpa.alg.refinepolicy; + +import com.ibm.wala.ipa.callgraph.propagation.cfa.CallerSiteContext; + +/** + * Interface for specifying a policy for refining the call graph. + */ +public interface CallGraphRefinePolicy { + + /** + * @param callSiteAndCGNode + * @return true if the analysis should attempt to determine targets for the virtual call on-the-fly, and + * false otherwise + */ + public boolean shouldRefine(CallerSiteContext callSiteAndCGNode); + + /** + * @return true if more refinement can be done, and hence another pass can be attempted; false otherwise + */ + public boolean nextPass(); + +} diff --git a/com.ibm.wala.core/src/com/ibm/wala/demandpa/alg/refinepolicy/FieldRefinePolicy.java b/com.ibm.wala.core/src/com/ibm/wala/demandpa/alg/refinepolicy/FieldRefinePolicy.java index f438695da..3a031e71b 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/demandpa/alg/refinepolicy/FieldRefinePolicy.java +++ b/com.ibm.wala.core/src/com/ibm/wala/demandpa/alg/refinepolicy/FieldRefinePolicy.java @@ -1,71 +1,71 @@ -/******************************************************************************* - * 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. - * - * This file is a derivative of code released by the University of - * California under the terms listed below. - * - * Refinement Analysis Tools is Copyright (c) 2007 The Regents of the - * University of California (Regents). Provided that this notice and - * the following two paragraphs are included in any distribution of - * Refinement Analysis Tools or its derivative work, Regents agrees - * not to assert any of Regents' copyright rights in Refinement - * Analysis Tools against recipient for recipient's reproduction, - * preparation of derivative works, public display, public - * performance, distribution or sublicensing of Refinement Analysis - * Tools and derivative works, in source code and object code form. - * This agreement not to assert does not confer, by implication, - * estoppel, or otherwise any license or rights in any intellectual - * property of Regents, including, but not limited to, any patents - * of Regents or Regents' employees. - * - * IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, - * INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, - * INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE - * AND ITS DOCUMENTATION, EVEN IF REGENTS HAS BEEN ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE AND FURTHER DISCLAIMS ANY STATUTORY - * WARRANTY OF NON-INFRINGEMENT. THE SOFTWARE AND ACCOMPANYING - * DOCUMENTATION, IF ANY, PROVIDED HEREUNDER IS PROVIDED "AS - * IS". REGENTS HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, - * UPDATES, ENHANCEMENTS, OR MODIFICATIONS. - */ -package com.ibm.wala.demandpa.alg.refinepolicy; - -import com.ibm.wala.classLoader.IField; -import com.ibm.wala.demandpa.alg.statemachine.StateMachine; -import com.ibm.wala.demandpa.flowgraph.IFlowLabel; -import com.ibm.wala.ipa.callgraph.propagation.PointerKey; - -/** - * Interface for specifying a policy for refinement of field access handling. - * - * @author Manu Sridharan - * - */ -public interface FieldRefinePolicy { - - /** - * - * @param field the accessed field - * @param basePtr the base pointer of the access - * @param val - * @param state - * @return true if match edges for the field access should be refined. Otherwise, false - * is returned, indicating that the field can be handled with match edges. - */ - public boolean shouldRefine(IField field, PointerKey basePtr, PointerKey val, IFlowLabel label, StateMachine.State state); - - /** - * - * @return true if more refinement can be done, and hence another pass can be attempted; - * false otherwise - */ - public boolean nextPass(); - -} +/******************************************************************************* + * 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. + * + * This file is a derivative of code released by the University of + * California under the terms listed below. + * + * Refinement Analysis Tools is Copyright (c) 2007 The Regents of the + * University of California (Regents). Provided that this notice and + * the following two paragraphs are included in any distribution of + * Refinement Analysis Tools or its derivative work, Regents agrees + * not to assert any of Regents' copyright rights in Refinement + * Analysis Tools against recipient for recipient's reproduction, + * preparation of derivative works, public display, public + * performance, distribution or sublicensing of Refinement Analysis + * Tools and derivative works, in source code and object code form. + * This agreement not to assert does not confer, by implication, + * estoppel, or otherwise any license or rights in any intellectual + * property of Regents, including, but not limited to, any patents + * of Regents or Regents' employees. + * + * IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, + * INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, + * INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE + * AND ITS DOCUMENTATION, EVEN IF REGENTS HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE AND FURTHER DISCLAIMS ANY STATUTORY + * WARRANTY OF NON-INFRINGEMENT. THE SOFTWARE AND ACCOMPANYING + * DOCUMENTATION, IF ANY, PROVIDED HEREUNDER IS PROVIDED "AS + * IS". REGENTS HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, + * UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + */ +package com.ibm.wala.demandpa.alg.refinepolicy; + +import com.ibm.wala.classLoader.IField; +import com.ibm.wala.demandpa.alg.statemachine.StateMachine; +import com.ibm.wala.demandpa.flowgraph.IFlowLabel; +import com.ibm.wala.ipa.callgraph.propagation.PointerKey; + +/** + * Interface for specifying a policy for refinement of field access handling. + * + * @author Manu Sridharan + * + */ +public interface FieldRefinePolicy { + + /** + * + * @param field the accessed field + * @param basePtr the base pointer of the access + * @param val + * @param state + * @return true if match edges for the field access should be refined. Otherwise, false + * is returned, indicating that the field can be handled with match edges. + */ + public boolean shouldRefine(IField field, PointerKey basePtr, PointerKey val, IFlowLabel label, StateMachine.State state); + + /** + * + * @return true if more refinement can be done, and hence another pass can be attempted; + * false otherwise + */ + public boolean nextPass(); + +} diff --git a/com.ibm.wala.core/src/com/ibm/wala/demandpa/alg/refinepolicy/ManualCGRefinePolicy.java b/com.ibm.wala.core/src/com/ibm/wala/demandpa/alg/refinepolicy/ManualCGRefinePolicy.java index d5a066ddd..bb6e79014 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/demandpa/alg/refinepolicy/ManualCGRefinePolicy.java +++ b/com.ibm.wala.core/src/com/ibm/wala/demandpa/alg/refinepolicy/ManualCGRefinePolicy.java @@ -1,66 +1,66 @@ -/******************************************************************************* - * 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. - * - * This file is a derivative of code released by the University of - * California under the terms listed below. - * - * Refinement Analysis Tools is Copyright (c) 2007 The Regents of the - * University of California (Regents). Provided that this notice and - * the following two paragraphs are included in any distribution of - * Refinement Analysis Tools or its derivative work, Regents agrees - * not to assert any of Regents' copyright rights in Refinement - * Analysis Tools against recipient for recipient's reproduction, - * preparation of derivative works, public display, public - * performance, distribution or sublicensing of Refinement Analysis - * Tools and derivative works, in source code and object code form. - * This agreement not to assert does not confer, by implication, - * estoppel, or otherwise any license or rights in any intellectual - * property of Regents, including, but not limited to, any patents - * of Regents or Regents' employees. - * - * IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, - * INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, - * INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE - * AND ITS DOCUMENTATION, EVEN IF REGENTS HAS BEEN ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE AND FURTHER DISCLAIMS ANY STATUTORY - * WARRANTY OF NON-INFRINGEMENT. THE SOFTWARE AND ACCOMPANYING - * DOCUMENTATION, IF ANY, PROVIDED HEREUNDER IS PROVIDED "AS - * IS". REGENTS HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, - * UPDATES, ENHANCEMENTS, OR MODIFICATIONS. - */ -package com.ibm.wala.demandpa.alg.refinepolicy; - -import com.ibm.wala.ipa.callgraph.propagation.cfa.CallerSiteContext; -import com.ibm.wala.types.MethodReference; - -/** - * A call graph refinement policy with manual annotations for which - * virtual call sites to refine. - * - */ -public class ManualCGRefinePolicy implements CallGraphRefinePolicy { - - public boolean shouldRefine(CallerSiteContext callSiteAndCGNode) throws IllegalArgumentException { - if (callSiteAndCGNode == null) { - throw new IllegalArgumentException("callSiteAndCGNode == null"); - } - MethodReference declaredTarget = callSiteAndCGNode.getCallSite().getDeclaredTarget(); - if (declaredTarget.toString().indexOf("toString()Ljava/lang/String") != -1) { - return false; - } - return true; - } - - public boolean nextPass() { - return false; - } - - -} +/******************************************************************************* + * 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. + * + * This file is a derivative of code released by the University of + * California under the terms listed below. + * + * Refinement Analysis Tools is Copyright (c) 2007 The Regents of the + * University of California (Regents). Provided that this notice and + * the following two paragraphs are included in any distribution of + * Refinement Analysis Tools or its derivative work, Regents agrees + * not to assert any of Regents' copyright rights in Refinement + * Analysis Tools against recipient for recipient's reproduction, + * preparation of derivative works, public display, public + * performance, distribution or sublicensing of Refinement Analysis + * Tools and derivative works, in source code and object code form. + * This agreement not to assert does not confer, by implication, + * estoppel, or otherwise any license or rights in any intellectual + * property of Regents, including, but not limited to, any patents + * of Regents or Regents' employees. + * + * IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, + * INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, + * INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE + * AND ITS DOCUMENTATION, EVEN IF REGENTS HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE AND FURTHER DISCLAIMS ANY STATUTORY + * WARRANTY OF NON-INFRINGEMENT. THE SOFTWARE AND ACCOMPANYING + * DOCUMENTATION, IF ANY, PROVIDED HEREUNDER IS PROVIDED "AS + * IS". REGENTS HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, + * UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + */ +package com.ibm.wala.demandpa.alg.refinepolicy; + +import com.ibm.wala.ipa.callgraph.propagation.cfa.CallerSiteContext; +import com.ibm.wala.types.MethodReference; + +/** + * A call graph refinement policy with manual annotations for which + * virtual call sites to refine. + * + */ +public class ManualCGRefinePolicy implements CallGraphRefinePolicy { + + public boolean shouldRefine(CallerSiteContext callSiteAndCGNode) throws IllegalArgumentException { + if (callSiteAndCGNode == null) { + throw new IllegalArgumentException("callSiteAndCGNode == null"); + } + MethodReference declaredTarget = callSiteAndCGNode.getCallSite().getDeclaredTarget(); + if (declaredTarget.toString().indexOf("toString()Ljava/lang/String") != -1) { + return false; + } + return true; + } + + public boolean nextPass() { + return false; + } + + +} diff --git a/com.ibm.wala.core/src/com/ibm/wala/demandpa/alg/refinepolicy/ManualFieldPolicy.java b/com.ibm.wala.core/src/com/ibm/wala/demandpa/alg/refinepolicy/ManualFieldPolicy.java index fa2c50231..63f7aeb14 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/demandpa/alg/refinepolicy/ManualFieldPolicy.java +++ b/com.ibm.wala.core/src/com/ibm/wala/demandpa/alg/refinepolicy/ManualFieldPolicy.java @@ -1,160 +1,160 @@ -/******************************************************************************* - * 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. - * - * This file is a derivative of code released by the University of - * California under the terms listed below. - * - * Refinement Analysis Tools is Copyright (c) 2007 The Regents of the - * University of California (Regents). Provided that this notice and - * the following two paragraphs are included in any distribution of - * Refinement Analysis Tools or its derivative work, Regents agrees - * not to assert any of Regents' copyright rights in Refinement - * Analysis Tools against recipient for recipient's reproduction, - * preparation of derivative works, public display, public - * performance, distribution or sublicensing of Refinement Analysis - * Tools and derivative works, in source code and object code form. - * This agreement not to assert does not confer, by implication, - * estoppel, or otherwise any license or rights in any intellectual - * property of Regents, including, but not limited to, any patents - * of Regents or Regents' employees. - * - * IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, - * INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, - * INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE - * AND ITS DOCUMENTATION, EVEN IF REGENTS HAS BEEN ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE AND FURTHER DISCLAIMS ANY STATUTORY - * WARRANTY OF NON-INFRINGEMENT. THE SOFTWARE AND ACCOMPANYING - * DOCUMENTATION, IF ANY, PROVIDED HEREUNDER IS PROVIDED "AS - * IS". REGENTS HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, - * UPDATES, ENHANCEMENTS, OR MODIFICATIONS. - */ -package com.ibm.wala.demandpa.alg.refinepolicy; - -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -import com.ibm.wala.classLoader.IClass; -import com.ibm.wala.classLoader.IField; -import com.ibm.wala.demandpa.alg.statemachine.StateMachine; -import com.ibm.wala.demandpa.flowgraph.IFlowLabel; -import com.ibm.wala.demandpa.util.ArrayContents; -import com.ibm.wala.ipa.callgraph.propagation.PointerKey; -import com.ibm.wala.ipa.cha.IClassHierarchy; -import com.ibm.wala.types.ClassLoaderReference; -import com.ibm.wala.types.TypeReference; - -/** - * Manually annotated policy for refining field accesses. - */ -public class ManualFieldPolicy implements FieldRefinePolicy { - - protected final Pattern refinePattern;// = - - // Pattern.compile("Lca/mcgill/sable/util|Ljava/util|Lpolyglot/util/TypedList"); - - private static final int NUM_DECISIONS_TO_TRACK = 10; - - final private boolean[] decisions = new boolean[NUM_DECISIONS_TO_TRACK]; - - private int curDecision; - - final private IClass[] encounteredClasses = new IClass[NUM_DECISIONS_TO_TRACK]; - - public boolean shouldRefine(IField field, PointerKey basePtr, PointerKey val, IFlowLabel label, StateMachine.State state) { - if (field == null) { - throw new IllegalArgumentException("null field"); - } - if (field == ArrayContents.v()) { - return true; - } else { - final IClass declaringClass = field.getDeclaringClass(); - final Matcher m = refinePattern.matcher(declaringClass.toString()); - final boolean foundPattern = m.find(); - recordDecision(declaringClass, foundPattern); - return foundPattern; - } - } - - private void recordDecision(final IClass declaringClass, final boolean foundPattern) { - if (curDecision < NUM_DECISIONS_TO_TRACK) { - IClass topMostClass = removeInner(declaringClass); - if (notSuperOfAnyEncountered(topMostClass)) { - encounteredClasses[curDecision] = topMostClass; - decisions[curDecision] = foundPattern; - curDecision++; - } - } - } - - private boolean notSuperOfAnyEncountered(IClass klass) { - for (int i = 0; i < curDecision; i++) { - if (cha.isAssignableFrom(klass, encounteredClasses[i])) { - return false; - } - } - return true; - } - - private final IClassHierarchy cha; - - /** - * @return the top-level {@link IClass} where klass is declared, or klass itself if klass is top-level - */ - private IClass removeInner(IClass klass) { - ClassLoaderReference cl = klass.getClassLoader().getReference(); - String klassStr = klass.getName().toString(); - int dollarIndex = klassStr.indexOf('$'); - if (dollarIndex == -1) { - return klass; - } else { - String topMostName = klassStr.substring(0, dollarIndex); - IClass topMostClass = cha.lookupClass(TypeReference.findOrCreate(cl, topMostName)); - assert topMostClass != null; - return topMostClass; - } - } - - /** - * @param refinePattern a pattern for detecting which match edges to refine. If the declaring class of the field related - * to the match edge matches the pattern, the match edge will be refined. For example, the pattern - * Pattern.compile("Ljava/util") will cause all fields of classes in the java.util package to - * be refined. - */ - public ManualFieldPolicy(IClassHierarchy cha, Pattern refinePattern) { - this.cha = cha; - this.refinePattern = refinePattern; - } - - public boolean nextPass() { - return false; - } - - /** - * - * - * @return a String representation of the decisions made by this - */ - public String getHistory() { - StringBuilder ret = new StringBuilder(); - for (int i = 0; i < curDecision; i++) { - if (decisions[i]) { - ret.append("refined "); - } else { - ret.append("skipped "); - } - ret.append(encounteredClasses[i]); - if (i + 1 < curDecision) { - ret.append(", "); - } - } - return ret.toString(); - } - -} +/******************************************************************************* + * 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. + * + * This file is a derivative of code released by the University of + * California under the terms listed below. + * + * Refinement Analysis Tools is Copyright (c) 2007 The Regents of the + * University of California (Regents). Provided that this notice and + * the following two paragraphs are included in any distribution of + * Refinement Analysis Tools or its derivative work, Regents agrees + * not to assert any of Regents' copyright rights in Refinement + * Analysis Tools against recipient for recipient's reproduction, + * preparation of derivative works, public display, public + * performance, distribution or sublicensing of Refinement Analysis + * Tools and derivative works, in source code and object code form. + * This agreement not to assert does not confer, by implication, + * estoppel, or otherwise any license or rights in any intellectual + * property of Regents, including, but not limited to, any patents + * of Regents or Regents' employees. + * + * IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, + * INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, + * INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE + * AND ITS DOCUMENTATION, EVEN IF REGENTS HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE AND FURTHER DISCLAIMS ANY STATUTORY + * WARRANTY OF NON-INFRINGEMENT. THE SOFTWARE AND ACCOMPANYING + * DOCUMENTATION, IF ANY, PROVIDED HEREUNDER IS PROVIDED "AS + * IS". REGENTS HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, + * UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + */ +package com.ibm.wala.demandpa.alg.refinepolicy; + +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import com.ibm.wala.classLoader.IClass; +import com.ibm.wala.classLoader.IField; +import com.ibm.wala.demandpa.alg.statemachine.StateMachine; +import com.ibm.wala.demandpa.flowgraph.IFlowLabel; +import com.ibm.wala.demandpa.util.ArrayContents; +import com.ibm.wala.ipa.callgraph.propagation.PointerKey; +import com.ibm.wala.ipa.cha.IClassHierarchy; +import com.ibm.wala.types.ClassLoaderReference; +import com.ibm.wala.types.TypeReference; + +/** + * Manually annotated policy for refining field accesses. + */ +public class ManualFieldPolicy implements FieldRefinePolicy { + + protected final Pattern refinePattern;// = + + // Pattern.compile("Lca/mcgill/sable/util|Ljava/util|Lpolyglot/util/TypedList"); + + private static final int NUM_DECISIONS_TO_TRACK = 10; + + final private boolean[] decisions = new boolean[NUM_DECISIONS_TO_TRACK]; + + private int curDecision; + + final private IClass[] encounteredClasses = new IClass[NUM_DECISIONS_TO_TRACK]; + + public boolean shouldRefine(IField field, PointerKey basePtr, PointerKey val, IFlowLabel label, StateMachine.State state) { + if (field == null) { + throw new IllegalArgumentException("null field"); + } + if (field == ArrayContents.v()) { + return true; + } else { + final IClass declaringClass = field.getDeclaringClass(); + final Matcher m = refinePattern.matcher(declaringClass.toString()); + final boolean foundPattern = m.find(); + recordDecision(declaringClass, foundPattern); + return foundPattern; + } + } + + private void recordDecision(final IClass declaringClass, final boolean foundPattern) { + if (curDecision < NUM_DECISIONS_TO_TRACK) { + IClass topMostClass = removeInner(declaringClass); + if (notSuperOfAnyEncountered(topMostClass)) { + encounteredClasses[curDecision] = topMostClass; + decisions[curDecision] = foundPattern; + curDecision++; + } + } + } + + private boolean notSuperOfAnyEncountered(IClass klass) { + for (int i = 0; i < curDecision; i++) { + if (cha.isAssignableFrom(klass, encounteredClasses[i])) { + return false; + } + } + return true; + } + + private final IClassHierarchy cha; + + /** + * @return the top-level {@link IClass} where klass is declared, or klass itself if klass is top-level + */ + private IClass removeInner(IClass klass) { + ClassLoaderReference cl = klass.getClassLoader().getReference(); + String klassStr = klass.getName().toString(); + int dollarIndex = klassStr.indexOf('$'); + if (dollarIndex == -1) { + return klass; + } else { + String topMostName = klassStr.substring(0, dollarIndex); + IClass topMostClass = cha.lookupClass(TypeReference.findOrCreate(cl, topMostName)); + assert topMostClass != null; + return topMostClass; + } + } + + /** + * @param refinePattern a pattern for detecting which match edges to refine. If the declaring class of the field related + * to the match edge matches the pattern, the match edge will be refined. For example, the pattern + * Pattern.compile("Ljava/util") will cause all fields of classes in the java.util package to + * be refined. + */ + public ManualFieldPolicy(IClassHierarchy cha, Pattern refinePattern) { + this.cha = cha; + this.refinePattern = refinePattern; + } + + public boolean nextPass() { + return false; + } + + /** + * + * + * @return a String representation of the decisions made by this + */ + public String getHistory() { + StringBuilder ret = new StringBuilder(); + for (int i = 0; i < curDecision; i++) { + if (decisions[i]) { + ret.append("refined "); + } else { + ret.append("skipped "); + } + ret.append(encounteredClasses[i]); + if (i + 1 < curDecision) { + ret.append(", "); + } + } + return ret.toString(); + } + +} diff --git a/com.ibm.wala.core/src/com/ibm/wala/demandpa/alg/refinepolicy/ManualRefinementPolicy.java b/com.ibm.wala.core/src/com/ibm/wala/demandpa/alg/refinepolicy/ManualRefinementPolicy.java index db6746f74..970b00a04 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/demandpa/alg/refinepolicy/ManualRefinementPolicy.java +++ b/com.ibm.wala.core/src/com/ibm/wala/demandpa/alg/refinepolicy/ManualRefinementPolicy.java @@ -1,65 +1,65 @@ -/******************************************************************************* - * 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. - * - * This file is a derivative of code released by the University of - * California under the terms listed below. - * - * Refinement Analysis Tools is Copyright (c) 2007 The Regents of the - * University of California (Regents). Provided that this notice and - * the following two paragraphs are included in any distribution of - * Refinement Analysis Tools or its derivative work, Regents agrees - * not to assert any of Regents' copyright rights in Refinement - * Analysis Tools against recipient for recipient's reproduction, - * preparation of derivative works, public display, public - * performance, distribution or sublicensing of Refinement Analysis - * Tools and derivative works, in source code and object code form. - * This agreement not to assert does not confer, by implication, - * estoppel, or otherwise any license or rights in any intellectual - * property of Regents, including, but not limited to, any patents - * of Regents or Regents' employees. - * - * IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, - * INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, - * INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE - * AND ITS DOCUMENTATION, EVEN IF REGENTS HAS BEEN ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE AND FURTHER DISCLAIMS ANY STATUTORY - * WARRANTY OF NON-INFRINGEMENT. THE SOFTWARE AND ACCOMPANYING - * DOCUMENTATION, IF ANY, PROVIDED HEREUNDER IS PROVIDED "AS - * IS". REGENTS HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, - * UPDATES, ENHANCEMENTS, OR MODIFICATIONS. - */ -package com.ibm.wala.demandpa.alg.refinepolicy; - -import com.ibm.wala.ipa.cha.IClassHierarchy; - -/** - * A refinement policy specified manually with annotations. - * @author Manu Sridharan - * - */ -public class ManualRefinementPolicy extends AbstractRefinementPolicy { - - private ManualRefinementPolicy(IClassHierarchy cha) { - // since we have specified what to refine manually, no need to run multiple passes - super(new ContainersFieldPolicy(cha), new AlwaysRefineCGPolicy(), 1, new int[] { LONGER_PASS_BUDGET }); - } - - public static class Factory implements RefinementPolicyFactory { - private final IClassHierarchy cha; - - public Factory(IClassHierarchy cha) { - this.cha = cha; - } - - public RefinementPolicy make() { - return new ManualRefinementPolicy(cha); - } - } -} +/******************************************************************************* + * 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. + * + * This file is a derivative of code released by the University of + * California under the terms listed below. + * + * Refinement Analysis Tools is Copyright (c) 2007 The Regents of the + * University of California (Regents). Provided that this notice and + * the following two paragraphs are included in any distribution of + * Refinement Analysis Tools or its derivative work, Regents agrees + * not to assert any of Regents' copyright rights in Refinement + * Analysis Tools against recipient for recipient's reproduction, + * preparation of derivative works, public display, public + * performance, distribution or sublicensing of Refinement Analysis + * Tools and derivative works, in source code and object code form. + * This agreement not to assert does not confer, by implication, + * estoppel, or otherwise any license or rights in any intellectual + * property of Regents, including, but not limited to, any patents + * of Regents or Regents' employees. + * + * IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, + * INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, + * INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE + * AND ITS DOCUMENTATION, EVEN IF REGENTS HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE AND FURTHER DISCLAIMS ANY STATUTORY + * WARRANTY OF NON-INFRINGEMENT. THE SOFTWARE AND ACCOMPANYING + * DOCUMENTATION, IF ANY, PROVIDED HEREUNDER IS PROVIDED "AS + * IS". REGENTS HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, + * UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + */ +package com.ibm.wala.demandpa.alg.refinepolicy; + +import com.ibm.wala.ipa.cha.IClassHierarchy; + +/** + * A refinement policy specified manually with annotations. + * @author Manu Sridharan + * + */ +public class ManualRefinementPolicy extends AbstractRefinementPolicy { + + private ManualRefinementPolicy(IClassHierarchy cha) { + // since we have specified what to refine manually, no need to run multiple passes + super(new ContainersFieldPolicy(cha), new AlwaysRefineCGPolicy(), 1, new int[] { LONGER_PASS_BUDGET }); + } + + public static class Factory implements RefinementPolicyFactory { + private final IClassHierarchy cha; + + public Factory(IClassHierarchy cha) { + this.cha = cha; + } + + public RefinementPolicy make() { + return new ManualRefinementPolicy(cha); + } + } +} diff --git a/com.ibm.wala.core/src/com/ibm/wala/demandpa/alg/refinepolicy/NeverRefineCGPolicy.java b/com.ibm.wala.core/src/com/ibm/wala/demandpa/alg/refinepolicy/NeverRefineCGPolicy.java index 5b1b12279..6dd2909a4 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/demandpa/alg/refinepolicy/NeverRefineCGPolicy.java +++ b/com.ibm.wala.core/src/com/ibm/wala/demandpa/alg/refinepolicy/NeverRefineCGPolicy.java @@ -1,52 +1,52 @@ -/******************************************************************************* - * 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. - * - * This file is a derivative of code released by the University of - * California under the terms listed below. - * - * Refinement Analysis Tools is Copyright (c) 2007 The Regents of the - * University of California (Regents). Provided that this notice and - * the following two paragraphs are included in any distribution of - * Refinement Analysis Tools or its derivative work, Regents agrees - * not to assert any of Regents' copyright rights in Refinement - * Analysis Tools against recipient for recipient's reproduction, - * preparation of derivative works, public display, public - * performance, distribution or sublicensing of Refinement Analysis - * Tools and derivative works, in source code and object code form. - * This agreement not to assert does not confer, by implication, - * estoppel, or otherwise any license or rights in any intellectual - * property of Regents, including, but not limited to, any patents - * of Regents or Regents' employees. - * - * IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, - * INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, - * INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE - * AND ITS DOCUMENTATION, EVEN IF REGENTS HAS BEEN ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE AND FURTHER DISCLAIMS ANY STATUTORY - * WARRANTY OF NON-INFRINGEMENT. THE SOFTWARE AND ACCOMPANYING - * DOCUMENTATION, IF ANY, PROVIDED HEREUNDER IS PROVIDED "AS - * IS". REGENTS HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, - * UPDATES, ENHANCEMENTS, OR MODIFICATIONS. - */ -package com.ibm.wala.demandpa.alg.refinepolicy; - -import com.ibm.wala.ipa.callgraph.propagation.cfa.CallerSiteContext; - -public class NeverRefineCGPolicy implements CallGraphRefinePolicy { - - public boolean shouldRefine(CallerSiteContext callSiteAndCGNode) { - return false; - } - - public boolean nextPass() { - return false; - } - -} +/******************************************************************************* + * 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. + * + * This file is a derivative of code released by the University of + * California under the terms listed below. + * + * Refinement Analysis Tools is Copyright (c) 2007 The Regents of the + * University of California (Regents). Provided that this notice and + * the following two paragraphs are included in any distribution of + * Refinement Analysis Tools or its derivative work, Regents agrees + * not to assert any of Regents' copyright rights in Refinement + * Analysis Tools against recipient for recipient's reproduction, + * preparation of derivative works, public display, public + * performance, distribution or sublicensing of Refinement Analysis + * Tools and derivative works, in source code and object code form. + * This agreement not to assert does not confer, by implication, + * estoppel, or otherwise any license or rights in any intellectual + * property of Regents, including, but not limited to, any patents + * of Regents or Regents' employees. + * + * IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, + * INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, + * INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE + * AND ITS DOCUMENTATION, EVEN IF REGENTS HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE AND FURTHER DISCLAIMS ANY STATUTORY + * WARRANTY OF NON-INFRINGEMENT. THE SOFTWARE AND ACCOMPANYING + * DOCUMENTATION, IF ANY, PROVIDED HEREUNDER IS PROVIDED "AS + * IS". REGENTS HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, + * UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + */ +package com.ibm.wala.demandpa.alg.refinepolicy; + +import com.ibm.wala.ipa.callgraph.propagation.cfa.CallerSiteContext; + +public class NeverRefineCGPolicy implements CallGraphRefinePolicy { + + public boolean shouldRefine(CallerSiteContext callSiteAndCGNode) { + return false; + } + + public boolean nextPass() { + return false; + } + +} diff --git a/com.ibm.wala.core/src/com/ibm/wala/demandpa/alg/refinepolicy/NeverRefineFieldsPolicy.java b/com.ibm.wala.core/src/com/ibm/wala/demandpa/alg/refinepolicy/NeverRefineFieldsPolicy.java index d02a6840f..59fadf137 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/demandpa/alg/refinepolicy/NeverRefineFieldsPolicy.java +++ b/com.ibm.wala.core/src/com/ibm/wala/demandpa/alg/refinepolicy/NeverRefineFieldsPolicy.java @@ -1,55 +1,55 @@ -/******************************************************************************* - * 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. - * - * This file is a derivative of code released by the University of - * California under the terms listed below. - * - * Refinement Analysis Tools is Copyright (c) 2007 The Regents of the - * University of California (Regents). Provided that this notice and - * the following two paragraphs are included in any distribution of - * Refinement Analysis Tools or its derivative work, Regents agrees - * not to assert any of Regents' copyright rights in Refinement - * Analysis Tools against recipient for recipient's reproduction, - * preparation of derivative works, public display, public - * performance, distribution or sublicensing of Refinement Analysis - * Tools and derivative works, in source code and object code form. - * This agreement not to assert does not confer, by implication, - * estoppel, or otherwise any license or rights in any intellectual - * property of Regents, including, but not limited to, any patents - * of Regents or Regents' employees. - * - * IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, - * INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, - * INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE - * AND ITS DOCUMENTATION, EVEN IF REGENTS HAS BEEN ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE AND FURTHER DISCLAIMS ANY STATUTORY - * WARRANTY OF NON-INFRINGEMENT. THE SOFTWARE AND ACCOMPANYING - * DOCUMENTATION, IF ANY, PROVIDED HEREUNDER IS PROVIDED "AS - * IS". REGENTS HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, - * UPDATES, ENHANCEMENTS, OR MODIFICATIONS. - */ -package com.ibm.wala.demandpa.alg.refinepolicy; - -import com.ibm.wala.classLoader.IField; -import com.ibm.wala.demandpa.alg.statemachine.StateMachine; -import com.ibm.wala.demandpa.flowgraph.IFlowLabel; -import com.ibm.wala.ipa.callgraph.propagation.PointerKey; - -public class NeverRefineFieldsPolicy implements FieldRefinePolicy { - - public boolean shouldRefine(IField field, PointerKey basePtr, PointerKey val, IFlowLabel label, StateMachine.State state) { - return false; - } - - public boolean nextPass() { - return false; - } - -} +/******************************************************************************* + * 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. + * + * This file is a derivative of code released by the University of + * California under the terms listed below. + * + * Refinement Analysis Tools is Copyright (c) 2007 The Regents of the + * University of California (Regents). Provided that this notice and + * the following two paragraphs are included in any distribution of + * Refinement Analysis Tools or its derivative work, Regents agrees + * not to assert any of Regents' copyright rights in Refinement + * Analysis Tools against recipient for recipient's reproduction, + * preparation of derivative works, public display, public + * performance, distribution or sublicensing of Refinement Analysis + * Tools and derivative works, in source code and object code form. + * This agreement not to assert does not confer, by implication, + * estoppel, or otherwise any license or rights in any intellectual + * property of Regents, including, but not limited to, any patents + * of Regents or Regents' employees. + * + * IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, + * INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, + * INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE + * AND ITS DOCUMENTATION, EVEN IF REGENTS HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE AND FURTHER DISCLAIMS ANY STATUTORY + * WARRANTY OF NON-INFRINGEMENT. THE SOFTWARE AND ACCOMPANYING + * DOCUMENTATION, IF ANY, PROVIDED HEREUNDER IS PROVIDED "AS + * IS". REGENTS HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, + * UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + */ +package com.ibm.wala.demandpa.alg.refinepolicy; + +import com.ibm.wala.classLoader.IField; +import com.ibm.wala.demandpa.alg.statemachine.StateMachine; +import com.ibm.wala.demandpa.flowgraph.IFlowLabel; +import com.ibm.wala.ipa.callgraph.propagation.PointerKey; + +public class NeverRefineFieldsPolicy implements FieldRefinePolicy { + + public boolean shouldRefine(IField field, PointerKey basePtr, PointerKey val, IFlowLabel label, StateMachine.State state) { + return false; + } + + public boolean nextPass() { + return false; + } + +} diff --git a/com.ibm.wala.core/src/com/ibm/wala/demandpa/alg/refinepolicy/RefinementPolicy.java b/com.ibm.wala.core/src/com/ibm/wala/demandpa/alg/refinepolicy/RefinementPolicy.java index 30c1e2dc5..44c46696e 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/demandpa/alg/refinepolicy/RefinementPolicy.java +++ b/com.ibm.wala.core/src/com/ibm/wala/demandpa/alg/refinepolicy/RefinementPolicy.java @@ -1,83 +1,83 @@ -/******************************************************************************* - * 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. - * - * This file is a derivative of code released by the University of - * California under the terms listed below. - * - * Refinement Analysis Tools is Copyright (c) 2007 The Regents of the - * University of California (Regents). Provided that this notice and - * the following two paragraphs are included in any distribution of - * Refinement Analysis Tools or its derivative work, Regents agrees - * not to assert any of Regents' copyright rights in Refinement - * Analysis Tools against recipient for recipient's reproduction, - * preparation of derivative works, public display, public - * performance, distribution or sublicensing of Refinement Analysis - * Tools and derivative works, in source code and object code form. - * This agreement not to assert does not confer, by implication, - * estoppel, or otherwise any license or rights in any intellectual - * property of Regents, including, but not limited to, any patents - * of Regents or Regents' employees. - * - * IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, - * INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, - * INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE - * AND ITS DOCUMENTATION, EVEN IF REGENTS HAS BEEN ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE AND FURTHER DISCLAIMS ANY STATUTORY - * WARRANTY OF NON-INFRINGEMENT. THE SOFTWARE AND ACCOMPANYING - * DOCUMENTATION, IF ANY, PROVIDED HEREUNDER IS PROVIDED "AS - * IS". REGENTS HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, - * UPDATES, ENHANCEMENTS, OR MODIFICATIONS. - */ -package com.ibm.wala.demandpa.alg.refinepolicy; - -/** - * A complete refinement policy for a points-to analysis. Specifies a - * {@link FieldRefinePolicy}, a {@link CallGraphRefinePolicy}, and budgets for - * analysis passes. - * - * @author Manu Sridharan - * - */ -public interface RefinementPolicy { - - /** - * - * @return the maximum number of refinement iterations for the query - */ - public int getNumPasses(); - - /** - * - * @param passNum - * @return the maximum number of nodes to traverse in pass - * passNum - */ - public int getBudgetForPass(int passNum); - - /** - * - * @return the field refinement policy - */ - public FieldRefinePolicy getFieldRefinePolicy(); - - /** - * - * @return the call graph refinement policy - */ - public CallGraphRefinePolicy getCallGraphRefinePolicy(); - - /** - * - * @return true if more refinement can be done, and hence - * another pass can be attempted; false otherwise - */ - public boolean nextPass(); - -} +/******************************************************************************* + * 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. + * + * This file is a derivative of code released by the University of + * California under the terms listed below. + * + * Refinement Analysis Tools is Copyright (c) 2007 The Regents of the + * University of California (Regents). Provided that this notice and + * the following two paragraphs are included in any distribution of + * Refinement Analysis Tools or its derivative work, Regents agrees + * not to assert any of Regents' copyright rights in Refinement + * Analysis Tools against recipient for recipient's reproduction, + * preparation of derivative works, public display, public + * performance, distribution or sublicensing of Refinement Analysis + * Tools and derivative works, in source code and object code form. + * This agreement not to assert does not confer, by implication, + * estoppel, or otherwise any license or rights in any intellectual + * property of Regents, including, but not limited to, any patents + * of Regents or Regents' employees. + * + * IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, + * INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, + * INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE + * AND ITS DOCUMENTATION, EVEN IF REGENTS HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE AND FURTHER DISCLAIMS ANY STATUTORY + * WARRANTY OF NON-INFRINGEMENT. THE SOFTWARE AND ACCOMPANYING + * DOCUMENTATION, IF ANY, PROVIDED HEREUNDER IS PROVIDED "AS + * IS". REGENTS HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, + * UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + */ +package com.ibm.wala.demandpa.alg.refinepolicy; + +/** + * A complete refinement policy for a points-to analysis. Specifies a + * {@link FieldRefinePolicy}, a {@link CallGraphRefinePolicy}, and budgets for + * analysis passes. + * + * @author Manu Sridharan + * + */ +public interface RefinementPolicy { + + /** + * + * @return the maximum number of refinement iterations for the query + */ + public int getNumPasses(); + + /** + * + * @param passNum + * @return the maximum number of nodes to traverse in pass + * passNum + */ + public int getBudgetForPass(int passNum); + + /** + * + * @return the field refinement policy + */ + public FieldRefinePolicy getFieldRefinePolicy(); + + /** + * + * @return the call graph refinement policy + */ + public CallGraphRefinePolicy getCallGraphRefinePolicy(); + + /** + * + * @return true if more refinement can be done, and hence + * another pass can be attempted; false otherwise + */ + public boolean nextPass(); + +} diff --git a/com.ibm.wala.core/src/com/ibm/wala/demandpa/alg/refinepolicy/RefinementPolicyFactory.java b/com.ibm.wala.core/src/com/ibm/wala/demandpa/alg/refinepolicy/RefinementPolicyFactory.java index f899bff03..00011c872 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/demandpa/alg/refinepolicy/RefinementPolicyFactory.java +++ b/com.ibm.wala.core/src/com/ibm/wala/demandpa/alg/refinepolicy/RefinementPolicyFactory.java @@ -1,44 +1,44 @@ -/******************************************************************************* - * 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. - * - * This file is a derivative of code released by the University of - * California under the terms listed below. - * - * Refinement Analysis Tools is Copyright (c) 2007 The Regents of the - * University of California (Regents). Provided that this notice and - * the following two paragraphs are included in any distribution of - * Refinement Analysis Tools or its derivative work, Regents agrees - * not to assert any of Regents' copyright rights in Refinement - * Analysis Tools against recipient for recipient's reproduction, - * preparation of derivative works, public display, public - * performance, distribution or sublicensing of Refinement Analysis - * Tools and derivative works, in source code and object code form. - * This agreement not to assert does not confer, by implication, - * estoppel, or otherwise any license or rights in any intellectual - * property of Regents, including, but not limited to, any patents - * of Regents or Regents' employees. - * - * IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, - * INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, - * INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE - * AND ITS DOCUMENTATION, EVEN IF REGENTS HAS BEEN ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE AND FURTHER DISCLAIMS ANY STATUTORY - * WARRANTY OF NON-INFRINGEMENT. THE SOFTWARE AND ACCOMPANYING - * DOCUMENTATION, IF ANY, PROVIDED HEREUNDER IS PROVIDED "AS - * IS". REGENTS HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, - * UPDATES, ENHANCEMENTS, OR MODIFICATIONS. - */ -package com.ibm.wala.demandpa.alg.refinepolicy; - -public interface RefinementPolicyFactory { - - public RefinementPolicy make(); - -} +/******************************************************************************* + * 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. + * + * This file is a derivative of code released by the University of + * California under the terms listed below. + * + * Refinement Analysis Tools is Copyright (c) 2007 The Regents of the + * University of California (Regents). Provided that this notice and + * the following two paragraphs are included in any distribution of + * Refinement Analysis Tools or its derivative work, Regents agrees + * not to assert any of Regents' copyright rights in Refinement + * Analysis Tools against recipient for recipient's reproduction, + * preparation of derivative works, public display, public + * performance, distribution or sublicensing of Refinement Analysis + * Tools and derivative works, in source code and object code form. + * This agreement not to assert does not confer, by implication, + * estoppel, or otherwise any license or rights in any intellectual + * property of Regents, including, but not limited to, any patents + * of Regents or Regents' employees. + * + * IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, + * INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, + * INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE + * AND ITS DOCUMENTATION, EVEN IF REGENTS HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE AND FURTHER DISCLAIMS ANY STATUTORY + * WARRANTY OF NON-INFRINGEMENT. THE SOFTWARE AND ACCOMPANYING + * DOCUMENTATION, IF ANY, PROVIDED HEREUNDER IS PROVIDED "AS + * IS". REGENTS HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, + * UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + */ +package com.ibm.wala.demandpa.alg.refinepolicy; + +public interface RefinementPolicyFactory { + + public RefinementPolicy make(); + +} diff --git a/com.ibm.wala.core/src/com/ibm/wala/demandpa/alg/refinepolicy/SinglePassRefinementPolicy.java b/com.ibm.wala.core/src/com/ibm/wala/demandpa/alg/refinepolicy/SinglePassRefinementPolicy.java index abd9c3f0b..04f4fc7ee 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/demandpa/alg/refinepolicy/SinglePassRefinementPolicy.java +++ b/com.ibm.wala.core/src/com/ibm/wala/demandpa/alg/refinepolicy/SinglePassRefinementPolicy.java @@ -1,81 +1,81 @@ -/******************************************************************************* - * 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. - * - * This file is a derivative of code released by the University of - * California under the terms listed below. - * - * Refinement Analysis Tools is Copyright (c) 2007 The Regents of the - * University of California (Regents). Provided that this notice and - * the following two paragraphs are included in any distribution of - * Refinement Analysis Tools or its derivative work, Regents agrees - * not to assert any of Regents' copyright rights in Refinement - * Analysis Tools against recipient for recipient's reproduction, - * preparation of derivative works, public display, public - * performance, distribution or sublicensing of Refinement Analysis - * Tools and derivative works, in source code and object code form. - * This agreement not to assert does not confer, by implication, - * estoppel, or otherwise any license or rights in any intellectual - * property of Regents, including, but not limited to, any patents - * of Regents or Regents' employees. - * - * IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, - * INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, - * INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE - * AND ITS DOCUMENTATION, EVEN IF REGENTS HAS BEEN ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE AND FURTHER DISCLAIMS ANY STATUTORY - * WARRANTY OF NON-INFRINGEMENT. THE SOFTWARE AND ACCOMPANYING - * DOCUMENTATION, IF ANY, PROVIDED HEREUNDER IS PROVIDED "AS - * IS". REGENTS HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, - * UPDATES, ENHANCEMENTS, OR MODIFICATIONS. - */ -package com.ibm.wala.demandpa.alg.refinepolicy; - -/** - * A policy for performing a single analysis pass, i.e., with no refinement. - * - * @author Manu Sridharan - * - */ -public class SinglePassRefinementPolicy extends AbstractRefinementPolicy { - - private SinglePassRefinementPolicy(FieldRefinePolicy fieldRefinePolicy, CallGraphRefinePolicy cgRefinePolicy, int budget) { - super(fieldRefinePolicy, cgRefinePolicy, 1, new int[] {budget}); - } - - @Override - public boolean nextPass() { - return false; - } - - public static class Factory implements RefinementPolicyFactory { - - private final FieldRefinePolicy fieldRefinePolicy; - - private final CallGraphRefinePolicy cgRefinePolicy; - - private final int budget; - - public Factory(FieldRefinePolicy fieldRefinePolicy, CallGraphRefinePolicy cgRefinePolicy) { - this(fieldRefinePolicy, cgRefinePolicy, Integer.MAX_VALUE); - } - - public Factory(FieldRefinePolicy fieldRefinePolicy, CallGraphRefinePolicy cgRefinePolicy, int budget) { - this.fieldRefinePolicy = fieldRefinePolicy; - this.cgRefinePolicy = cgRefinePolicy; - this.budget = budget; - } - - - public RefinementPolicy make() { - return new SinglePassRefinementPolicy(fieldRefinePolicy, cgRefinePolicy, budget); - } - - } -} +/******************************************************************************* + * 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. + * + * This file is a derivative of code released by the University of + * California under the terms listed below. + * + * Refinement Analysis Tools is Copyright (c) 2007 The Regents of the + * University of California (Regents). Provided that this notice and + * the following two paragraphs are included in any distribution of + * Refinement Analysis Tools or its derivative work, Regents agrees + * not to assert any of Regents' copyright rights in Refinement + * Analysis Tools against recipient for recipient's reproduction, + * preparation of derivative works, public display, public + * performance, distribution or sublicensing of Refinement Analysis + * Tools and derivative works, in source code and object code form. + * This agreement not to assert does not confer, by implication, + * estoppel, or otherwise any license or rights in any intellectual + * property of Regents, including, but not limited to, any patents + * of Regents or Regents' employees. + * + * IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, + * INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, + * INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE + * AND ITS DOCUMENTATION, EVEN IF REGENTS HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE AND FURTHER DISCLAIMS ANY STATUTORY + * WARRANTY OF NON-INFRINGEMENT. THE SOFTWARE AND ACCOMPANYING + * DOCUMENTATION, IF ANY, PROVIDED HEREUNDER IS PROVIDED "AS + * IS". REGENTS HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, + * UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + */ +package com.ibm.wala.demandpa.alg.refinepolicy; + +/** + * A policy for performing a single analysis pass, i.e., with no refinement. + * + * @author Manu Sridharan + * + */ +public class SinglePassRefinementPolicy extends AbstractRefinementPolicy { + + private SinglePassRefinementPolicy(FieldRefinePolicy fieldRefinePolicy, CallGraphRefinePolicy cgRefinePolicy, int budget) { + super(fieldRefinePolicy, cgRefinePolicy, 1, new int[] {budget}); + } + + @Override + public boolean nextPass() { + return false; + } + + public static class Factory implements RefinementPolicyFactory { + + private final FieldRefinePolicy fieldRefinePolicy; + + private final CallGraphRefinePolicy cgRefinePolicy; + + private final int budget; + + public Factory(FieldRefinePolicy fieldRefinePolicy, CallGraphRefinePolicy cgRefinePolicy) { + this(fieldRefinePolicy, cgRefinePolicy, Integer.MAX_VALUE); + } + + public Factory(FieldRefinePolicy fieldRefinePolicy, CallGraphRefinePolicy cgRefinePolicy, int budget) { + this.fieldRefinePolicy = fieldRefinePolicy; + this.cgRefinePolicy = cgRefinePolicy; + this.budget = budget; + } + + + public RefinementPolicy make() { + return new SinglePassRefinementPolicy(fieldRefinePolicy, cgRefinePolicy, budget); + } + + } +} diff --git a/com.ibm.wala.core/src/com/ibm/wala/demandpa/alg/refinepolicy/TunedRefinementPolicy.java b/com.ibm.wala.core/src/com/ibm/wala/demandpa/alg/refinepolicy/TunedRefinementPolicy.java index f97a1faf7..d40b4e39a 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/demandpa/alg/refinepolicy/TunedRefinementPolicy.java +++ b/com.ibm.wala.core/src/com/ibm/wala/demandpa/alg/refinepolicy/TunedRefinementPolicy.java @@ -1,68 +1,68 @@ -/******************************************************************************* - * 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. - * - * This file is a derivative of code released by the University of - * California under the terms listed below. - * - * Refinement Analysis Tools is Copyright (c) 2007 The Regents of the - * University of California (Regents). Provided that this notice and - * the following two paragraphs are included in any distribution of - * Refinement Analysis Tools or its derivative work, Regents agrees - * not to assert any of Regents' copyright rights in Refinement - * Analysis Tools against recipient for recipient's reproduction, - * preparation of derivative works, public display, public - * performance, distribution or sublicensing of Refinement Analysis - * Tools and derivative works, in source code and object code form. - * This agreement not to assert does not confer, by implication, - * estoppel, or otherwise any license or rights in any intellectual - * property of Regents, including, but not limited to, any patents - * of Regents or Regents' employees. - * - * IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, - * INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, - * INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE - * AND ITS DOCUMENTATION, EVEN IF REGENTS HAS BEEN ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE AND FURTHER DISCLAIMS ANY STATUTORY - * WARRANTY OF NON-INFRINGEMENT. THE SOFTWARE AND ACCOMPANYING - * DOCUMENTATION, IF ANY, PROVIDED HEREUNDER IS PROVIDED "AS - * IS". REGENTS HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, - * UPDATES, ENHANCEMENTS, OR MODIFICATIONS. - */ -package com.ibm.wala.demandpa.alg.refinepolicy; - -import com.ibm.wala.ipa.cha.IClassHierarchy; - -/** - * A refinement policy that iteratively adds more types to refine, based on which type was encountered first in each - * analysis pass. - * - * @author Manu Sridharan - * - */ -public class TunedRefinementPolicy extends AbstractRefinementPolicy { - - public TunedRefinementPolicy(IClassHierarchy cha) { - super(new TunedFieldRefinementPolicy(cha), new AlwaysRefineCGPolicy()); - } - - public static class Factory implements RefinementPolicyFactory { - - private final IClassHierarchy cha; - - public Factory(IClassHierarchy cha) { - this.cha = cha; - } - - public RefinementPolicy make() { - return new TunedRefinementPolicy(cha); - } - - } -} +/******************************************************************************* + * 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. + * + * This file is a derivative of code released by the University of + * California under the terms listed below. + * + * Refinement Analysis Tools is Copyright (c) 2007 The Regents of the + * University of California (Regents). Provided that this notice and + * the following two paragraphs are included in any distribution of + * Refinement Analysis Tools or its derivative work, Regents agrees + * not to assert any of Regents' copyright rights in Refinement + * Analysis Tools against recipient for recipient's reproduction, + * preparation of derivative works, public display, public + * performance, distribution or sublicensing of Refinement Analysis + * Tools and derivative works, in source code and object code form. + * This agreement not to assert does not confer, by implication, + * estoppel, or otherwise any license or rights in any intellectual + * property of Regents, including, but not limited to, any patents + * of Regents or Regents' employees. + * + * IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, + * INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, + * INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE + * AND ITS DOCUMENTATION, EVEN IF REGENTS HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE AND FURTHER DISCLAIMS ANY STATUTORY + * WARRANTY OF NON-INFRINGEMENT. THE SOFTWARE AND ACCOMPANYING + * DOCUMENTATION, IF ANY, PROVIDED HEREUNDER IS PROVIDED "AS + * IS". REGENTS HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, + * UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + */ +package com.ibm.wala.demandpa.alg.refinepolicy; + +import com.ibm.wala.ipa.cha.IClassHierarchy; + +/** + * A refinement policy that iteratively adds more types to refine, based on which type was encountered first in each + * analysis pass. + * + * @author Manu Sridharan + * + */ +public class TunedRefinementPolicy extends AbstractRefinementPolicy { + + public TunedRefinementPolicy(IClassHierarchy cha) { + super(new TunedFieldRefinementPolicy(cha), new AlwaysRefineCGPolicy()); + } + + public static class Factory implements RefinementPolicyFactory { + + private final IClassHierarchy cha; + + public Factory(IClassHierarchy cha) { + this.cha = cha; + } + + public RefinementPolicy make() { + return new TunedRefinementPolicy(cha); + } + + } +} diff --git a/com.ibm.wala.core/src/com/ibm/wala/demandpa/alg/statemachine/DummyStateMachine.java b/com.ibm.wala.core/src/com/ibm/wala/demandpa/alg/statemachine/DummyStateMachine.java index 01f26c28c..15d776027 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/demandpa/alg/statemachine/DummyStateMachine.java +++ b/com.ibm.wala.core/src/com/ibm/wala/demandpa/alg/statemachine/DummyStateMachine.java @@ -1,79 +1,79 @@ -/******************************************************************************* - * 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. - * - * This file is a derivative of code released by the University of - * California under the terms listed below. - * - * Refinement Analysis Tools is Copyright (c) 2007 The Regents of the - * University of California (Regents). Provided that this notice and - * the following two paragraphs are included in any distribution of - * Refinement Analysis Tools or its derivative work, Regents agrees - * not to assert any of Regents' copyright rights in Refinement - * Analysis Tools against recipient for recipient's reproduction, - * preparation of derivative works, public display, public - * performance, distribution or sublicensing of Refinement Analysis - * Tools and derivative works, in source code and object code form. - * This agreement not to assert does not confer, by implication, - * estoppel, or otherwise any license or rights in any intellectual - * property of Regents, including, but not limited to, any patents - * of Regents or Regents' employees. - * - * IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, - * INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, - * INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE - * AND ITS DOCUMENTATION, EVEN IF REGENTS HAS BEEN ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE AND FURTHER DISCLAIMS ANY STATUTORY - * WARRANTY OF NON-INFRINGEMENT. THE SOFTWARE AND ACCOMPANYING - * DOCUMENTATION, IF ANY, PROVIDED HEREUNDER IS PROVIDED "AS - * IS". REGENTS HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, - * UPDATES, ENHANCEMENTS, OR MODIFICATIONS. - */ -package com.ibm.wala.demandpa.alg.statemachine; - -/** - * A dummy state machine with a single, non-error state. Primarily for testing - * purposes. - * - * @author Manu Sridharan - * - */ -public class DummyStateMachine implements StateMachine { - - public static class Factory implements StateMachineFactory { - - public StateMachine make() { - return new DummyStateMachine(); - } - - } - - private static final State DUMMY = new State() { - @Override - public String toString() { - return "DUMMY"; - } - }; - - /* - * (non-Javadoc) - * - * @see statemachine.StateMachine#transition(int, java.lang.Object) - */ - public State transition(State prevState, T label) { - return DUMMY; - } - - public State getStartState() { - return DUMMY; - } - - private DummyStateMachine() { - } -} +/******************************************************************************* + * 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. + * + * This file is a derivative of code released by the University of + * California under the terms listed below. + * + * Refinement Analysis Tools is Copyright (c) 2007 The Regents of the + * University of California (Regents). Provided that this notice and + * the following two paragraphs are included in any distribution of + * Refinement Analysis Tools or its derivative work, Regents agrees + * not to assert any of Regents' copyright rights in Refinement + * Analysis Tools against recipient for recipient's reproduction, + * preparation of derivative works, public display, public + * performance, distribution or sublicensing of Refinement Analysis + * Tools and derivative works, in source code and object code form. + * This agreement not to assert does not confer, by implication, + * estoppel, or otherwise any license or rights in any intellectual + * property of Regents, including, but not limited to, any patents + * of Regents or Regents' employees. + * + * IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, + * INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, + * INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE + * AND ITS DOCUMENTATION, EVEN IF REGENTS HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE AND FURTHER DISCLAIMS ANY STATUTORY + * WARRANTY OF NON-INFRINGEMENT. THE SOFTWARE AND ACCOMPANYING + * DOCUMENTATION, IF ANY, PROVIDED HEREUNDER IS PROVIDED "AS + * IS". REGENTS HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, + * UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + */ +package com.ibm.wala.demandpa.alg.statemachine; + +/** + * A dummy state machine with a single, non-error state. Primarily for testing + * purposes. + * + * @author Manu Sridharan + * + */ +public class DummyStateMachine implements StateMachine { + + public static class Factory implements StateMachineFactory { + + public StateMachine make() { + return new DummyStateMachine(); + } + + } + + private static final State DUMMY = new State() { + @Override + public String toString() { + return "DUMMY"; + } + }; + + /* + * (non-Javadoc) + * + * @see statemachine.StateMachine#transition(int, java.lang.Object) + */ + public State transition(State prevState, T label) { + return DUMMY; + } + + public State getStartState() { + return DUMMY; + } + + private DummyStateMachine() { + } +} diff --git a/com.ibm.wala.core/src/com/ibm/wala/demandpa/alg/statemachine/StateMachine.java b/com.ibm.wala.core/src/com/ibm/wala/demandpa/alg/statemachine/StateMachine.java index 8340482b5..70868fb80 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/demandpa/alg/statemachine/StateMachine.java +++ b/com.ibm.wala.core/src/com/ibm/wala/demandpa/alg/statemachine/StateMachine.java @@ -1,67 +1,67 @@ -/******************************************************************************* - * 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. - * - * This file is a derivative of code released by the University of - * California under the terms listed below. - * - * Refinement Analysis Tools is Copyright (c) 2007 The Regents of the - * University of California (Regents). Provided that this notice and - * the following two paragraphs are included in any distribution of - * Refinement Analysis Tools or its derivative work, Regents agrees - * not to assert any of Regents' copyright rights in Refinement - * Analysis Tools against recipient for recipient's reproduction, - * preparation of derivative works, public display, public - * performance, distribution or sublicensing of Refinement Analysis - * Tools and derivative works, in source code and object code form. - * This agreement not to assert does not confer, by implication, - * estoppel, or otherwise any license or rights in any intellectual - * property of Regents, including, but not limited to, any patents - * of Regents or Regents' employees. - * - * IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, - * INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, - * INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE - * AND ITS DOCUMENTATION, EVEN IF REGENTS HAS BEEN ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE AND FURTHER DISCLAIMS ANY STATUTORY - * WARRANTY OF NON-INFRINGEMENT. THE SOFTWARE AND ACCOMPANYING - * DOCUMENTATION, IF ANY, PROVIDED HEREUNDER IS PROVIDED "AS - * IS". REGENTS HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, - * UPDATES, ENHANCEMENTS, OR MODIFICATIONS. - */ -package com.ibm.wala.demandpa.alg.statemachine; - -/** - * A state machine with an error state. Non-error states must be represented - * externally as natural numbers. - * - * @author Manu Sridharan - * - */ -public interface StateMachine { - - public static interface State { - } - - public static final State ERROR = new State() { - }; - - public State getStartState(); - - /** - * @param prevState - * @param label - * @return the successor state of prevState for the transition labelled label, - * or null if no such transition exists - * @throws StatesMergedException if merging of states is detected - * @see StatesMergedException - */ - public State transition(State prevState, T label); - -} +/******************************************************************************* + * 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. + * + * This file is a derivative of code released by the University of + * California under the terms listed below. + * + * Refinement Analysis Tools is Copyright (c) 2007 The Regents of the + * University of California (Regents). Provided that this notice and + * the following two paragraphs are included in any distribution of + * Refinement Analysis Tools or its derivative work, Regents agrees + * not to assert any of Regents' copyright rights in Refinement + * Analysis Tools against recipient for recipient's reproduction, + * preparation of derivative works, public display, public + * performance, distribution or sublicensing of Refinement Analysis + * Tools and derivative works, in source code and object code form. + * This agreement not to assert does not confer, by implication, + * estoppel, or otherwise any license or rights in any intellectual + * property of Regents, including, but not limited to, any patents + * of Regents or Regents' employees. + * + * IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, + * INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, + * INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE + * AND ITS DOCUMENTATION, EVEN IF REGENTS HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE AND FURTHER DISCLAIMS ANY STATUTORY + * WARRANTY OF NON-INFRINGEMENT. THE SOFTWARE AND ACCOMPANYING + * DOCUMENTATION, IF ANY, PROVIDED HEREUNDER IS PROVIDED "AS + * IS". REGENTS HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, + * UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + */ +package com.ibm.wala.demandpa.alg.statemachine; + +/** + * A state machine with an error state. Non-error states must be represented + * externally as natural numbers. + * + * @author Manu Sridharan + * + */ +public interface StateMachine { + + public static interface State { + } + + public static final State ERROR = new State() { + }; + + public State getStartState(); + + /** + * @param prevState + * @param label + * @return the successor state of prevState for the transition labelled label, + * or null if no such transition exists + * @throws StatesMergedException if merging of states is detected + * @see StatesMergedException + */ + public State transition(State prevState, T label); + +} diff --git a/com.ibm.wala.core/src/com/ibm/wala/demandpa/alg/statemachine/StateMachineFactory.java b/com.ibm.wala.core/src/com/ibm/wala/demandpa/alg/statemachine/StateMachineFactory.java index 7953856b9..97500a6de 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/demandpa/alg/statemachine/StateMachineFactory.java +++ b/com.ibm.wala.core/src/com/ibm/wala/demandpa/alg/statemachine/StateMachineFactory.java @@ -1,44 +1,44 @@ -/******************************************************************************* - * 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. - * - * This file is a derivative of code released by the University of - * California under the terms listed below. - * - * Refinement Analysis Tools is Copyright (c) 2007 The Regents of the - * University of California (Regents). Provided that this notice and - * the following two paragraphs are included in any distribution of - * Refinement Analysis Tools or its derivative work, Regents agrees - * not to assert any of Regents' copyright rights in Refinement - * Analysis Tools against recipient for recipient's reproduction, - * preparation of derivative works, public display, public - * performance, distribution or sublicensing of Refinement Analysis - * Tools and derivative works, in source code and object code form. - * This agreement not to assert does not confer, by implication, - * estoppel, or otherwise any license or rights in any intellectual - * property of Regents, including, but not limited to, any patents - * of Regents or Regents' employees. - * - * IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, - * INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, - * INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE - * AND ITS DOCUMENTATION, EVEN IF REGENTS HAS BEEN ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE AND FURTHER DISCLAIMS ANY STATUTORY - * WARRANTY OF NON-INFRINGEMENT. THE SOFTWARE AND ACCOMPANYING - * DOCUMENTATION, IF ANY, PROVIDED HEREUNDER IS PROVIDED "AS - * IS". REGENTS HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, - * UPDATES, ENHANCEMENTS, OR MODIFICATIONS. - */ -package com.ibm.wala.demandpa.alg.statemachine; - - -public interface StateMachineFactory { - - public StateMachine make(); -} +/******************************************************************************* + * 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. + * + * This file is a derivative of code released by the University of + * California under the terms listed below. + * + * Refinement Analysis Tools is Copyright (c) 2007 The Regents of the + * University of California (Regents). Provided that this notice and + * the following two paragraphs are included in any distribution of + * Refinement Analysis Tools or its derivative work, Regents agrees + * not to assert any of Regents' copyright rights in Refinement + * Analysis Tools against recipient for recipient's reproduction, + * preparation of derivative works, public display, public + * performance, distribution or sublicensing of Refinement Analysis + * Tools and derivative works, in source code and object code form. + * This agreement not to assert does not confer, by implication, + * estoppel, or otherwise any license or rights in any intellectual + * property of Regents, including, but not limited to, any patents + * of Regents or Regents' employees. + * + * IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, + * INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, + * INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE + * AND ITS DOCUMENTATION, EVEN IF REGENTS HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE AND FURTHER DISCLAIMS ANY STATUTORY + * WARRANTY OF NON-INFRINGEMENT. THE SOFTWARE AND ACCOMPANYING + * DOCUMENTATION, IF ANY, PROVIDED HEREUNDER IS PROVIDED "AS + * IS". REGENTS HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, + * UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + */ +package com.ibm.wala.demandpa.alg.statemachine; + + +public interface StateMachineFactory { + + public StateMachine make(); +} diff --git a/com.ibm.wala.core/src/com/ibm/wala/demandpa/alg/statemachine/StatesMergedException.java b/com.ibm.wala.core/src/com/ibm/wala/demandpa/alg/statemachine/StatesMergedException.java index 52e26c79d..6e816da96 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/demandpa/alg/statemachine/StatesMergedException.java +++ b/com.ibm.wala.core/src/com/ibm/wala/demandpa/alg/statemachine/StatesMergedException.java @@ -1,52 +1,52 @@ -/******************************************************************************* - * 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. - * - * This file is a derivative of code released by the University of - * California under the terms listed below. - * - * Refinement Analysis Tools is Copyright (c) 2007 The Regents of the - * University of California (Regents). Provided that this notice and - * the following two paragraphs are included in any distribution of - * Refinement Analysis Tools or its derivative work, Regents agrees - * not to assert any of Regents' copyright rights in Refinement - * Analysis Tools against recipient for recipient's reproduction, - * preparation of derivative works, public display, public - * performance, distribution or sublicensing of Refinement Analysis - * Tools and derivative works, in source code and object code form. - * This agreement not to assert does not confer, by implication, - * estoppel, or otherwise any license or rights in any intellectual - * property of Regents, including, but not limited to, any patents - * of Regents or Regents' employees. - * - * IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, - * INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, - * INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE - * AND ITS DOCUMENTATION, EVEN IF REGENTS HAS BEEN ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE AND FURTHER DISCLAIMS ANY STATUTORY - * WARRANTY OF NON-INFRINGEMENT. THE SOFTWARE AND ACCOMPANYING - * DOCUMENTATION, IF ANY, PROVIDED HEREUNDER IS PROVIDED "AS - * IS". REGENTS HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, - * UPDATES, ENHANCEMENTS, OR MODIFICATIONS. - */ -package com.ibm.wala.demandpa.alg.statemachine; - -/** - * Exception thrown when a state machine needs to merge states and treat them as - * equivalent. For example, a state machine for context sensitivity may throw - * this exception in its - * {@link StateMachine#transition(com.ibm.wala.demandpa.alg.statemachine.StateMachine.State, Object)} - * method when recursive method calls are detected. - * - * @author Manu Sridharan - * - */ -public class StatesMergedException extends RuntimeException { - -} +/******************************************************************************* + * 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. + * + * This file is a derivative of code released by the University of + * California under the terms listed below. + * + * Refinement Analysis Tools is Copyright (c) 2007 The Regents of the + * University of California (Regents). Provided that this notice and + * the following two paragraphs are included in any distribution of + * Refinement Analysis Tools or its derivative work, Regents agrees + * not to assert any of Regents' copyright rights in Refinement + * Analysis Tools against recipient for recipient's reproduction, + * preparation of derivative works, public display, public + * performance, distribution or sublicensing of Refinement Analysis + * Tools and derivative works, in source code and object code form. + * This agreement not to assert does not confer, by implication, + * estoppel, or otherwise any license or rights in any intellectual + * property of Regents, including, but not limited to, any patents + * of Regents or Regents' employees. + * + * IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, + * INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, + * INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE + * AND ITS DOCUMENTATION, EVEN IF REGENTS HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE AND FURTHER DISCLAIMS ANY STATUTORY + * WARRANTY OF NON-INFRINGEMENT. THE SOFTWARE AND ACCOMPANYING + * DOCUMENTATION, IF ANY, PROVIDED HEREUNDER IS PROVIDED "AS + * IS". REGENTS HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, + * UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + */ +package com.ibm.wala.demandpa.alg.statemachine; + +/** + * Exception thrown when a state machine needs to merge states and treat them as + * equivalent. For example, a state machine for context sensitivity may throw + * this exception in its + * {@link StateMachine#transition(com.ibm.wala.demandpa.alg.statemachine.StateMachine.State, Object)} + * method when recursive method calls are detected. + * + * @author Manu Sridharan + * + */ +public class StatesMergedException extends RuntimeException { + +} diff --git a/com.ibm.wala.core/src/com/ibm/wala/demandpa/flowgraph/AbstractDemandFlowGraph.java b/com.ibm.wala.core/src/com/ibm/wala/demandpa/flowgraph/AbstractDemandFlowGraph.java index 55367a741..d39d2465d 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/demandpa/flowgraph/AbstractDemandFlowGraph.java +++ b/com.ibm.wala.core/src/com/ibm/wala/demandpa/flowgraph/AbstractDemandFlowGraph.java @@ -1,391 +1,391 @@ -/******************************************************************************* - * 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. - * - * This file is a derivative of code released by the University of - * California under the terms listed below. - * - * Refinement Analysis Tools is Copyright (c) 2007 The Regents of the - * University of California (Regents). Provided that this notice and - * the following two paragraphs are included in any distribution of - * Refinement Analysis Tools or its derivative work, Regents agrees - * not to assert any of Regents' copyright rights in Refinement - * Analysis Tools against recipient for recipient's reproduction, - * preparation of derivative works, public display, public - * performance, distribution or sublicensing of Refinement Analysis - * Tools and derivative works, in source code and object code form. - * This agreement not to assert does not confer, by implication, - * estoppel, or otherwise any license or rights in any intellectual - * property of Regents, including, but not limited to, any patents - * of Regents or Regents' employees. - * - * IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, - * INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, - * INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE - * AND ITS DOCUMENTATION, EVEN IF REGENTS HAS BEEN ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE AND FURTHER DISCLAIMS ANY STATUTORY - * WARRANTY OF NON-INFRINGEMENT. THE SOFTWARE AND ACCOMPANYING - * DOCUMENTATION, IF ANY, PROVIDED HEREUNDER IS PROVIDED "AS - * IS". REGENTS HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, - * UPDATES, ENHANCEMENTS, OR MODIFICATIONS. - */ -package com.ibm.wala.demandpa.flowgraph; - -import java.util.ArrayList; -import java.util.Collection; -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.classLoader.CallSiteReference; -import com.ibm.wala.demandpa.util.MemoryAccessMap; -import com.ibm.wala.ipa.callgraph.CGNode; -import com.ibm.wala.ipa.callgraph.CallGraph; -import com.ibm.wala.ipa.callgraph.propagation.HeapModel; -import com.ibm.wala.ipa.callgraph.propagation.LocalPointerKey; -import com.ibm.wala.ipa.callgraph.propagation.PointerKey; -import com.ibm.wala.ipa.callgraph.propagation.ReturnValueKey; -import com.ibm.wala.ipa.callgraph.propagation.SSAPropagationCallGraphBuilder; -import com.ibm.wala.ipa.callgraph.propagation.cfa.CallerSiteContext; -import com.ibm.wala.ipa.cha.IClassHierarchy; -import com.ibm.wala.ssa.DefUse; -import com.ibm.wala.ssa.IR; -import com.ibm.wala.ssa.ISSABasicBlock; -import com.ibm.wala.ssa.SSAAbstractInvokeInstruction; -import com.ibm.wala.ssa.SSAInstruction; -import com.ibm.wala.ssa.SSAInvokeInstruction; -import com.ibm.wala.ssa.SSAPhiInstruction; -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.intset.BitVectorIntSet; -import com.ibm.wala.util.ref.ReferenceCleanser; - -/** - * A graph representing program flow, constructed method-by-method on demand - */ -public abstract class AbstractDemandFlowGraph extends AbstractFlowGraph { - private final static boolean DEBUG = false; - - /** - * Counter for wiping soft caches - */ - private static int wipeCount = 0; - - /** - * node numbers of CGNodes we have already visited - */ - final BitVectorIntSet cgNodesVisited = new BitVectorIntSet(); - - /* - * @see com.ibm.wala.demandpa.flowgraph.IFlowGraph#addSubgraphForNode(com.ibm.wala.ipa.callgraph.CGNode) - */ - public void addSubgraphForNode(CGNode node) throws IllegalArgumentException { - if (node == null) { - throw new IllegalArgumentException("node == null"); - } - IR ir = node.getIR(); - if (ir == null) { - throw new IllegalArgumentException("no ir for node " + node); - } - int n = cg.getNumber(node); - if (!cgNodesVisited.contains(n)) { - cgNodesVisited.add(n); - unconditionallyAddConstraintsFromNode(node, ir); - addNodesForInvocations(node, ir); - addNodesForParameters(node, ir); - } - } - - /* - * @see com.ibm.wala.demandpa.flowgraph.IFlowGraph#hasSubgraphForNode(com.ibm.wala.ipa.callgraph.CGNode) - */ - public boolean hasSubgraphForNode(CGNode node) { - return cgNodesVisited.contains(cg.getNumber(node)); - } - - /* - * @see com.ibm.wala.demandpa.flowgraph.IFlowGraph#getParamSuccs(com.ibm.wala.ipa.callgraph.propagation.LocalPointerKey) - */ - public Iterator getParamSuccs(LocalPointerKey pk) { - // TODO cache this result - // TODO take some cgnode as parameter if we have calling context? - CGNode cgNode = params.get(pk); - if (cgNode == null) { - return EmptyIterator.instance(); - } - int paramPos = pk.getValueNumber() - 1; - ArrayList paramSuccs = new ArrayList(); - // iterate over callers - for (CGNode caller : cg) { - // TODO optimization: we don't need to add the graph if null is passed - // as the argument - addSubgraphForNode(caller); - IR ir = caller.getIR(); - for (Iterator iterator = ir.iterateCallSites(); iterator.hasNext();) { - CallSiteReference call = iterator.next(); - if (cg.getPossibleTargets(caller, call).contains(cgNode)) { - SSAAbstractInvokeInstruction[] callInstrs = ir.getCalls(call); - for (int i = 0; i < callInstrs.length; i++) { - SSAAbstractInvokeInstruction callInstr = callInstrs[i]; - PointerKey actualPk = heapModel.getPointerKeyForLocal(caller, callInstr.getUse(paramPos)); - assert containsNode(actualPk); - assert containsNode(pk); - paramSuccs.add(new PointerKeyAndCallSite(actualPk, call)); - } - } - } - } - return paramSuccs.iterator(); - } - - /* - * @see com.ibm.wala.demandpa.flowgraph.IFlowGraph#getParamPreds(com.ibm.wala.ipa.callgraph.propagation.LocalPointerKey) - */ - public Iterator getParamPreds(LocalPointerKey pk) { - // TODO - Set instrs = callParams.get(pk); - if (instrs == null) { - return EmptyIterator.instance(); - } - ArrayList paramPreds = new ArrayList(); - for (SSAInvokeInstruction callInstr : instrs) { - for (int i = 0; i < callInstr.getNumberOfUses(); i++) { - if (pk.getValueNumber() != callInstr.getUse(i)) - continue; - CallSiteReference callSiteRef = callInstr.getCallSite(); - // get call targets - Collection possibleCallees = cg.getPossibleTargets(pk.getNode(), callSiteRef); - // construct graph for each target - for (CGNode callee : possibleCallees) { - addSubgraphForNode(callee); - // TODO test this!!! - // TODO test passing null as an argument - PointerKey paramVal = heapModel.getPointerKeyForLocal(callee, i + 1); - assert containsNode(paramVal); - paramPreds.add(new PointerKeyAndCallSite(paramVal, callSiteRef)); - } - } - } - return paramPreds.iterator(); - - } - - /* - * @see com.ibm.wala.demandpa.flowgraph.IFlowGraph#getReturnSuccs(com.ibm.wala.ipa.callgraph.propagation.LocalPointerKey) - */ - public Iterator getReturnSuccs(LocalPointerKey pk) { - SSAInvokeInstruction callInstr = callDefs.get(pk); - if (callInstr == null) - return EmptyIterator.instance(); - ArrayList returnSuccs = new ArrayList(); - boolean isExceptional = pk.getValueNumber() == callInstr.getException(); - - CallSiteReference callSiteRef = callInstr.getCallSite(); - // get call targets - Collection possibleCallees = cg.getPossibleTargets(pk.getNode(), callSiteRef); - // construct graph for each target - for (CGNode callee : possibleCallees) { - addSubgraphForNode(callee); - PointerKey retVal = isExceptional ? heapModel.getPointerKeyForExceptionalReturnValue(callee) : heapModel - .getPointerKeyForReturnValue(callee); - assert containsNode(retVal); - returnSuccs.add(new PointerKeyAndCallSite(retVal, callSiteRef)); - } - - return returnSuccs.iterator(); - } - - /* - * @see com.ibm.wala.demandpa.flowgraph.IFlowGraph#getReturnPreds(com.ibm.wala.ipa.callgraph.propagation.LocalPointerKey) - */ - public Iterator getReturnPreds(LocalPointerKey pk) { - CGNode cgNode = returns.get(pk); - if (cgNode == null) { - return EmptyIterator.instance(); - } - boolean isExceptional = pk == heapModel.getPointerKeyForExceptionalReturnValue(cgNode); - ArrayList returnPreds = new ArrayList(); - // iterate over callers - for (CGNode caller : cg) { - // TODO we don't need to add the graph if null is passed - // as the argument - addSubgraphForNode(caller); - IR ir = caller.getIR(); - for (Iterator iterator = ir.iterateCallSites(); iterator.hasNext();) { - CallSiteReference call = iterator.next(); - if (cg.getPossibleTargets(caller, call).contains(cgNode)) { - SSAAbstractInvokeInstruction[] callInstrs = ir.getCalls(call); - for (int i = 0; i < callInstrs.length; i++) { - SSAAbstractInvokeInstruction callInstr = callInstrs[i]; - PointerKey returnPk = heapModel.getPointerKeyForLocal(caller, isExceptional ? callInstr.getException() : callInstr - .getDef()); - assert containsNode(returnPk); - assert containsNode(pk); - returnPreds.add(new PointerKeyAndCallSite(returnPk, call)); - } - } - } - } - return returnPreds.iterator(); - } - - protected abstract void addNodesForParameters(CGNode node, IR ir); - - protected void unconditionallyAddConstraintsFromNode(CGNode node, IR ir) { - - if (DEBUG) { - System.err.println(("Adding constraints for CGNode " + node)); - } - - if (SSAPropagationCallGraphBuilder.PERIODIC_WIPE_SOFT_CACHES) { - wipeCount++; - if (wipeCount >= SSAPropagationCallGraphBuilder.WIPE_SOFT_CACHE_INTERVAL) { - wipeCount = 0; - ReferenceCleanser.clearSoftCaches(); - } - } - - debugPrintIR(ir); - - if (ir == null) { - return; - } - - DefUse du = node.getDU(); - addNodeInstructionConstraints(node, ir, du); - addNodePassthruExceptionConstraints(node, ir); - addNodeConstantConstraints(node, ir); - } - - /** - * Add pointer flow constraints based on instructions in a given node - */ - protected void addNodeInstructionConstraints(CGNode node, IR ir, DefUse du) { - FlowStatementVisitor v = makeVisitor(node); - ControlFlowGraph cfg = ir.getControlFlowGraph(); - for (ISSABasicBlock b : cfg) { - addBlockInstructionConstraints(node, cfg, b, v); - } - } - - /** - * Add constraints for a particular basic block. - */ - protected void addBlockInstructionConstraints(CGNode node, ControlFlowGraph cfg, - ISSABasicBlock b, FlowStatementVisitor v) { - v.setBasicBlock(b); - - // visit each instruction in the basic block. - for (Iterator it = b.iterator(); it.hasNext();) { - SSAInstruction s = it.next(); - if (s != null) { - s.visit(v); - } - } - - addPhiConstraints(node, cfg, b); - } - - private void addPhiConstraints(CGNode node, ControlFlowGraph cfg, ISSABasicBlock b) { - - // visit each phi instruction in each successor block - for (Iterator iter = cfg.getSuccNodes(b); iter.hasNext();) { - ISSABasicBlock sb = (ISSABasicBlock) iter.next(); - if (sb.isExitBlock()) { - // an optimization based on invariant that exit blocks should - // have no - // phis. - continue; - } - int n = 0; - // set n to be whichPred(this, sb); - for (Iterator back = cfg.getPredNodes(sb); back.hasNext(); n++) { - if (back.next() == b) { - break; - } - } - assert n < cfg.getPredNodeCount(sb); - for (Iterator phis = sb.iteratePhis(); phis.hasNext();) { - // Assertions.UNREACHABLE(); - SSAPhiInstruction phi = phis.next(); - if (phi == null) { - continue; - } - PointerKey def = heapModel.getPointerKeyForLocal(node, phi.getDef()); - if (phi.getUse(n) > 0) { - PointerKey use = heapModel.getPointerKeyForLocal(node, phi.getUse(n)); - addNode(def); - addNode(use); - addEdge(def, use, AssignLabel.noFilter()); - } - // } - // } - } - } - } - - protected abstract FlowStatementVisitor makeVisitor(CGNode node); - - private void debugPrintIR(IR ir) { - if (DEBUG) { - if (ir == null) { - System.err.println("\n No statements\n"); - } else { - try { - System.err.println(ir.toString()); - } catch (Error e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - } - } - } - - final Map> callerCache = HashMapFactory.make(); - - public Set getPotentialCallers(PointerKey formalPk) { - CGNode callee = null; - if (formalPk instanceof LocalPointerKey) { - callee = ((LocalPointerKey) formalPk).getNode(); - } else if (formalPk instanceof ReturnValueKey) { - callee = ((ReturnValueKey) formalPk).getNode(); - } else { - throw new IllegalArgumentException("formalPk must represent a local"); - } - Set ret = callerCache.get(callee); - if (ret == null) { - ret = HashSetFactory.make(); - for (Iterator predNodes = cg.getPredNodes(callee); predNodes.hasNext();) { - CGNode caller = predNodes.next(); - for (Iterator iterator = cg.getPossibleSites(caller, callee); iterator.hasNext();) { - CallSiteReference call = iterator.next(); - ret.add(new CallerSiteContext(caller, call)); - } - } - callerCache.put(callee, ret); - } - return ret; - } - - public Set getPossibleTargets(CGNode node, CallSiteReference site, LocalPointerKey actualPk) { - return cg.getPossibleTargets(node, site); - } - - protected interface FlowStatementVisitor extends SSAInstruction.IVisitor { - void setBasicBlock(ISSABasicBlock b); - } - - public AbstractDemandFlowGraph(final CallGraph cg, final HeapModel heapModel, final MemoryAccessMap mam, final IClassHierarchy cha) { - super(mam, heapModel, cha, cg); - } - +/******************************************************************************* + * 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. + * + * This file is a derivative of code released by the University of + * California under the terms listed below. + * + * Refinement Analysis Tools is Copyright (c) 2007 The Regents of the + * University of California (Regents). Provided that this notice and + * the following two paragraphs are included in any distribution of + * Refinement Analysis Tools or its derivative work, Regents agrees + * not to assert any of Regents' copyright rights in Refinement + * Analysis Tools against recipient for recipient's reproduction, + * preparation of derivative works, public display, public + * performance, distribution or sublicensing of Refinement Analysis + * Tools and derivative works, in source code and object code form. + * This agreement not to assert does not confer, by implication, + * estoppel, or otherwise any license or rights in any intellectual + * property of Regents, including, but not limited to, any patents + * of Regents or Regents' employees. + * + * IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, + * INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, + * INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE + * AND ITS DOCUMENTATION, EVEN IF REGENTS HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE AND FURTHER DISCLAIMS ANY STATUTORY + * WARRANTY OF NON-INFRINGEMENT. THE SOFTWARE AND ACCOMPANYING + * DOCUMENTATION, IF ANY, PROVIDED HEREUNDER IS PROVIDED "AS + * IS". REGENTS HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, + * UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + */ +package com.ibm.wala.demandpa.flowgraph; + +import java.util.ArrayList; +import java.util.Collection; +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.classLoader.CallSiteReference; +import com.ibm.wala.demandpa.util.MemoryAccessMap; +import com.ibm.wala.ipa.callgraph.CGNode; +import com.ibm.wala.ipa.callgraph.CallGraph; +import com.ibm.wala.ipa.callgraph.propagation.HeapModel; +import com.ibm.wala.ipa.callgraph.propagation.LocalPointerKey; +import com.ibm.wala.ipa.callgraph.propagation.PointerKey; +import com.ibm.wala.ipa.callgraph.propagation.ReturnValueKey; +import com.ibm.wala.ipa.callgraph.propagation.SSAPropagationCallGraphBuilder; +import com.ibm.wala.ipa.callgraph.propagation.cfa.CallerSiteContext; +import com.ibm.wala.ipa.cha.IClassHierarchy; +import com.ibm.wala.ssa.DefUse; +import com.ibm.wala.ssa.IR; +import com.ibm.wala.ssa.ISSABasicBlock; +import com.ibm.wala.ssa.SSAAbstractInvokeInstruction; +import com.ibm.wala.ssa.SSAInstruction; +import com.ibm.wala.ssa.SSAInvokeInstruction; +import com.ibm.wala.ssa.SSAPhiInstruction; +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.intset.BitVectorIntSet; +import com.ibm.wala.util.ref.ReferenceCleanser; + +/** + * A graph representing program flow, constructed method-by-method on demand + */ +public abstract class AbstractDemandFlowGraph extends AbstractFlowGraph { + private final static boolean DEBUG = false; + + /** + * Counter for wiping soft caches + */ + private static int wipeCount = 0; + + /** + * node numbers of CGNodes we have already visited + */ + final BitVectorIntSet cgNodesVisited = new BitVectorIntSet(); + + /* + * @see com.ibm.wala.demandpa.flowgraph.IFlowGraph#addSubgraphForNode(com.ibm.wala.ipa.callgraph.CGNode) + */ + public void addSubgraphForNode(CGNode node) throws IllegalArgumentException { + if (node == null) { + throw new IllegalArgumentException("node == null"); + } + IR ir = node.getIR(); + if (ir == null) { + throw new IllegalArgumentException("no ir for node " + node); + } + int n = cg.getNumber(node); + if (!cgNodesVisited.contains(n)) { + cgNodesVisited.add(n); + unconditionallyAddConstraintsFromNode(node, ir); + addNodesForInvocations(node, ir); + addNodesForParameters(node, ir); + } + } + + /* + * @see com.ibm.wala.demandpa.flowgraph.IFlowGraph#hasSubgraphForNode(com.ibm.wala.ipa.callgraph.CGNode) + */ + public boolean hasSubgraphForNode(CGNode node) { + return cgNodesVisited.contains(cg.getNumber(node)); + } + + /* + * @see com.ibm.wala.demandpa.flowgraph.IFlowGraph#getParamSuccs(com.ibm.wala.ipa.callgraph.propagation.LocalPointerKey) + */ + public Iterator getParamSuccs(LocalPointerKey pk) { + // TODO cache this result + // TODO take some cgnode as parameter if we have calling context? + CGNode cgNode = params.get(pk); + if (cgNode == null) { + return EmptyIterator.instance(); + } + int paramPos = pk.getValueNumber() - 1; + ArrayList paramSuccs = new ArrayList(); + // iterate over callers + for (CGNode caller : cg) { + // TODO optimization: we don't need to add the graph if null is passed + // as the argument + addSubgraphForNode(caller); + IR ir = caller.getIR(); + for (Iterator iterator = ir.iterateCallSites(); iterator.hasNext();) { + CallSiteReference call = iterator.next(); + if (cg.getPossibleTargets(caller, call).contains(cgNode)) { + SSAAbstractInvokeInstruction[] callInstrs = ir.getCalls(call); + for (int i = 0; i < callInstrs.length; i++) { + SSAAbstractInvokeInstruction callInstr = callInstrs[i]; + PointerKey actualPk = heapModel.getPointerKeyForLocal(caller, callInstr.getUse(paramPos)); + assert containsNode(actualPk); + assert containsNode(pk); + paramSuccs.add(new PointerKeyAndCallSite(actualPk, call)); + } + } + } + } + return paramSuccs.iterator(); + } + + /* + * @see com.ibm.wala.demandpa.flowgraph.IFlowGraph#getParamPreds(com.ibm.wala.ipa.callgraph.propagation.LocalPointerKey) + */ + public Iterator getParamPreds(LocalPointerKey pk) { + // TODO + Set instrs = callParams.get(pk); + if (instrs == null) { + return EmptyIterator.instance(); + } + ArrayList paramPreds = new ArrayList(); + for (SSAInvokeInstruction callInstr : instrs) { + for (int i = 0; i < callInstr.getNumberOfUses(); i++) { + if (pk.getValueNumber() != callInstr.getUse(i)) + continue; + CallSiteReference callSiteRef = callInstr.getCallSite(); + // get call targets + Collection possibleCallees = cg.getPossibleTargets(pk.getNode(), callSiteRef); + // construct graph for each target + for (CGNode callee : possibleCallees) { + addSubgraphForNode(callee); + // TODO test this!!! + // TODO test passing null as an argument + PointerKey paramVal = heapModel.getPointerKeyForLocal(callee, i + 1); + assert containsNode(paramVal); + paramPreds.add(new PointerKeyAndCallSite(paramVal, callSiteRef)); + } + } + } + return paramPreds.iterator(); + + } + + /* + * @see com.ibm.wala.demandpa.flowgraph.IFlowGraph#getReturnSuccs(com.ibm.wala.ipa.callgraph.propagation.LocalPointerKey) + */ + public Iterator getReturnSuccs(LocalPointerKey pk) { + SSAInvokeInstruction callInstr = callDefs.get(pk); + if (callInstr == null) + return EmptyIterator.instance(); + ArrayList returnSuccs = new ArrayList(); + boolean isExceptional = pk.getValueNumber() == callInstr.getException(); + + CallSiteReference callSiteRef = callInstr.getCallSite(); + // get call targets + Collection possibleCallees = cg.getPossibleTargets(pk.getNode(), callSiteRef); + // construct graph for each target + for (CGNode callee : possibleCallees) { + addSubgraphForNode(callee); + PointerKey retVal = isExceptional ? heapModel.getPointerKeyForExceptionalReturnValue(callee) : heapModel + .getPointerKeyForReturnValue(callee); + assert containsNode(retVal); + returnSuccs.add(new PointerKeyAndCallSite(retVal, callSiteRef)); + } + + return returnSuccs.iterator(); + } + + /* + * @see com.ibm.wala.demandpa.flowgraph.IFlowGraph#getReturnPreds(com.ibm.wala.ipa.callgraph.propagation.LocalPointerKey) + */ + public Iterator getReturnPreds(LocalPointerKey pk) { + CGNode cgNode = returns.get(pk); + if (cgNode == null) { + return EmptyIterator.instance(); + } + boolean isExceptional = pk == heapModel.getPointerKeyForExceptionalReturnValue(cgNode); + ArrayList returnPreds = new ArrayList(); + // iterate over callers + for (CGNode caller : cg) { + // TODO we don't need to add the graph if null is passed + // as the argument + addSubgraphForNode(caller); + IR ir = caller.getIR(); + for (Iterator iterator = ir.iterateCallSites(); iterator.hasNext();) { + CallSiteReference call = iterator.next(); + if (cg.getPossibleTargets(caller, call).contains(cgNode)) { + SSAAbstractInvokeInstruction[] callInstrs = ir.getCalls(call); + for (int i = 0; i < callInstrs.length; i++) { + SSAAbstractInvokeInstruction callInstr = callInstrs[i]; + PointerKey returnPk = heapModel.getPointerKeyForLocal(caller, isExceptional ? callInstr.getException() : callInstr + .getDef()); + assert containsNode(returnPk); + assert containsNode(pk); + returnPreds.add(new PointerKeyAndCallSite(returnPk, call)); + } + } + } + } + return returnPreds.iterator(); + } + + protected abstract void addNodesForParameters(CGNode node, IR ir); + + protected void unconditionallyAddConstraintsFromNode(CGNode node, IR ir) { + + if (DEBUG) { + System.err.println(("Adding constraints for CGNode " + node)); + } + + if (SSAPropagationCallGraphBuilder.PERIODIC_WIPE_SOFT_CACHES) { + wipeCount++; + if (wipeCount >= SSAPropagationCallGraphBuilder.WIPE_SOFT_CACHE_INTERVAL) { + wipeCount = 0; + ReferenceCleanser.clearSoftCaches(); + } + } + + debugPrintIR(ir); + + if (ir == null) { + return; + } + + DefUse du = node.getDU(); + addNodeInstructionConstraints(node, ir, du); + addNodePassthruExceptionConstraints(node, ir); + addNodeConstantConstraints(node, ir); + } + + /** + * Add pointer flow constraints based on instructions in a given node + */ + protected void addNodeInstructionConstraints(CGNode node, IR ir, DefUse du) { + FlowStatementVisitor v = makeVisitor(node); + ControlFlowGraph cfg = ir.getControlFlowGraph(); + for (ISSABasicBlock b : cfg) { + addBlockInstructionConstraints(node, cfg, b, v); + } + } + + /** + * Add constraints for a particular basic block. + */ + protected void addBlockInstructionConstraints(CGNode node, ControlFlowGraph cfg, + ISSABasicBlock b, FlowStatementVisitor v) { + v.setBasicBlock(b); + + // visit each instruction in the basic block. + for (Iterator it = b.iterator(); it.hasNext();) { + SSAInstruction s = it.next(); + if (s != null) { + s.visit(v); + } + } + + addPhiConstraints(node, cfg, b); + } + + private void addPhiConstraints(CGNode node, ControlFlowGraph cfg, ISSABasicBlock b) { + + // visit each phi instruction in each successor block + for (Iterator iter = cfg.getSuccNodes(b); iter.hasNext();) { + ISSABasicBlock sb = (ISSABasicBlock) iter.next(); + if (sb.isExitBlock()) { + // an optimization based on invariant that exit blocks should + // have no + // phis. + continue; + } + int n = 0; + // set n to be whichPred(this, sb); + for (Iterator back = cfg.getPredNodes(sb); back.hasNext(); n++) { + if (back.next() == b) { + break; + } + } + assert n < cfg.getPredNodeCount(sb); + for (Iterator phis = sb.iteratePhis(); phis.hasNext();) { + // Assertions.UNREACHABLE(); + SSAPhiInstruction phi = phis.next(); + if (phi == null) { + continue; + } + PointerKey def = heapModel.getPointerKeyForLocal(node, phi.getDef()); + if (phi.getUse(n) > 0) { + PointerKey use = heapModel.getPointerKeyForLocal(node, phi.getUse(n)); + addNode(def); + addNode(use); + addEdge(def, use, AssignLabel.noFilter()); + } + // } + // } + } + } + } + + protected abstract FlowStatementVisitor makeVisitor(CGNode node); + + private void debugPrintIR(IR ir) { + if (DEBUG) { + if (ir == null) { + System.err.println("\n No statements\n"); + } else { + try { + System.err.println(ir.toString()); + } catch (Error e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } + } + } + + final Map> callerCache = HashMapFactory.make(); + + public Set getPotentialCallers(PointerKey formalPk) { + CGNode callee = null; + if (formalPk instanceof LocalPointerKey) { + callee = ((LocalPointerKey) formalPk).getNode(); + } else if (formalPk instanceof ReturnValueKey) { + callee = ((ReturnValueKey) formalPk).getNode(); + } else { + throw new IllegalArgumentException("formalPk must represent a local"); + } + Set ret = callerCache.get(callee); + if (ret == null) { + ret = HashSetFactory.make(); + for (Iterator predNodes = cg.getPredNodes(callee); predNodes.hasNext();) { + CGNode caller = predNodes.next(); + for (Iterator iterator = cg.getPossibleSites(caller, callee); iterator.hasNext();) { + CallSiteReference call = iterator.next(); + ret.add(new CallerSiteContext(caller, call)); + } + } + callerCache.put(callee, ret); + } + return ret; + } + + public Set getPossibleTargets(CGNode node, CallSiteReference site, LocalPointerKey actualPk) { + return cg.getPossibleTargets(node, site); + } + + protected interface FlowStatementVisitor extends SSAInstruction.IVisitor { + void setBasicBlock(ISSABasicBlock b); + } + + public AbstractDemandFlowGraph(final CallGraph cg, final HeapModel heapModel, final MemoryAccessMap mam, final IClassHierarchy cha) { + super(mam, heapModel, cha, cg); + } + } \ No newline at end of file diff --git a/com.ibm.wala.core/src/com/ibm/wala/demandpa/flowgraph/AbstractFlowGraph.java b/com.ibm.wala.core/src/com/ibm/wala/demandpa/flowgraph/AbstractFlowGraph.java index 6771675a1..84c081578 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/demandpa/flowgraph/AbstractFlowGraph.java +++ b/com.ibm.wala.core/src/com/ibm/wala/demandpa/flowgraph/AbstractFlowGraph.java @@ -1,494 +1,494 @@ -/******************************************************************************* - * 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. - * - * This file is a derivative of code released by the University of - * California under the terms listed below. - * - * Refinement Analysis Tools is Copyright (c) 2007 The Regents of the - * University of California (Regents). Provided that this notice and - * the following two paragraphs are included in any distribution of - * Refinement Analysis Tools or its derivative work, Regents agrees - * not to assert any of Regents' copyright rights in Refinement - * Analysis Tools against recipient for recipient's reproduction, - * preparation of derivative works, public display, public - * performance, distribution or sublicensing of Refinement Analysis - * Tools and derivative works, in source code and object code form. - * This agreement not to assert does not confer, by implication, - * estoppel, or otherwise any license or rights in any intellectual - * property of Regents, including, but not limited to, any patents - * of Regents or Regents' employees. - * - * IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, - * INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, - * INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE - * AND ITS DOCUMENTATION, EVEN IF REGENTS HAS BEEN ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE AND FURTHER DISCLAIMS ANY STATUTORY - * WARRANTY OF NON-INFRINGEMENT. THE SOFTWARE AND ACCOMPANYING - * DOCUMENTATION, IF ANY, PROVIDED HEREUNDER IS PROVIDED "AS - * IS". REGENTS HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, - * UPDATES, ENHANCEMENTS, OR MODIFICATIONS. - */ -package com.ibm.wala.demandpa.flowgraph; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.Set; - -import com.ibm.wala.classLoader.CallSiteReference; -import com.ibm.wala.classLoader.IClass; -import com.ibm.wala.classLoader.IField; -import com.ibm.wala.classLoader.ProgramCounter; -import com.ibm.wala.demandpa.flowgraph.DemandPointerFlowGraph.NewMultiDimInfo; -import com.ibm.wala.demandpa.flowgraph.IFlowLabel.IFlowLabelVisitor; -import com.ibm.wala.demandpa.util.ArrayContents; -import com.ibm.wala.demandpa.util.MemoryAccess; -import com.ibm.wala.demandpa.util.MemoryAccessMap; -import com.ibm.wala.ipa.callgraph.CGNode; -import com.ibm.wala.ipa.callgraph.CallGraph; -import com.ibm.wala.ipa.callgraph.propagation.ArrayContentsKey; -import com.ibm.wala.ipa.callgraph.propagation.ConcreteTypeKey; -import com.ibm.wala.ipa.callgraph.propagation.HeapModel; -import com.ibm.wala.ipa.callgraph.propagation.InstanceKey; -import com.ibm.wala.ipa.callgraph.propagation.LocalPointerKey; -import com.ibm.wala.ipa.callgraph.propagation.NormalAllocationInNode; -import com.ibm.wala.ipa.callgraph.propagation.PointerKey; -import com.ibm.wala.ipa.callgraph.propagation.PropagationCallGraphBuilder; -import com.ibm.wala.ipa.callgraph.propagation.ReturnValueKey; -import com.ibm.wala.ipa.callgraph.propagation.SSAPropagationCallGraphBuilder; -import com.ibm.wala.ipa.callgraph.propagation.StaticFieldKey; -import com.ibm.wala.ipa.cha.IClassHierarchy; -import com.ibm.wala.ssa.IR; -import com.ibm.wala.ssa.SSAAbstractInvokeInstruction; -import com.ibm.wala.ssa.SSAAbstractThrowInstruction; -import com.ibm.wala.ssa.SSAArrayLoadInstruction; -import com.ibm.wala.ssa.SSAArrayStoreInstruction; -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.SSAPutInstruction; -import com.ibm.wala.ssa.SymbolTable; -import com.ibm.wala.types.TypeReference; -import com.ibm.wala.util.collections.EmptyIterator; -import com.ibm.wala.util.collections.HashMapFactory; -import com.ibm.wala.util.collections.MapUtil; -import com.ibm.wala.util.collections.Pair; -import com.ibm.wala.util.debug.Assertions; -import com.ibm.wala.util.graph.labeled.SlowSparseNumberedLabeledGraph; - -/** - * A graph whose edges are labeled with {@link IFlowLabel}s. - * - * @author Manu Sridharan - * - */ -public abstract class AbstractFlowGraph extends SlowSparseNumberedLabeledGraph implements IFlowGraph { - - private final static IFlowLabel defaultLabel = new IFlowLabel() { - public IFlowLabel bar() { - return defaultLabel; - } - - public boolean isBarred() { - return false; - } - - public void visit(IFlowLabelVisitor v, Object dst) { - } - - }; - - /** - * Map: LocalPointerKey -> SSAInvokeInstruction. If we have (x, foo()), that means that x was def'fed by the return value from the - * call to foo() - */ - protected final Map callDefs = HashMapFactory.make(); - - /** - * Map: {@link LocalPointerKey} -> Set<{@link SSAInvokeInstruction}>. If we have (x, foo()), that means x was passed as a - * parameter to the call to foo(). The parameter position is not represented and must be recovered. - */ - protected final Map> callParams = HashMapFactory.make(); - - /** - * Map: LocalPointerKey -> CGNode. If we have (x, foo), then x is a parameter of method foo. For now, we have to re-discover the - * parameter position. TODO this should just be a set; we can get the CGNode from the {@link LocalPointerKey} - */ - protected final Map params = HashMapFactory.make(); - - /** - * Map: {@link LocalPointerKey} -> {@link CGNode}. If we have (x, foo), then x is a return value of method foo. Must re-discover - * if x is normal or exceptional return value. - */ - protected final Map returns = HashMapFactory.make(); - - protected final MemoryAccessMap mam; - - protected final HeapModel heapModel; - - protected final IClassHierarchy cha; - - protected final CallGraph cg; - - public AbstractFlowGraph(MemoryAccessMap mam, HeapModel heapModel, IClassHierarchy cha, CallGraph cg) { - super(defaultLabel); - this.mam = mam; - this.heapModel = heapModel; - this.cha = cha; - this.cg = cg; - } - - /* - * @see com.ibm.wala.demandpa.flowgraph.IFlowLabelGraph#visitSuccs(java.lang.Object, - * com.ibm.wala.demandpa.flowgraph.IFlowLabel.IFlowLabelVisitor) - */ - public void visitSuccs(Object node, IFlowLabelVisitor v) { - for (Iterator succLabelIter = getSuccLabels(node); succLabelIter.hasNext();) { - final IFlowLabel label = succLabelIter.next(); - for (Iterator succNodeIter = getSuccNodes(node, label); succNodeIter.hasNext();) { - label.visit(v, succNodeIter.next()); - } - } - } - - /* - * @see com.ibm.wala.demandpa.flowgraph.IFlowLabelGraph#visitPreds(java.lang.Object, - * com.ibm.wala.demandpa.flowgraph.IFlowLabel.IFlowLabelVisitor) - */ - public void visitPreds(Object node, IFlowLabelVisitor v) { - for (Iterator predLabelIter = getPredLabels(node); predLabelIter.hasNext();) { - final IFlowLabel label = predLabelIter.next(); - for (Iterator predNodeIter = getPredNodes(node, label); predNodeIter.hasNext();) { - label.visit(v, predNodeIter.next()); - } - } - } - - /** - * For each invocation in the method, add nodes for actual parameters and return values - * - * @param node - */ - protected void addNodesForInvocations(CGNode node, IR ir) { - for (Iterator iter = ir.iterateCallSites(); iter.hasNext();) { - CallSiteReference site = iter.next(); - SSAAbstractInvokeInstruction[] calls = ir.getCalls(site); - for (SSAAbstractInvokeInstruction invokeInstr : calls) { - for (int i = 0; i < invokeInstr.getNumberOfUses(); i++) { - // just make nodes for parameters; we'll get to them when - // traversing - // from the callee - PointerKey use = heapModel.getPointerKeyForLocal(node, invokeInstr.getUse(i)); - addNode(use); - Set s = MapUtil.findOrCreateSet(callParams, use); - s.add((SSAInvokeInstruction) invokeInstr); - } - - // for any def'd values, keep track of the fact that they are def'd - // by a call - if (invokeInstr.hasDef()) { - PointerKey def = heapModel.getPointerKeyForLocal(node, invokeInstr.getDef()); - addNode(def); - callDefs.put(def, (SSAInvokeInstruction) invokeInstr); - } - PointerKey exc = heapModel.getPointerKeyForLocal(node, invokeInstr.getException()); - addNode(exc); - callDefs.put(exc, (SSAInvokeInstruction) invokeInstr); - - } - } - } - - public boolean isParam(LocalPointerKey pk) { - return params.get(pk) != null; - } - - public Iterator getInstrsPassingParam(LocalPointerKey pk) { - Set instrs = callParams.get(pk); - if (instrs == null) { - return EmptyIterator.instance(); - } else { - return instrs.iterator(); - } - } - - public SSAInvokeInstruction getInstrReturningTo(LocalPointerKey pk) { - return callDefs.get(pk); - } - - public Iterator getWritesToStaticField(StaticFieldKey sfk) throws IllegalArgumentException { - if (sfk == null) { - throw new IllegalArgumentException("sfk == null"); - } - Collection fieldWrites = mam.getStaticFieldWrites(sfk.getField()); - for (MemoryAccess a : fieldWrites) { - addSubgraphForNode(a.getNode()); - } - return getSuccNodes(sfk, AssignGlobalLabel.v()); - } - - public Iterator getReadsOfStaticField(StaticFieldKey sfk) throws IllegalArgumentException { - if (sfk == null) { - throw new IllegalArgumentException("sfk == null"); - } - Collection fieldReads = mam.getStaticFieldReads(sfk.getField()); - for (MemoryAccess a : fieldReads) { - addSubgraphForNode(a.getNode()); - } - return getPredNodes(sfk, AssignGlobalLabel.v()); - } - - public Iterator getWritesToInstanceField(PointerKey pk, IField f) { - // TODO: cache this!! - if (f == ArrayContents.v()) { - return getArrayWrites(pk); - } - pk = convertPointerKeyToHeapModel(pk, mam.getHeapModel()); - Collection writes = mam.getFieldWrites(pk, f); - for (MemoryAccess a : writes) { - addSubgraphForNode(a.getNode()); - } - ArrayList written = new ArrayList(); - for (MemoryAccess a : writes) { - IR ir = a.getNode().getIR(); - SSAPutInstruction s = (SSAPutInstruction) ir.getInstructions()[a.getInstructionIndex()]; - if (s == null) { - // s can be null because the memory access map may be constructed from bytecode, - // and the write instruction may have been eliminated from SSA because it's dead - // TODO clean this up - continue; - } - PointerKey r = heapModel.getPointerKeyForLocal(a.getNode(), s.getVal()); - // if (Assertions.verifyAssertions) { - // Assertions._assert(containsNode(r)); - // } - written.add(r); - } - return written.iterator(); - } - - /** - * convert a pointer key to one in the memory access map's heap model - * - * TODO move this somewhere more appropriate - * - * @throws UnsupportedOperationException if it doesn't know how to handle a {@link PointerKey} - */ - public static PointerKey convertPointerKeyToHeapModel(PointerKey pk, HeapModel h) { - if (pk == null) { - throw new IllegalArgumentException("null pk"); - } - if (pk instanceof LocalPointerKey) { - LocalPointerKey lpk = (LocalPointerKey) pk; - return h.getPointerKeyForLocal(lpk.getNode(), lpk.getValueNumber()); - } else if (pk instanceof ArrayContentsKey) { - ArrayContentsKey ack = (ArrayContentsKey) pk; - InstanceKey ik = ack.getInstanceKey(); - if (ik instanceof NormalAllocationInNode) { - NormalAllocationInNode nain = (NormalAllocationInNode) ik; - ik = h.getInstanceKeyForAllocation(nain.getNode(), nain.getSite()); - } else { - assert false : "need to handle " + ik.getClass(); - } - return h.getPointerKeyForArrayContents(ik); - } else if (pk instanceof ReturnValueKey) { - ReturnValueKey rvk = (ReturnValueKey) pk; - return h.getPointerKeyForReturnValue(rvk.getNode()); - } - throw new UnsupportedOperationException("need to handle " + pk.getClass()); - } - - public Iterator getReadsOfInstanceField(PointerKey pk, IField f) { - // TODO: cache this!! - if (f == ArrayContents.v()) { - return getArrayReads(pk); - } - pk = convertPointerKeyToHeapModel(pk, mam.getHeapModel()); - Collection reads = mam.getFieldReads(pk, f); - for (MemoryAccess a : reads) { - addSubgraphForNode(a.getNode()); - } - ArrayList readInto = new ArrayList(); - for (MemoryAccess a : reads) { - IR ir = a.getNode().getIR(); - SSAGetInstruction s = (SSAGetInstruction) ir.getInstructions()[a.getInstructionIndex()]; - if (s == null) { - // actually dead code - continue; - } - PointerKey r = heapModel.getPointerKeyForLocal(a.getNode(), s.getDef()); - // if (Assertions.verifyAssertions) { - // Assertions._assert(containsNode(r)); - // } - readInto.add(r); - } - return readInto.iterator(); - } - - Iterator getArrayWrites(PointerKey arrayRef) { - arrayRef = convertPointerKeyToHeapModel(arrayRef, mam.getHeapModel()); - Collection arrayWrites = mam.getArrayWrites(arrayRef); - for (MemoryAccess a : arrayWrites) { - addSubgraphForNode(a.getNode()); - } - ArrayList written = new ArrayList(); - for (MemoryAccess a : arrayWrites) { - final CGNode node = a.getNode(); - IR ir = node.getIR(); - SSAInstruction instruction = ir.getInstructions()[a.getInstructionIndex()]; - if (instruction == null) { - // this means the array store found was in fact dead code - // TODO detect this earlier and don't keep it in the MemoryAccessMap - continue; - } - if (instruction instanceof SSAArrayStoreInstruction) { - SSAArrayStoreInstruction s = (SSAArrayStoreInstruction) instruction; - PointerKey r = heapModel.getPointerKeyForLocal(node, s.getValue()); - written.add(r); - } else if (instruction instanceof SSANewInstruction) { - NewMultiDimInfo multiDimInfo = DemandPointerFlowGraph.getInfoForNewMultiDim((SSANewInstruction) instruction, heapModel, - node); - for (Pair arrStoreInstr : multiDimInfo.arrStoreInstrs) { - written.add(arrStoreInstr.snd); - } - } else { - Assertions.UNREACHABLE(); - } - } - return written.iterator(); - } - - protected Iterator getArrayReads(PointerKey arrayRef) { - arrayRef = convertPointerKeyToHeapModel(arrayRef, mam.getHeapModel()); - Collection arrayReads = mam.getArrayReads(arrayRef); - for (Iterator it = arrayReads.iterator(); it.hasNext();) { - MemoryAccess a = it.next(); - addSubgraphForNode(a.getNode()); - } - ArrayList read = new ArrayList(); - for (Iterator it = arrayReads.iterator(); it.hasNext();) { - MemoryAccess a = it.next(); - IR ir = a.getNode().getIR(); - SSAArrayLoadInstruction s = (SSAArrayLoadInstruction) ir.getInstructions()[a.getInstructionIndex()]; - if (s == null) { - // actually dead code - continue; - } - PointerKey r = heapModel.getPointerKeyForLocal(a.getNode(), s.getDef()); - // if (Assertions.verifyAssertions) { - // Assertions._assert(containsNode(r)); - // } - read.add(r); - } - return read.iterator(); - } - - /** - * Add constraints to represent the flow of exceptions to the exceptional return value for this node - */ - protected void addNodePassthruExceptionConstraints(CGNode node, IR ir) { - // add constraints relating to thrown exceptions that reach the exit - // block. - List peis = SSAPropagationCallGraphBuilder.getIncomingPEIs(ir, ir.getExitBlock()); - PointerKey exception = heapModel.getPointerKeyForExceptionalReturnValue(node); - IClass c = node.getClassHierarchy().lookupClass(TypeReference.JavaLangThrowable); - - addExceptionDefConstraints(ir, node, peis, exception, Collections.singleton(c)); - } - - /** - * Generate constraints which assign exception values into an exception pointer - * - * @param node governing node - * @param peis list of PEI instructions - * @param exceptionVar PointerKey representing a pointer to an exception value - * @param catchClasses the types "caught" by the exceptionVar - */ - protected void addExceptionDefConstraints(IR ir, CGNode node, List peis, PointerKey exceptionVar, - Set catchClasses) { - for (Iterator it = peis.iterator(); it.hasNext();) { - ProgramCounter peiLoc = it.next(); - SSAInstruction pei = ir.getPEI(peiLoc); - - if (pei instanceof SSAAbstractInvokeInstruction) { - SSAAbstractInvokeInstruction s = (SSAAbstractInvokeInstruction) pei; - PointerKey e = heapModel.getPointerKeyForLocal(node, s.getException()); - addNode(exceptionVar); - addNode(e); - addEdge(exceptionVar, e, AssignLabel.noFilter()); - - } else if (pei instanceof SSAAbstractThrowInstruction) { - SSAAbstractThrowInstruction s = (SSAAbstractThrowInstruction) pei; - PointerKey e = heapModel.getPointerKeyForLocal(node, s.getException()); - addNode(exceptionVar); - addNode(e); - addEdge(exceptionVar, e, AssignLabel.noFilter()); - } - - // Account for those exceptions for which we do not actually have a - // points-to set for - // the pei, but just instance keys - Collection types = pei.getExceptionTypes(); - if (types != null) { - for (Iterator it2 = types.iterator(); it2.hasNext();) { - TypeReference type = it2.next(); - if (type != null) { - InstanceKey ik = heapModel.getInstanceKeyForPEI(node, peiLoc, type); - if (ik == null) { - // ugh. hope someone somewhere else knows what they are doing. - // this is probably due to analysis scope exclusions. - continue; - } - if (!(ik instanceof ConcreteTypeKey)) { - assert ik instanceof ConcreteTypeKey : "uh oh: need to implement getCaughtException constraints for instance " + ik; - } - ConcreteTypeKey ck = (ConcreteTypeKey) ik; - IClass klass = ck.getType(); - if (PropagationCallGraphBuilder.catches(catchClasses, klass, cha)) { - addNode(exceptionVar); - addNode(ik); - addEdge(exceptionVar, ik, NewLabel.v()); - } - } - } - } - } - } - - /** - * add constraints for reference constants assigned to vars - */ - protected void addNodeConstantConstraints(CGNode node, IR ir) { - SymbolTable symbolTable = ir.getSymbolTable(); - for (int i = 1; i <= symbolTable.getMaxValueNumber(); i++) { - if (symbolTable.isConstant(i)) { - Object v = symbolTable.getConstantValue(i); - if (!(v instanceof Number)) { - Object S = symbolTable.getConstantValue(i); - TypeReference type = node.getMethod().getDeclaringClass().getClassLoader().getLanguage().getConstantType(S); - if (type != null) { - InstanceKey ik = heapModel.getInstanceKeyForConstant(type, S); - if (ik != null) { - PointerKey pk = heapModel.getPointerKeyForLocal(node, i); - addNode(pk); - addNode(ik); - addEdge(pk, ik, NewLabel.v()); - } - } - } - } - } - } - -} +/******************************************************************************* + * 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. + * + * This file is a derivative of code released by the University of + * California under the terms listed below. + * + * Refinement Analysis Tools is Copyright (c) 2007 The Regents of the + * University of California (Regents). Provided that this notice and + * the following two paragraphs are included in any distribution of + * Refinement Analysis Tools or its derivative work, Regents agrees + * not to assert any of Regents' copyright rights in Refinement + * Analysis Tools against recipient for recipient's reproduction, + * preparation of derivative works, public display, public + * performance, distribution or sublicensing of Refinement Analysis + * Tools and derivative works, in source code and object code form. + * This agreement not to assert does not confer, by implication, + * estoppel, or otherwise any license or rights in any intellectual + * property of Regents, including, but not limited to, any patents + * of Regents or Regents' employees. + * + * IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, + * INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, + * INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE + * AND ITS DOCUMENTATION, EVEN IF REGENTS HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE AND FURTHER DISCLAIMS ANY STATUTORY + * WARRANTY OF NON-INFRINGEMENT. THE SOFTWARE AND ACCOMPANYING + * DOCUMENTATION, IF ANY, PROVIDED HEREUNDER IS PROVIDED "AS + * IS". REGENTS HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, + * UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + */ +package com.ibm.wala.demandpa.flowgraph; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import com.ibm.wala.classLoader.CallSiteReference; +import com.ibm.wala.classLoader.IClass; +import com.ibm.wala.classLoader.IField; +import com.ibm.wala.classLoader.ProgramCounter; +import com.ibm.wala.demandpa.flowgraph.DemandPointerFlowGraph.NewMultiDimInfo; +import com.ibm.wala.demandpa.flowgraph.IFlowLabel.IFlowLabelVisitor; +import com.ibm.wala.demandpa.util.ArrayContents; +import com.ibm.wala.demandpa.util.MemoryAccess; +import com.ibm.wala.demandpa.util.MemoryAccessMap; +import com.ibm.wala.ipa.callgraph.CGNode; +import com.ibm.wala.ipa.callgraph.CallGraph; +import com.ibm.wala.ipa.callgraph.propagation.ArrayContentsKey; +import com.ibm.wala.ipa.callgraph.propagation.ConcreteTypeKey; +import com.ibm.wala.ipa.callgraph.propagation.HeapModel; +import com.ibm.wala.ipa.callgraph.propagation.InstanceKey; +import com.ibm.wala.ipa.callgraph.propagation.LocalPointerKey; +import com.ibm.wala.ipa.callgraph.propagation.NormalAllocationInNode; +import com.ibm.wala.ipa.callgraph.propagation.PointerKey; +import com.ibm.wala.ipa.callgraph.propagation.PropagationCallGraphBuilder; +import com.ibm.wala.ipa.callgraph.propagation.ReturnValueKey; +import com.ibm.wala.ipa.callgraph.propagation.SSAPropagationCallGraphBuilder; +import com.ibm.wala.ipa.callgraph.propagation.StaticFieldKey; +import com.ibm.wala.ipa.cha.IClassHierarchy; +import com.ibm.wala.ssa.IR; +import com.ibm.wala.ssa.SSAAbstractInvokeInstruction; +import com.ibm.wala.ssa.SSAAbstractThrowInstruction; +import com.ibm.wala.ssa.SSAArrayLoadInstruction; +import com.ibm.wala.ssa.SSAArrayStoreInstruction; +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.SSAPutInstruction; +import com.ibm.wala.ssa.SymbolTable; +import com.ibm.wala.types.TypeReference; +import com.ibm.wala.util.collections.EmptyIterator; +import com.ibm.wala.util.collections.HashMapFactory; +import com.ibm.wala.util.collections.MapUtil; +import com.ibm.wala.util.collections.Pair; +import com.ibm.wala.util.debug.Assertions; +import com.ibm.wala.util.graph.labeled.SlowSparseNumberedLabeledGraph; + +/** + * A graph whose edges are labeled with {@link IFlowLabel}s. + * + * @author Manu Sridharan + * + */ +public abstract class AbstractFlowGraph extends SlowSparseNumberedLabeledGraph implements IFlowGraph { + + private final static IFlowLabel defaultLabel = new IFlowLabel() { + public IFlowLabel bar() { + return defaultLabel; + } + + public boolean isBarred() { + return false; + } + + public void visit(IFlowLabelVisitor v, Object dst) { + } + + }; + + /** + * Map: LocalPointerKey -> SSAInvokeInstruction. If we have (x, foo()), that means that x was def'fed by the return value from the + * call to foo() + */ + protected final Map callDefs = HashMapFactory.make(); + + /** + * Map: {@link LocalPointerKey} -> Set<{@link SSAInvokeInstruction}>. If we have (x, foo()), that means x was passed as a + * parameter to the call to foo(). The parameter position is not represented and must be recovered. + */ + protected final Map> callParams = HashMapFactory.make(); + + /** + * Map: LocalPointerKey -> CGNode. If we have (x, foo), then x is a parameter of method foo. For now, we have to re-discover the + * parameter position. TODO this should just be a set; we can get the CGNode from the {@link LocalPointerKey} + */ + protected final Map params = HashMapFactory.make(); + + /** + * Map: {@link LocalPointerKey} -> {@link CGNode}. If we have (x, foo), then x is a return value of method foo. Must re-discover + * if x is normal or exceptional return value. + */ + protected final Map returns = HashMapFactory.make(); + + protected final MemoryAccessMap mam; + + protected final HeapModel heapModel; + + protected final IClassHierarchy cha; + + protected final CallGraph cg; + + public AbstractFlowGraph(MemoryAccessMap mam, HeapModel heapModel, IClassHierarchy cha, CallGraph cg) { + super(defaultLabel); + this.mam = mam; + this.heapModel = heapModel; + this.cha = cha; + this.cg = cg; + } + + /* + * @see com.ibm.wala.demandpa.flowgraph.IFlowLabelGraph#visitSuccs(java.lang.Object, + * com.ibm.wala.demandpa.flowgraph.IFlowLabel.IFlowLabelVisitor) + */ + public void visitSuccs(Object node, IFlowLabelVisitor v) { + for (Iterator succLabelIter = getSuccLabels(node); succLabelIter.hasNext();) { + final IFlowLabel label = succLabelIter.next(); + for (Iterator succNodeIter = getSuccNodes(node, label); succNodeIter.hasNext();) { + label.visit(v, succNodeIter.next()); + } + } + } + + /* + * @see com.ibm.wala.demandpa.flowgraph.IFlowLabelGraph#visitPreds(java.lang.Object, + * com.ibm.wala.demandpa.flowgraph.IFlowLabel.IFlowLabelVisitor) + */ + public void visitPreds(Object node, IFlowLabelVisitor v) { + for (Iterator predLabelIter = getPredLabels(node); predLabelIter.hasNext();) { + final IFlowLabel label = predLabelIter.next(); + for (Iterator predNodeIter = getPredNodes(node, label); predNodeIter.hasNext();) { + label.visit(v, predNodeIter.next()); + } + } + } + + /** + * For each invocation in the method, add nodes for actual parameters and return values + * + * @param node + */ + protected void addNodesForInvocations(CGNode node, IR ir) { + for (Iterator iter = ir.iterateCallSites(); iter.hasNext();) { + CallSiteReference site = iter.next(); + SSAAbstractInvokeInstruction[] calls = ir.getCalls(site); + for (SSAAbstractInvokeInstruction invokeInstr : calls) { + for (int i = 0; i < invokeInstr.getNumberOfUses(); i++) { + // just make nodes for parameters; we'll get to them when + // traversing + // from the callee + PointerKey use = heapModel.getPointerKeyForLocal(node, invokeInstr.getUse(i)); + addNode(use); + Set s = MapUtil.findOrCreateSet(callParams, use); + s.add((SSAInvokeInstruction) invokeInstr); + } + + // for any def'd values, keep track of the fact that they are def'd + // by a call + if (invokeInstr.hasDef()) { + PointerKey def = heapModel.getPointerKeyForLocal(node, invokeInstr.getDef()); + addNode(def); + callDefs.put(def, (SSAInvokeInstruction) invokeInstr); + } + PointerKey exc = heapModel.getPointerKeyForLocal(node, invokeInstr.getException()); + addNode(exc); + callDefs.put(exc, (SSAInvokeInstruction) invokeInstr); + + } + } + } + + public boolean isParam(LocalPointerKey pk) { + return params.get(pk) != null; + } + + public Iterator getInstrsPassingParam(LocalPointerKey pk) { + Set instrs = callParams.get(pk); + if (instrs == null) { + return EmptyIterator.instance(); + } else { + return instrs.iterator(); + } + } + + public SSAInvokeInstruction getInstrReturningTo(LocalPointerKey pk) { + return callDefs.get(pk); + } + + public Iterator getWritesToStaticField(StaticFieldKey sfk) throws IllegalArgumentException { + if (sfk == null) { + throw new IllegalArgumentException("sfk == null"); + } + Collection fieldWrites = mam.getStaticFieldWrites(sfk.getField()); + for (MemoryAccess a : fieldWrites) { + addSubgraphForNode(a.getNode()); + } + return getSuccNodes(sfk, AssignGlobalLabel.v()); + } + + public Iterator getReadsOfStaticField(StaticFieldKey sfk) throws IllegalArgumentException { + if (sfk == null) { + throw new IllegalArgumentException("sfk == null"); + } + Collection fieldReads = mam.getStaticFieldReads(sfk.getField()); + for (MemoryAccess a : fieldReads) { + addSubgraphForNode(a.getNode()); + } + return getPredNodes(sfk, AssignGlobalLabel.v()); + } + + public Iterator getWritesToInstanceField(PointerKey pk, IField f) { + // TODO: cache this!! + if (f == ArrayContents.v()) { + return getArrayWrites(pk); + } + pk = convertPointerKeyToHeapModel(pk, mam.getHeapModel()); + Collection writes = mam.getFieldWrites(pk, f); + for (MemoryAccess a : writes) { + addSubgraphForNode(a.getNode()); + } + ArrayList written = new ArrayList(); + for (MemoryAccess a : writes) { + IR ir = a.getNode().getIR(); + SSAPutInstruction s = (SSAPutInstruction) ir.getInstructions()[a.getInstructionIndex()]; + if (s == null) { + // s can be null because the memory access map may be constructed from bytecode, + // and the write instruction may have been eliminated from SSA because it's dead + // TODO clean this up + continue; + } + PointerKey r = heapModel.getPointerKeyForLocal(a.getNode(), s.getVal()); + // if (Assertions.verifyAssertions) { + // Assertions._assert(containsNode(r)); + // } + written.add(r); + } + return written.iterator(); + } + + /** + * convert a pointer key to one in the memory access map's heap model + * + * TODO move this somewhere more appropriate + * + * @throws UnsupportedOperationException if it doesn't know how to handle a {@link PointerKey} + */ + public static PointerKey convertPointerKeyToHeapModel(PointerKey pk, HeapModel h) { + if (pk == null) { + throw new IllegalArgumentException("null pk"); + } + if (pk instanceof LocalPointerKey) { + LocalPointerKey lpk = (LocalPointerKey) pk; + return h.getPointerKeyForLocal(lpk.getNode(), lpk.getValueNumber()); + } else if (pk instanceof ArrayContentsKey) { + ArrayContentsKey ack = (ArrayContentsKey) pk; + InstanceKey ik = ack.getInstanceKey(); + if (ik instanceof NormalAllocationInNode) { + NormalAllocationInNode nain = (NormalAllocationInNode) ik; + ik = h.getInstanceKeyForAllocation(nain.getNode(), nain.getSite()); + } else { + assert false : "need to handle " + ik.getClass(); + } + return h.getPointerKeyForArrayContents(ik); + } else if (pk instanceof ReturnValueKey) { + ReturnValueKey rvk = (ReturnValueKey) pk; + return h.getPointerKeyForReturnValue(rvk.getNode()); + } + throw new UnsupportedOperationException("need to handle " + pk.getClass()); + } + + public Iterator getReadsOfInstanceField(PointerKey pk, IField f) { + // TODO: cache this!! + if (f == ArrayContents.v()) { + return getArrayReads(pk); + } + pk = convertPointerKeyToHeapModel(pk, mam.getHeapModel()); + Collection reads = mam.getFieldReads(pk, f); + for (MemoryAccess a : reads) { + addSubgraphForNode(a.getNode()); + } + ArrayList readInto = new ArrayList(); + for (MemoryAccess a : reads) { + IR ir = a.getNode().getIR(); + SSAGetInstruction s = (SSAGetInstruction) ir.getInstructions()[a.getInstructionIndex()]; + if (s == null) { + // actually dead code + continue; + } + PointerKey r = heapModel.getPointerKeyForLocal(a.getNode(), s.getDef()); + // if (Assertions.verifyAssertions) { + // Assertions._assert(containsNode(r)); + // } + readInto.add(r); + } + return readInto.iterator(); + } + + Iterator getArrayWrites(PointerKey arrayRef) { + arrayRef = convertPointerKeyToHeapModel(arrayRef, mam.getHeapModel()); + Collection arrayWrites = mam.getArrayWrites(arrayRef); + for (MemoryAccess a : arrayWrites) { + addSubgraphForNode(a.getNode()); + } + ArrayList written = new ArrayList(); + for (MemoryAccess a : arrayWrites) { + final CGNode node = a.getNode(); + IR ir = node.getIR(); + SSAInstruction instruction = ir.getInstructions()[a.getInstructionIndex()]; + if (instruction == null) { + // this means the array store found was in fact dead code + // TODO detect this earlier and don't keep it in the MemoryAccessMap + continue; + } + if (instruction instanceof SSAArrayStoreInstruction) { + SSAArrayStoreInstruction s = (SSAArrayStoreInstruction) instruction; + PointerKey r = heapModel.getPointerKeyForLocal(node, s.getValue()); + written.add(r); + } else if (instruction instanceof SSANewInstruction) { + NewMultiDimInfo multiDimInfo = DemandPointerFlowGraph.getInfoForNewMultiDim((SSANewInstruction) instruction, heapModel, + node); + for (Pair arrStoreInstr : multiDimInfo.arrStoreInstrs) { + written.add(arrStoreInstr.snd); + } + } else { + Assertions.UNREACHABLE(); + } + } + return written.iterator(); + } + + protected Iterator getArrayReads(PointerKey arrayRef) { + arrayRef = convertPointerKeyToHeapModel(arrayRef, mam.getHeapModel()); + Collection arrayReads = mam.getArrayReads(arrayRef); + for (Iterator it = arrayReads.iterator(); it.hasNext();) { + MemoryAccess a = it.next(); + addSubgraphForNode(a.getNode()); + } + ArrayList read = new ArrayList(); + for (Iterator it = arrayReads.iterator(); it.hasNext();) { + MemoryAccess a = it.next(); + IR ir = a.getNode().getIR(); + SSAArrayLoadInstruction s = (SSAArrayLoadInstruction) ir.getInstructions()[a.getInstructionIndex()]; + if (s == null) { + // actually dead code + continue; + } + PointerKey r = heapModel.getPointerKeyForLocal(a.getNode(), s.getDef()); + // if (Assertions.verifyAssertions) { + // Assertions._assert(containsNode(r)); + // } + read.add(r); + } + return read.iterator(); + } + + /** + * Add constraints to represent the flow of exceptions to the exceptional return value for this node + */ + protected void addNodePassthruExceptionConstraints(CGNode node, IR ir) { + // add constraints relating to thrown exceptions that reach the exit + // block. + List peis = SSAPropagationCallGraphBuilder.getIncomingPEIs(ir, ir.getExitBlock()); + PointerKey exception = heapModel.getPointerKeyForExceptionalReturnValue(node); + IClass c = node.getClassHierarchy().lookupClass(TypeReference.JavaLangThrowable); + + addExceptionDefConstraints(ir, node, peis, exception, Collections.singleton(c)); + } + + /** + * Generate constraints which assign exception values into an exception pointer + * + * @param node governing node + * @param peis list of PEI instructions + * @param exceptionVar PointerKey representing a pointer to an exception value + * @param catchClasses the types "caught" by the exceptionVar + */ + protected void addExceptionDefConstraints(IR ir, CGNode node, List peis, PointerKey exceptionVar, + Set catchClasses) { + for (Iterator it = peis.iterator(); it.hasNext();) { + ProgramCounter peiLoc = it.next(); + SSAInstruction pei = ir.getPEI(peiLoc); + + if (pei instanceof SSAAbstractInvokeInstruction) { + SSAAbstractInvokeInstruction s = (SSAAbstractInvokeInstruction) pei; + PointerKey e = heapModel.getPointerKeyForLocal(node, s.getException()); + addNode(exceptionVar); + addNode(e); + addEdge(exceptionVar, e, AssignLabel.noFilter()); + + } else if (pei instanceof SSAAbstractThrowInstruction) { + SSAAbstractThrowInstruction s = (SSAAbstractThrowInstruction) pei; + PointerKey e = heapModel.getPointerKeyForLocal(node, s.getException()); + addNode(exceptionVar); + addNode(e); + addEdge(exceptionVar, e, AssignLabel.noFilter()); + } + + // Account for those exceptions for which we do not actually have a + // points-to set for + // the pei, but just instance keys + Collection types = pei.getExceptionTypes(); + if (types != null) { + for (Iterator it2 = types.iterator(); it2.hasNext();) { + TypeReference type = it2.next(); + if (type != null) { + InstanceKey ik = heapModel.getInstanceKeyForPEI(node, peiLoc, type); + if (ik == null) { + // ugh. hope someone somewhere else knows what they are doing. + // this is probably due to analysis scope exclusions. + continue; + } + if (!(ik instanceof ConcreteTypeKey)) { + assert ik instanceof ConcreteTypeKey : "uh oh: need to implement getCaughtException constraints for instance " + ik; + } + ConcreteTypeKey ck = (ConcreteTypeKey) ik; + IClass klass = ck.getType(); + if (PropagationCallGraphBuilder.catches(catchClasses, klass, cha)) { + addNode(exceptionVar); + addNode(ik); + addEdge(exceptionVar, ik, NewLabel.v()); + } + } + } + } + } + } + + /** + * add constraints for reference constants assigned to vars + */ + protected void addNodeConstantConstraints(CGNode node, IR ir) { + SymbolTable symbolTable = ir.getSymbolTable(); + for (int i = 1; i <= symbolTable.getMaxValueNumber(); i++) { + if (symbolTable.isConstant(i)) { + Object v = symbolTable.getConstantValue(i); + if (!(v instanceof Number)) { + Object S = symbolTable.getConstantValue(i); + TypeReference type = node.getMethod().getDeclaringClass().getClassLoader().getLanguage().getConstantType(S); + if (type != null) { + InstanceKey ik = heapModel.getInstanceKeyForConstant(type, S); + if (ik != null) { + PointerKey pk = heapModel.getPointerKeyForLocal(node, i); + addNode(pk); + addNode(ik); + addEdge(pk, ik, NewLabel.v()); + } + } + } + } + } + } + +} diff --git a/com.ibm.wala.core/src/com/ibm/wala/demandpa/flowgraph/AbstractFlowLabelVisitor.java b/com.ibm.wala.core/src/com/ibm/wala/demandpa/flowgraph/AbstractFlowLabelVisitor.java index cb8f62aeb..2bf727da7 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/demandpa/flowgraph/AbstractFlowLabelVisitor.java +++ b/com.ibm.wala.core/src/com/ibm/wala/demandpa/flowgraph/AbstractFlowLabelVisitor.java @@ -1,114 +1,114 @@ -/******************************************************************************* - * 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. - * - * This file is a derivative of code released by the University of - * California under the terms listed below. - * - * Refinement Analysis Tools is Copyright (c) 2007 The Regents of the - * University of California (Regents). Provided that this notice and - * the following two paragraphs are included in any distribution of - * Refinement Analysis Tools or its derivative work, Regents agrees - * not to assert any of Regents' copyright rights in Refinement - * Analysis Tools against recipient for recipient's reproduction, - * preparation of derivative works, public display, public - * performance, distribution or sublicensing of Refinement Analysis - * Tools and derivative works, in source code and object code form. - * This agreement not to assert does not confer, by implication, - * estoppel, or otherwise any license or rights in any intellectual - * property of Regents, including, but not limited to, any patents - * of Regents or Regents' employees. - * - * IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, - * INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, - * INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE - * AND ITS DOCUMENTATION, EVEN IF REGENTS HAS BEEN ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE AND FURTHER DISCLAIMS ANY STATUTORY - * WARRANTY OF NON-INFRINGEMENT. THE SOFTWARE AND ACCOMPANYING - * DOCUMENTATION, IF ANY, PROVIDED HEREUNDER IS PROVIDED "AS - * IS". REGENTS HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, - * UPDATES, ENHANCEMENTS, OR MODIFICATIONS. - */ -package com.ibm.wala.demandpa.flowgraph; - -import com.ibm.wala.demandpa.flowgraph.IFlowLabel.IFlowLabelVisitor; - -/** - * An {@link IFlowLabelVisitor} that does nothing. Subclasses can override only - * the label types they care about. - * - * @author Manu Sridharan - * - */ -public class AbstractFlowLabelVisitor implements IFlowLabelVisitor { - - public void visitParam(ParamLabel label, Object dst) { - - } - - public void visitReturn(ReturnLabel label, Object dst) { - - } - - public void visitAssign(AssignLabel label, Object dst) { - - } - - public void visitAssignGlobal(AssignGlobalLabel label, Object dst) { - - } - - public void visitGetField(GetFieldLabel label, Object dst) { - - } - - public void visitMatch(MatchLabel label, Object dst) { - - } - - public void visitNew(NewLabel label, Object dst) { - - } - - public void visitPutField(PutFieldLabel label, Object dst) { - - } - - public void visitAssignGlobalBar(AssignGlobalBarLabel label, Object dst) { - - } - - public void visitAssignBar(AssignBarLabel label, Object dst) { - } - - public void visitGetFieldBar(GetFieldBarLabel label, Object dst) { - - } - - public void visitMatchBar(MatchBarLabel label, Object dst) { - - } - - public void visitNewBar(NewBarLabel label, Object dst) { - - } - - public void visitPutFieldBar(PutFieldBarLabel label, Object dst) { - - } - - public void visitReturnBar(ReturnBarLabel label, Object dst) { - - } - - public void visitParamBar(ParamBarLabel label, Object dst) { - - } - -} +/******************************************************************************* + * 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. + * + * This file is a derivative of code released by the University of + * California under the terms listed below. + * + * Refinement Analysis Tools is Copyright (c) 2007 The Regents of the + * University of California (Regents). Provided that this notice and + * the following two paragraphs are included in any distribution of + * Refinement Analysis Tools or its derivative work, Regents agrees + * not to assert any of Regents' copyright rights in Refinement + * Analysis Tools against recipient for recipient's reproduction, + * preparation of derivative works, public display, public + * performance, distribution or sublicensing of Refinement Analysis + * Tools and derivative works, in source code and object code form. + * This agreement not to assert does not confer, by implication, + * estoppel, or otherwise any license or rights in any intellectual + * property of Regents, including, but not limited to, any patents + * of Regents or Regents' employees. + * + * IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, + * INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, + * INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE + * AND ITS DOCUMENTATION, EVEN IF REGENTS HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE AND FURTHER DISCLAIMS ANY STATUTORY + * WARRANTY OF NON-INFRINGEMENT. THE SOFTWARE AND ACCOMPANYING + * DOCUMENTATION, IF ANY, PROVIDED HEREUNDER IS PROVIDED "AS + * IS". REGENTS HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, + * UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + */ +package com.ibm.wala.demandpa.flowgraph; + +import com.ibm.wala.demandpa.flowgraph.IFlowLabel.IFlowLabelVisitor; + +/** + * An {@link IFlowLabelVisitor} that does nothing. Subclasses can override only + * the label types they care about. + * + * @author Manu Sridharan + * + */ +public class AbstractFlowLabelVisitor implements IFlowLabelVisitor { + + public void visitParam(ParamLabel label, Object dst) { + + } + + public void visitReturn(ReturnLabel label, Object dst) { + + } + + public void visitAssign(AssignLabel label, Object dst) { + + } + + public void visitAssignGlobal(AssignGlobalLabel label, Object dst) { + + } + + public void visitGetField(GetFieldLabel label, Object dst) { + + } + + public void visitMatch(MatchLabel label, Object dst) { + + } + + public void visitNew(NewLabel label, Object dst) { + + } + + public void visitPutField(PutFieldLabel label, Object dst) { + + } + + public void visitAssignGlobalBar(AssignGlobalBarLabel label, Object dst) { + + } + + public void visitAssignBar(AssignBarLabel label, Object dst) { + } + + public void visitGetFieldBar(GetFieldBarLabel label, Object dst) { + + } + + public void visitMatchBar(MatchBarLabel label, Object dst) { + + } + + public void visitNewBar(NewBarLabel label, Object dst) { + + } + + public void visitPutFieldBar(PutFieldBarLabel label, Object dst) { + + } + + public void visitReturnBar(ReturnBarLabel label, Object dst) { + + } + + public void visitParamBar(ParamBarLabel label, Object dst) { + + } + +} diff --git a/com.ibm.wala.core/src/com/ibm/wala/demandpa/flowgraph/AssignBarLabel.java b/com.ibm.wala.core/src/com/ibm/wala/demandpa/flowgraph/AssignBarLabel.java index ab12c1c97..60de67fd3 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/demandpa/flowgraph/AssignBarLabel.java +++ b/com.ibm.wala.core/src/com/ibm/wala/demandpa/flowgraph/AssignBarLabel.java @@ -1,115 +1,115 @@ -/******************************************************************************* - * 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. - * - * This file is a derivative of code released by the University of - * California under the terms listed below. - * - * Refinement Analysis Tools is Copyright (c) 2007 The Regents of the - * University of California (Regents). Provided that this notice and - * the following two paragraphs are included in any distribution of - * Refinement Analysis Tools or its derivative work, Regents agrees - * not to assert any of Regents' copyright rights in Refinement - * Analysis Tools against recipient for recipient's reproduction, - * preparation of derivative works, public display, public - * performance, distribution or sublicensing of Refinement Analysis - * Tools and derivative works, in source code and object code form. - * This agreement not to assert does not confer, by implication, - * estoppel, or otherwise any license or rights in any intellectual - * property of Regents, including, but not limited to, any patents - * of Regents or Regents' employees. - * - * IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, - * INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, - * INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE - * AND ITS DOCUMENTATION, EVEN IF REGENTS HAS BEEN ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE AND FURTHER DISCLAIMS ANY STATUTORY - * WARRANTY OF NON-INFRINGEMENT. THE SOFTWARE AND ACCOMPANYING - * DOCUMENTATION, IF ANY, PROVIDED HEREUNDER IS PROVIDED "AS - * IS". REGENTS HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, - * UPDATES, ENHANCEMENTS, OR MODIFICATIONS. - */ -package com.ibm.wala.demandpa.flowgraph; - -import com.ibm.wala.ipa.callgraph.propagation.FilteredPointerKey.TypeFilter; - -/** - * @author Manu Sridharan - * - */ -public class AssignBarLabel implements IFlowLabelWithFilter { - - private static final AssignBarLabel noFilter = new AssignBarLabel(null); - - private final TypeFilter filter; - - private AssignBarLabel(TypeFilter filter) { - this.filter = filter; - } - - public static AssignBarLabel noFilter() { - return noFilter; - } - - public static AssignBarLabel make(TypeFilter filter) { - return new AssignBarLabel(filter); - } - - /* - * (non-Javadoc) - * @see demandGraph.IFlowLabel#bar() - */ - public AssignLabel bar() { - return (this == noFilter) ? AssignLabel.noFilter() : AssignLabel.make(filter); - } - - /* - * (non-Javadoc) - * @see demandGraph.IFlowLabel#visit(demandGraph.IFlowLabel.IFlowLabelVisitor, java.lang.Object) - */ - public void visit(IFlowLabelVisitor v, Object dst) throws IllegalArgumentException { - if (v == null) { - throw new IllegalArgumentException("v == null"); - } - v.visitAssignBar(this, dst); - } - - public boolean isBarred() { - return true; - } - - @Override - public int hashCode() { - final int prime = 31; - int result = 1; - result = prime * result + ((filter == null) ? 0 : filter.hashCode()); - return result; - } - - @Override - public boolean equals(Object obj) { - if (this == obj) - return true; - if (obj == null) - return false; - if (getClass() != obj.getClass()) - return false; - final AssignBarLabel other = (AssignBarLabel) obj; - if (filter == null) { - if (other.filter != null) - return false; - } else if (!filter.equals(other.filter)) - return false; - return true; - } - - public TypeFilter getFilter() { - return filter; - } -} +/******************************************************************************* + * 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. + * + * This file is a derivative of code released by the University of + * California under the terms listed below. + * + * Refinement Analysis Tools is Copyright (c) 2007 The Regents of the + * University of California (Regents). Provided that this notice and + * the following two paragraphs are included in any distribution of + * Refinement Analysis Tools or its derivative work, Regents agrees + * not to assert any of Regents' copyright rights in Refinement + * Analysis Tools against recipient for recipient's reproduction, + * preparation of derivative works, public display, public + * performance, distribution or sublicensing of Refinement Analysis + * Tools and derivative works, in source code and object code form. + * This agreement not to assert does not confer, by implication, + * estoppel, or otherwise any license or rights in any intellectual + * property of Regents, including, but not limited to, any patents + * of Regents or Regents' employees. + * + * IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, + * INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, + * INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE + * AND ITS DOCUMENTATION, EVEN IF REGENTS HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE AND FURTHER DISCLAIMS ANY STATUTORY + * WARRANTY OF NON-INFRINGEMENT. THE SOFTWARE AND ACCOMPANYING + * DOCUMENTATION, IF ANY, PROVIDED HEREUNDER IS PROVIDED "AS + * IS". REGENTS HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, + * UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + */ +package com.ibm.wala.demandpa.flowgraph; + +import com.ibm.wala.ipa.callgraph.propagation.FilteredPointerKey.TypeFilter; + +/** + * @author Manu Sridharan + * + */ +public class AssignBarLabel implements IFlowLabelWithFilter { + + private static final AssignBarLabel noFilter = new AssignBarLabel(null); + + private final TypeFilter filter; + + private AssignBarLabel(TypeFilter filter) { + this.filter = filter; + } + + public static AssignBarLabel noFilter() { + return noFilter; + } + + public static AssignBarLabel make(TypeFilter filter) { + return new AssignBarLabel(filter); + } + + /* + * (non-Javadoc) + * @see demandGraph.IFlowLabel#bar() + */ + public AssignLabel bar() { + return (this == noFilter) ? AssignLabel.noFilter() : AssignLabel.make(filter); + } + + /* + * (non-Javadoc) + * @see demandGraph.IFlowLabel#visit(demandGraph.IFlowLabel.IFlowLabelVisitor, java.lang.Object) + */ + public void visit(IFlowLabelVisitor v, Object dst) throws IllegalArgumentException { + if (v == null) { + throw new IllegalArgumentException("v == null"); + } + v.visitAssignBar(this, dst); + } + + public boolean isBarred() { + return true; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((filter == null) ? 0 : filter.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + final AssignBarLabel other = (AssignBarLabel) obj; + if (filter == null) { + if (other.filter != null) + return false; + } else if (!filter.equals(other.filter)) + return false; + return true; + } + + public TypeFilter getFilter() { + return filter; + } +} diff --git a/com.ibm.wala.core/src/com/ibm/wala/demandpa/flowgraph/AssignGlobalBarLabel.java b/com.ibm.wala.core/src/com/ibm/wala/demandpa/flowgraph/AssignGlobalBarLabel.java index 7c6659da4..3baaa6005 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/demandpa/flowgraph/AssignGlobalBarLabel.java +++ b/com.ibm.wala.core/src/com/ibm/wala/demandpa/flowgraph/AssignGlobalBarLabel.java @@ -1,86 +1,86 @@ -/******************************************************************************* - * 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. - * - * This file is a derivative of code released by the University of - * California under the terms listed below. - * - * Refinement Analysis Tools is Copyright (c) 2007 The Regents of the - * University of California (Regents). Provided that this notice and - * the following two paragraphs are included in any distribution of - * Refinement Analysis Tools or its derivative work, Regents agrees - * not to assert any of Regents' copyright rights in Refinement - * Analysis Tools against recipient for recipient's reproduction, - * preparation of derivative works, public display, public - * performance, distribution or sublicensing of Refinement Analysis - * Tools and derivative works, in source code and object code form. - * This agreement not to assert does not confer, by implication, - * estoppel, or otherwise any license or rights in any intellectual - * property of Regents, including, but not limited to, any patents - * of Regents or Regents' employees. - * - * IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, - * INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, - * INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE - * AND ITS DOCUMENTATION, EVEN IF REGENTS HAS BEEN ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE AND FURTHER DISCLAIMS ANY STATUTORY - * WARRANTY OF NON-INFRINGEMENT. THE SOFTWARE AND ACCOMPANYING - * DOCUMENTATION, IF ANY, PROVIDED HEREUNDER IS PROVIDED "AS - * IS". REGENTS HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, - * UPDATES, ENHANCEMENTS, OR MODIFICATIONS. - */ -package com.ibm.wala.demandpa.flowgraph; - -/** - * @author Manu Sridharan - * - */ -public class AssignGlobalBarLabel implements IFlowLabel { - - private static final AssignGlobalBarLabel theInstance = new AssignGlobalBarLabel(); - - private AssignGlobalBarLabel() { - } - - public static AssignGlobalBarLabel v() { - return theInstance; - } - - /* - * (non-Javadoc) - * - * @see demandGraph.IFlowLabel#bar() - */ - public AssignGlobalLabel bar() { - return AssignGlobalLabel.v(); - } - - /* - * (non-Javadoc) - * - * @see demandGraph.IFlowLabel#visit(demandGraph.IFlowLabel.IFlowLabelVisitor, - * java.lang.Object) - */ - public void visit(IFlowLabelVisitor v, Object dst) throws IllegalArgumentException { - if (v == null) { - throw new IllegalArgumentException("v == null"); - } - v.visitAssignGlobalBar(this, dst); - } - - public boolean isBarred() { - return true; - } - - @Override - public String toString() { - return "assignGlobalBar"; - } - -} +/******************************************************************************* + * 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. + * + * This file is a derivative of code released by the University of + * California under the terms listed below. + * + * Refinement Analysis Tools is Copyright (c) 2007 The Regents of the + * University of California (Regents). Provided that this notice and + * the following two paragraphs are included in any distribution of + * Refinement Analysis Tools or its derivative work, Regents agrees + * not to assert any of Regents' copyright rights in Refinement + * Analysis Tools against recipient for recipient's reproduction, + * preparation of derivative works, public display, public + * performance, distribution or sublicensing of Refinement Analysis + * Tools and derivative works, in source code and object code form. + * This agreement not to assert does not confer, by implication, + * estoppel, or otherwise any license or rights in any intellectual + * property of Regents, including, but not limited to, any patents + * of Regents or Regents' employees. + * + * IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, + * INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, + * INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE + * AND ITS DOCUMENTATION, EVEN IF REGENTS HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE AND FURTHER DISCLAIMS ANY STATUTORY + * WARRANTY OF NON-INFRINGEMENT. THE SOFTWARE AND ACCOMPANYING + * DOCUMENTATION, IF ANY, PROVIDED HEREUNDER IS PROVIDED "AS + * IS". REGENTS HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, + * UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + */ +package com.ibm.wala.demandpa.flowgraph; + +/** + * @author Manu Sridharan + * + */ +public class AssignGlobalBarLabel implements IFlowLabel { + + private static final AssignGlobalBarLabel theInstance = new AssignGlobalBarLabel(); + + private AssignGlobalBarLabel() { + } + + public static AssignGlobalBarLabel v() { + return theInstance; + } + + /* + * (non-Javadoc) + * + * @see demandGraph.IFlowLabel#bar() + */ + public AssignGlobalLabel bar() { + return AssignGlobalLabel.v(); + } + + /* + * (non-Javadoc) + * + * @see demandGraph.IFlowLabel#visit(demandGraph.IFlowLabel.IFlowLabelVisitor, + * java.lang.Object) + */ + public void visit(IFlowLabelVisitor v, Object dst) throws IllegalArgumentException { + if (v == null) { + throw new IllegalArgumentException("v == null"); + } + v.visitAssignGlobalBar(this, dst); + } + + public boolean isBarred() { + return true; + } + + @Override + public String toString() { + return "assignGlobalBar"; + } + +} diff --git a/com.ibm.wala.core/src/com/ibm/wala/demandpa/flowgraph/AssignGlobalLabel.java b/com.ibm.wala.core/src/com/ibm/wala/demandpa/flowgraph/AssignGlobalLabel.java index 1ba03d261..942971535 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/demandpa/flowgraph/AssignGlobalLabel.java +++ b/com.ibm.wala.core/src/com/ibm/wala/demandpa/flowgraph/AssignGlobalLabel.java @@ -1,69 +1,69 @@ -/******************************************************************************* - * 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. - * - * This file is a derivative of code released by the University of - * California under the terms listed below. - * - * Refinement Analysis Tools is Copyright (c) 2007 The Regents of the - * University of California (Regents). Provided that this notice and - * the following two paragraphs are included in any distribution of - * Refinement Analysis Tools or its derivative work, Regents agrees - * not to assert any of Regents' copyright rights in Refinement - * Analysis Tools against recipient for recipient's reproduction, - * preparation of derivative works, public display, public - * performance, distribution or sublicensing of Refinement Analysis - * Tools and derivative works, in source code and object code form. - * This agreement not to assert does not confer, by implication, - * estoppel, or otherwise any license or rights in any intellectual - * property of Regents, including, but not limited to, any patents - * of Regents or Regents' employees. - * - * IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, - * INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, - * INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE - * AND ITS DOCUMENTATION, EVEN IF REGENTS HAS BEEN ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE AND FURTHER DISCLAIMS ANY STATUTORY - * WARRANTY OF NON-INFRINGEMENT. THE SOFTWARE AND ACCOMPANYING - * DOCUMENTATION, IF ANY, PROVIDED HEREUNDER IS PROVIDED "AS - * IS". REGENTS HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, - * UPDATES, ENHANCEMENTS, OR MODIFICATIONS. - */ -package com.ibm.wala.demandpa.flowgraph; - -public class AssignGlobalLabel implements IFlowLabel { - private static final AssignGlobalLabel theInstance = new AssignGlobalLabel(); - - private AssignGlobalLabel() { - } - - public static AssignGlobalLabel v() { - return theInstance; - } - - public void visit(IFlowLabelVisitor v, Object dst) throws IllegalArgumentException { - if (v == null) { - throw new IllegalArgumentException("v == null"); - } - v.visitAssignGlobal(this, dst); - } - - public AssignGlobalBarLabel bar() { - return AssignGlobalBarLabel.v(); - } - - public boolean isBarred() { - return false; - } - - @Override - public String toString() { - return "assignGlobal"; - } -} +/******************************************************************************* + * 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. + * + * This file is a derivative of code released by the University of + * California under the terms listed below. + * + * Refinement Analysis Tools is Copyright (c) 2007 The Regents of the + * University of California (Regents). Provided that this notice and + * the following two paragraphs are included in any distribution of + * Refinement Analysis Tools or its derivative work, Regents agrees + * not to assert any of Regents' copyright rights in Refinement + * Analysis Tools against recipient for recipient's reproduction, + * preparation of derivative works, public display, public + * performance, distribution or sublicensing of Refinement Analysis + * Tools and derivative works, in source code and object code form. + * This agreement not to assert does not confer, by implication, + * estoppel, or otherwise any license or rights in any intellectual + * property of Regents, including, but not limited to, any patents + * of Regents or Regents' employees. + * + * IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, + * INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, + * INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE + * AND ITS DOCUMENTATION, EVEN IF REGENTS HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE AND FURTHER DISCLAIMS ANY STATUTORY + * WARRANTY OF NON-INFRINGEMENT. THE SOFTWARE AND ACCOMPANYING + * DOCUMENTATION, IF ANY, PROVIDED HEREUNDER IS PROVIDED "AS + * IS". REGENTS HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, + * UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + */ +package com.ibm.wala.demandpa.flowgraph; + +public class AssignGlobalLabel implements IFlowLabel { + private static final AssignGlobalLabel theInstance = new AssignGlobalLabel(); + + private AssignGlobalLabel() { + } + + public static AssignGlobalLabel v() { + return theInstance; + } + + public void visit(IFlowLabelVisitor v, Object dst) throws IllegalArgumentException { + if (v == null) { + throw new IllegalArgumentException("v == null"); + } + v.visitAssignGlobal(this, dst); + } + + public AssignGlobalBarLabel bar() { + return AssignGlobalBarLabel.v(); + } + + public boolean isBarred() { + return false; + } + + @Override + public String toString() { + return "assignGlobal"; + } +} diff --git a/com.ibm.wala.core/src/com/ibm/wala/demandpa/flowgraph/AssignLabel.java b/com.ibm.wala.core/src/com/ibm/wala/demandpa/flowgraph/AssignLabel.java index abc5fc0cd..9a8e12eff 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/demandpa/flowgraph/AssignLabel.java +++ b/com.ibm.wala.core/src/com/ibm/wala/demandpa/flowgraph/AssignLabel.java @@ -1,108 +1,108 @@ -/******************************************************************************* - * 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. - * - * This file is a derivative of code released by the University of - * California under the terms listed below. - * - * Refinement Analysis Tools is Copyright (c) 2007 The Regents of the - * University of California (Regents). Provided that this notice and - * the following two paragraphs are included in any distribution of - * Refinement Analysis Tools or its derivative work, Regents agrees - * not to assert any of Regents' copyright rights in Refinement - * Analysis Tools against recipient for recipient's reproduction, - * preparation of derivative works, public display, public - * performance, distribution or sublicensing of Refinement Analysis - * Tools and derivative works, in source code and object code form. - * This agreement not to assert does not confer, by implication, - * estoppel, or otherwise any license or rights in any intellectual - * property of Regents, including, but not limited to, any patents - * of Regents or Regents' employees. - * - * IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, - * INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, - * INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE - * AND ITS DOCUMENTATION, EVEN IF REGENTS HAS BEEN ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE AND FURTHER DISCLAIMS ANY STATUTORY - * WARRANTY OF NON-INFRINGEMENT. THE SOFTWARE AND ACCOMPANYING - * DOCUMENTATION, IF ANY, PROVIDED HEREUNDER IS PROVIDED "AS - * IS". REGENTS HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, - * UPDATES, ENHANCEMENTS, OR MODIFICATIONS. - */ -package com.ibm.wala.demandpa.flowgraph; - -import com.ibm.wala.ipa.callgraph.propagation.FilteredPointerKey.TypeFilter; - -public class AssignLabel implements IFlowLabelWithFilter { - - private static final AssignLabel noFilter = new AssignLabel(null); - - private final TypeFilter filter; - - private AssignLabel(TypeFilter filter) { - this.filter = filter; - } - - @Override - public int hashCode() { - final int prime = 31; - int result = 1; - result = prime * result + ((filter == null) ? 0 : filter.hashCode()); - return result; - } - - @Override - public boolean equals(Object obj) { - if (this == obj) - return true; - if (obj == null) - return false; - if (getClass() != obj.getClass()) - return false; - final AssignLabel other = (AssignLabel) obj; - if (filter == null) { - if (other.filter != null) - return false; - } else if (!filter.equals(other.filter)) - return false; - return true; - } - - public static AssignLabel noFilter() { - return noFilter; - } - - public static AssignLabel make(TypeFilter filter) { - return new AssignLabel(filter); - } - - public void visit(IFlowLabelVisitor v, Object dst) throws IllegalArgumentException { - if (v == null) { - throw new IllegalArgumentException("v == null"); - } - v.visitAssign(this, dst); - } - - public AssignBarLabel bar() { - return this == noFilter ? AssignBarLabel.noFilter() : AssignBarLabel.make(filter); - } - - @Override - public String toString() { - return "assign"; - } - - public boolean isBarred() { - return false; - } - - public TypeFilter getFilter() { - return filter; - } -} +/******************************************************************************* + * 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. + * + * This file is a derivative of code released by the University of + * California under the terms listed below. + * + * Refinement Analysis Tools is Copyright (c) 2007 The Regents of the + * University of California (Regents). Provided that this notice and + * the following two paragraphs are included in any distribution of + * Refinement Analysis Tools or its derivative work, Regents agrees + * not to assert any of Regents' copyright rights in Refinement + * Analysis Tools against recipient for recipient's reproduction, + * preparation of derivative works, public display, public + * performance, distribution or sublicensing of Refinement Analysis + * Tools and derivative works, in source code and object code form. + * This agreement not to assert does not confer, by implication, + * estoppel, or otherwise any license or rights in any intellectual + * property of Regents, including, but not limited to, any patents + * of Regents or Regents' employees. + * + * IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, + * INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, + * INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE + * AND ITS DOCUMENTATION, EVEN IF REGENTS HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE AND FURTHER DISCLAIMS ANY STATUTORY + * WARRANTY OF NON-INFRINGEMENT. THE SOFTWARE AND ACCOMPANYING + * DOCUMENTATION, IF ANY, PROVIDED HEREUNDER IS PROVIDED "AS + * IS". REGENTS HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, + * UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + */ +package com.ibm.wala.demandpa.flowgraph; + +import com.ibm.wala.ipa.callgraph.propagation.FilteredPointerKey.TypeFilter; + +public class AssignLabel implements IFlowLabelWithFilter { + + private static final AssignLabel noFilter = new AssignLabel(null); + + private final TypeFilter filter; + + private AssignLabel(TypeFilter filter) { + this.filter = filter; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((filter == null) ? 0 : filter.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + final AssignLabel other = (AssignLabel) obj; + if (filter == null) { + if (other.filter != null) + return false; + } else if (!filter.equals(other.filter)) + return false; + return true; + } + + public static AssignLabel noFilter() { + return noFilter; + } + + public static AssignLabel make(TypeFilter filter) { + return new AssignLabel(filter); + } + + public void visit(IFlowLabelVisitor v, Object dst) throws IllegalArgumentException { + if (v == null) { + throw new IllegalArgumentException("v == null"); + } + v.visitAssign(this, dst); + } + + public AssignBarLabel bar() { + return this == noFilter ? AssignBarLabel.noFilter() : AssignBarLabel.make(filter); + } + + @Override + public String toString() { + return "assign"; + } + + public boolean isBarred() { + return false; + } + + public TypeFilter getFilter() { + return filter; + } +} diff --git a/com.ibm.wala.core/src/com/ibm/wala/demandpa/flowgraph/CallLabel.java b/com.ibm.wala.core/src/com/ibm/wala/demandpa/flowgraph/CallLabel.java index 482a195a0..d8db2fcb8 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/demandpa/flowgraph/CallLabel.java +++ b/com.ibm.wala.core/src/com/ibm/wala/demandpa/flowgraph/CallLabel.java @@ -1,79 +1,79 @@ -/******************************************************************************* - * 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. - * - * This file is a derivative of code released by the University of - * California under the terms listed below. - * - * Refinement Analysis Tools is Copyright (c) 2007 The Regents of the - * University of California (Regents). Provided that this notice and - * the following two paragraphs are included in any distribution of - * Refinement Analysis Tools or its derivative work, Regents agrees - * not to assert any of Regents' copyright rights in Refinement - * Analysis Tools against recipient for recipient's reproduction, - * preparation of derivative works, public display, public - * performance, distribution or sublicensing of Refinement Analysis - * Tools and derivative works, in source code and object code form. - * This agreement not to assert does not confer, by implication, - * estoppel, or otherwise any license or rights in any intellectual - * property of Regents, including, but not limited to, any patents - * of Regents or Regents' employees. - * - * IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, - * INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, - * INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE - * AND ITS DOCUMENTATION, EVEN IF REGENTS HAS BEEN ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE AND FURTHER DISCLAIMS ANY STATUTORY - * WARRANTY OF NON-INFRINGEMENT. THE SOFTWARE AND ACCOMPANYING - * DOCUMENTATION, IF ANY, PROVIDED HEREUNDER IS PROVIDED "AS - * IS". REGENTS HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, - * UPDATES, ENHANCEMENTS, OR MODIFICATIONS. - */ -package com.ibm.wala.demandpa.flowgraph; - -import com.ibm.wala.ipa.callgraph.propagation.cfa.CallerSiteContext; - -public abstract class CallLabel implements IFlowLabel { - - protected final CallerSiteContext callSite; - - protected CallLabel(CallerSiteContext callSite) { - this.callSite = callSite; - } - public CallerSiteContext getCallSite() { - return callSite; - } - - @Override - public int hashCode() { - final int PRIME = 31; - int result = 1; - result = PRIME * result + ((callSite == null) ? 0 : callSite.hashCode()); - return result; - } - - @Override - public boolean equals(Object obj) { - if (this == obj) - return true; - if (obj == null) - return false; - if (getClass() != obj.getClass()) - return false; - final ParamBarLabel other = (ParamBarLabel) obj; - if (callSite == null) { - if (other.callSite != null) - return false; - } else if (!callSite.equals(other.callSite)) - return false; - return true; - } - - -} +/******************************************************************************* + * 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. + * + * This file is a derivative of code released by the University of + * California under the terms listed below. + * + * Refinement Analysis Tools is Copyright (c) 2007 The Regents of the + * University of California (Regents). Provided that this notice and + * the following two paragraphs are included in any distribution of + * Refinement Analysis Tools or its derivative work, Regents agrees + * not to assert any of Regents' copyright rights in Refinement + * Analysis Tools against recipient for recipient's reproduction, + * preparation of derivative works, public display, public + * performance, distribution or sublicensing of Refinement Analysis + * Tools and derivative works, in source code and object code form. + * This agreement not to assert does not confer, by implication, + * estoppel, or otherwise any license or rights in any intellectual + * property of Regents, including, but not limited to, any patents + * of Regents or Regents' employees. + * + * IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, + * INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, + * INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE + * AND ITS DOCUMENTATION, EVEN IF REGENTS HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE AND FURTHER DISCLAIMS ANY STATUTORY + * WARRANTY OF NON-INFRINGEMENT. THE SOFTWARE AND ACCOMPANYING + * DOCUMENTATION, IF ANY, PROVIDED HEREUNDER IS PROVIDED "AS + * IS". REGENTS HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, + * UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + */ +package com.ibm.wala.demandpa.flowgraph; + +import com.ibm.wala.ipa.callgraph.propagation.cfa.CallerSiteContext; + +public abstract class CallLabel implements IFlowLabel { + + protected final CallerSiteContext callSite; + + protected CallLabel(CallerSiteContext callSite) { + this.callSite = callSite; + } + public CallerSiteContext getCallSite() { + return callSite; + } + + @Override + public int hashCode() { + final int PRIME = 31; + int result = 1; + result = PRIME * result + ((callSite == null) ? 0 : callSite.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + final ParamBarLabel other = (ParamBarLabel) obj; + if (callSite == null) { + if (other.callSite != null) + return false; + } else if (!callSite.equals(other.callSite)) + return false; + return true; + } + + +} diff --git a/com.ibm.wala.core/src/com/ibm/wala/demandpa/flowgraph/DemandPointerFlowGraph.java b/com.ibm.wala.core/src/com/ibm/wala/demandpa/flowgraph/DemandPointerFlowGraph.java index d43f3c75a..556eee4f0 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/demandpa/flowgraph/DemandPointerFlowGraph.java +++ b/com.ibm.wala.core/src/com/ibm/wala/demandpa/flowgraph/DemandPointerFlowGraph.java @@ -1,562 +1,562 @@ -/******************************************************************************* - * 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. - * - * This file is a derivative of code released by the University of - * California under the terms listed below. - * - * Refinement Analysis Tools is Copyright (c) 2007 The Regents of the - * University of California (Regents). Provided that this notice and - * the following two paragraphs are included in any distribution of - * Refinement Analysis Tools or its derivative work, Regents agrees - * not to assert any of Regents' copyright rights in Refinement - * Analysis Tools against recipient for recipient's reproduction, - * preparation of derivative works, public display, public - * performance, distribution or sublicensing of Refinement Analysis - * Tools and derivative works, in source code and object code form. - * This agreement not to assert does not confer, by implication, - * estoppel, or otherwise any license or rights in any intellectual - * property of Regents, including, but not limited to, any patents - * of Regents or Regents' employees. - * - * IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, - * INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, - * INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE - * AND ITS DOCUMENTATION, EVEN IF REGENTS HAS BEEN ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE AND FURTHER DISCLAIMS ANY STATUTORY - * WARRANTY OF NON-INFRINGEMENT. THE SOFTWARE AND ACCOMPANYING - * DOCUMENTATION, IF ANY, PROVIDED HEREUNDER IS PROVIDED "AS - * IS". REGENTS HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, - * UPDATES, ENHANCEMENTS, OR MODIFICATIONS. - */ -package com.ibm.wala.demandpa.flowgraph; - -import java.util.Collection; -import java.util.Iterator; -import java.util.List; -import java.util.Set; - -import com.ibm.wala.classLoader.ArrayClass; -import com.ibm.wala.classLoader.IClass; -import com.ibm.wala.classLoader.IField; -import com.ibm.wala.classLoader.ProgramCounter; -import com.ibm.wala.demandpa.util.ArrayContents; -import com.ibm.wala.demandpa.util.MemoryAccessMap; -import com.ibm.wala.demandpa.util.PointerParamValueNumIterator; -import com.ibm.wala.ipa.callgraph.CGNode; -import com.ibm.wala.ipa.callgraph.CallGraph; -import com.ibm.wala.ipa.callgraph.propagation.ConcreteTypeKey; -import com.ibm.wala.ipa.callgraph.propagation.FilteredPointerKey; -import com.ibm.wala.ipa.callgraph.propagation.HeapModel; -import com.ibm.wala.ipa.callgraph.propagation.InstanceKey; -import com.ibm.wala.ipa.callgraph.propagation.PointerKey; -import com.ibm.wala.ipa.callgraph.propagation.PropagationCallGraphBuilder; -import com.ibm.wala.ipa.callgraph.propagation.SSAPropagationCallGraphBuilder; -import com.ibm.wala.ipa.cha.IClassHierarchy; -import com.ibm.wala.ssa.DefUse; -import com.ibm.wala.ssa.IR; -import com.ibm.wala.ssa.ISSABasicBlock; -import com.ibm.wala.ssa.SSAAbstractInvokeInstruction; -import com.ibm.wala.ssa.SSAAbstractThrowInstruction; -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.SSALoadMetadataInstruction; -import com.ibm.wala.ssa.SSANewInstruction; -import com.ibm.wala.ssa.SSAPiInstruction; -import com.ibm.wala.ssa.SSAPutInstruction; -import com.ibm.wala.ssa.SSAReturnInstruction; -import com.ibm.wala.ssa.SSAThrowInstruction; -import com.ibm.wala.ssa.SymbolTable; -import com.ibm.wala.types.FieldReference; -import com.ibm.wala.types.TypeReference; -import com.ibm.wala.util.collections.HashSetFactory; -import com.ibm.wala.util.collections.Pair; - -/** - * A graph representation of statements flowing pointer values, but not primitive values. Nodes are variables, and edges - * are against value flow; assignment x = y yields edge from x to y with label {@link AssignLabel#noFilter()} - */ -public class DemandPointerFlowGraph extends AbstractDemandFlowGraph implements IFlowGraph { - - public DemandPointerFlowGraph(CallGraph cg, HeapModel heapModel, MemoryAccessMap mam, IClassHierarchy cha) { - super(cg, heapModel, mam, cha); - } - - /** - * add nodes for parameters and return values - */ - @Override - protected void addNodesForParameters(CGNode node, IR ir) { - for (Iterator iter = new PointerParamValueNumIterator(node); iter.hasNext();) { - int parameter = iter.next(); - PointerKey paramPk = heapModel.getPointerKeyForLocal(node, parameter); - addNode(paramPk); - params.put(paramPk, node); - } - PointerKey returnKey = heapModel.getPointerKeyForReturnValue(node); - addNode(returnKey); - returns.put(returnKey, node); - PointerKey exceptionReturnKey = heapModel.getPointerKeyForExceptionalReturnValue(node); - addNode(exceptionReturnKey); - returns.put(exceptionReturnKey, node); - } - - @Override - protected FlowStatementVisitor makeVisitor(CGNode node) { - return new StatementVisitor(heapModel, this, cha, cg, node); - } - - /** - * A visitor that generates graph nodes and edges for an IR. - * - * strategy: when visiting a statement, for each use of that statement, add a graph edge from def to use. - * - * TODO: special treatment for parameter passing, etc. - */ - public static class StatementVisitor extends SSAInstruction.Visitor implements FlowStatementVisitor { - - private final HeapModel heapModel; - - private final IFlowGraph g; - - private final IClassHierarchy cha; - - private final CallGraph cg; - - /** - * The node whose statements we are currently traversing - */ - protected final CGNode node; - - /** - * The governing IR - */ - protected final IR ir; - - /** - * The basic block currently being processed - */ - private ISSABasicBlock basicBlock; - - /** - * Governing symbol table - */ - protected final SymbolTable symbolTable; - - /** - * Def-use information - */ - protected final DefUse du; - - public StatementVisitor(HeapModel heapModel, IFlowGraph g, IClassHierarchy cha, CallGraph cg, CGNode node) { - super(); - this.heapModel = heapModel; - this.g = g; - this.cha = cha; - this.cg = cg; - this.node = node; - this.ir = node.getIR(); - this.du = node.getDU(); - this.symbolTable = ir.getSymbolTable(); - assert symbolTable != null; - } - - /* - * @see com.ibm.domo.ssa.SSAInstruction.Visitor#visitArrayLoad(com.ibm.domo.ssa.SSAArrayLoadInstruction) - */ - @Override - public void visitArrayLoad(SSAArrayLoadInstruction instruction) { - // skip arrays of primitive type - if (instruction.typeIsPrimitive()) { - return; - } - PointerKey result = heapModel.getPointerKeyForLocal(node, instruction.getDef()); - PointerKey arrayRef = heapModel.getPointerKeyForLocal(node, instruction.getArrayRef()); - // TODO optimizations for purely local stuff - g.addNode(result); - g.addNode(arrayRef); - g.addEdge(result, arrayRef, GetFieldLabel.make(ArrayContents.v())); - } - - /* - * @see com.ibm.domo.ssa.SSAInstruction.Visitor#visitArrayStore(com.ibm.domo.ssa.SSAArrayStoreInstruction) - */ - @Override - public void visitArrayStore(SSAArrayStoreInstruction instruction) { - // Assertions.UNREACHABLE(); - // skip arrays of primitive type - if (instruction.typeIsPrimitive()) { - return; - } - // make node for used value - PointerKey value = heapModel.getPointerKeyForLocal(node, instruction.getValue()); - PointerKey arrayRef = heapModel.getPointerKeyForLocal(node, instruction.getArrayRef()); - // TODO purely local optimizations - g.addNode(value); - g.addNode(arrayRef); - g.addEdge(arrayRef, value, PutFieldLabel.make(ArrayContents.v())); - } - - /* - * @see com.ibm.domo.ssa.SSAInstruction.Visitor#visitCheckCast(com.ibm.domo.ssa.SSACheckCastInstruction) - */ - @Override - public void visitCheckCast(SSACheckCastInstruction instruction) { - Set types = HashSetFactory.make(); - - for(TypeReference t : instruction.getDeclaredResultTypes()) { - IClass cls = cha.lookupClass(t); - if (cls == null) { - return; - } else { - types.add(cls); - } - } - - FilteredPointerKey.MultipleClassesFilter filter = new FilteredPointerKey.MultipleClassesFilter(types.toArray(new IClass[ types.size() ])); - PointerKey result = heapModel.getPointerKeyForLocal(node, instruction.getResult()); - PointerKey value = heapModel.getPointerKeyForLocal(node, instruction.getVal()); - g.addNode(result); - g.addNode(value); - g.addEdge(result, value, AssignLabel.make(filter)); - } - - /* - * @see com.ibm.domo.ssa.SSAInstruction.Visitor#visitReturn(com.ibm.domo.ssa.SSAReturnInstruction) - */ - @Override - public void visitReturn(SSAReturnInstruction instruction) { - // skip returns of primitive type - if (instruction.returnsPrimitiveType() || instruction.returnsVoid()) { - return; - } else { - // just make a node for the def'd value - PointerKey def = heapModel.getPointerKeyForLocal(node, instruction.getResult()); - g.addNode(def); - PointerKey returnValue = heapModel.getPointerKeyForReturnValue(node); - g.addNode(returnValue); - g.addEdge(returnValue, def, AssignLabel.noFilter()); - } - } - - /* - * @see com.ibm.domo.ssa.SSAInstruction.Visitor#visitGet(com.ibm.domo.ssa.SSAGetInstruction) - */ - @Override - public void visitGet(SSAGetInstruction instruction) { - visitGetInternal(instruction.getDef(), instruction.getRef(), instruction.isStatic(), instruction.getDeclaredField()); - } - - protected void visitGetInternal(int lval, int ref, boolean isStatic, FieldReference field) { - - // skip getfields of primitive type (optimisation) - if (field.getFieldType().isPrimitiveType()) { - return; - } - IField f = cg.getClassHierarchy().resolveField(field); - if (f == null) { - return; - } - PointerKey def = heapModel.getPointerKeyForLocal(node, lval); - assert def != null; - - if (isStatic) { - PointerKey fKey = heapModel.getPointerKeyForStaticField(f); - g.addNode(def); - g.addNode(fKey); - g.addEdge(def, fKey, AssignGlobalLabel.v()); - } else { - PointerKey refKey = heapModel.getPointerKeyForLocal(node, ref); - g.addNode(def); - g.addNode(refKey); - // TODO purely local optimizations - g.addEdge(def, refKey, GetFieldLabel.make(f)); - } - } - - /* - * @see com.ibm.domo.ssa.Instruction.Visitor#visitPut(com.ibm.domo.ssa.PutInstruction) - */ - @Override - public void visitPut(SSAPutInstruction instruction) { - visitPutInternal(instruction.getVal(), instruction.getRef(), instruction.isStatic(), instruction.getDeclaredField()); - } - - public void visitPutInternal(int rval, int ref, boolean isStatic, FieldReference field) { - // skip putfields of primitive type (optimisation) - if (field.getFieldType().isPrimitiveType()) { - return; - } - IField f = cg.getClassHierarchy().resolveField(field); - if (f == null) { - return; - } - PointerKey use = heapModel.getPointerKeyForLocal(node, rval); - assert use != null; - - if (isStatic) { - PointerKey fKey = heapModel.getPointerKeyForStaticField(f); - g.addNode(use); - g.addNode(fKey); - g.addEdge(fKey, use, AssignGlobalLabel.v()); - } else { - PointerKey refKey = heapModel.getPointerKeyForLocal(node, ref); - g.addNode(use); - g.addNode(refKey); - g.addEdge(refKey, use, PutFieldLabel.make(f)); - } - - } - - /* - * @see com.ibm.domo.ssa.Instruction.Visitor#visitInvoke(com.ibm.domo.ssa.InvokeInstruction) - */ - @Override - public void visitInvoke(SSAInvokeInstruction instruction) { - - // for (int i = 0; i < instruction.getNumberOfUses(); i++) { - // // just make nodes for parameters; we'll get to them when - // // traversing - // // from the callee - // PointerKey use = heapModel.getPointerKeyForLocal(node, instruction.getUse(i)); - // g.addNode(use); - // Set s = MapUtil.findOrCreateSet(callParams, use); - // s.add(instruction); - // } - // - // // for any def'd values, keep track of the fact that they are def'd - // // by a call - // if (instruction.hasDef()) { - // PointerKey def = heapModel.getPointerKeyForLocal(node, instruction.getDef()); - // g.addNode(def); - // callDefs.put(def, instruction); - // } - // PointerKey exc = heapModel.getPointerKeyForLocal(node, instruction.getException()); - // g.addNode(exc); - // callDefs.put(exc, instruction); - } - - /* - * @see com.ibm.domo.ssa.Instruction.Visitor#visitNew(com.ibm.domo.ssa.NewInstruction) - */ - @Override - public void visitNew(SSANewInstruction instruction) { - - InstanceKey iKey = heapModel.getInstanceKeyForAllocation(node, instruction.getNewSite()); - if (iKey == null) { - // something went wrong. I hope someone raised a warning. - return; - } - PointerKey def = heapModel.getPointerKeyForLocal(node, instruction.getDef()); - g.addNode(iKey); - g.addNode(def); - g.addEdge(def, iKey, NewLabel.v()); - - NewMultiDimInfo multiDimInfo = getInfoForNewMultiDim(instruction, heapModel, node); - if (multiDimInfo != null) { - for (Pair newInstr : multiDimInfo.newInstrs) { - g.addNode(newInstr.fst); - g.addNode(newInstr.snd); - g.addEdge(newInstr.fst, newInstr.snd, NewLabel.v()); - } - for (Pair arrStoreInstr : multiDimInfo.arrStoreInstrs) { - g.addNode(arrStoreInstr.fst); - g.addNode(arrStoreInstr.snd); - g.addEdge(arrStoreInstr.fst, arrStoreInstr.snd, PutFieldLabel.make(ArrayContents.v())); - } - } - } - - /* - * @see com.ibm.domo.ssa.Instruction.Visitor#visitThrow(com.ibm.domo.ssa.ThrowInstruction) - */ - @Override - public void visitThrow(SSAThrowInstruction instruction) { - // don't do anything: we handle exceptional edges - // in a separate pass - } - - /* - * @see com.ibm.domo.ssa.Instruction.Visitor#visitGetCaughtException(com.ibm.domo.ssa.GetCaughtExceptionInstruction) - */ - @Override - public void visitGetCaughtException(SSAGetCaughtExceptionInstruction instruction) { - List peis = SSAPropagationCallGraphBuilder.getIncomingPEIs(ir, getBasicBlock()); - PointerKey def = heapModel.getPointerKeyForLocal(node, instruction.getDef()); - - Set types = SSAPropagationCallGraphBuilder.getCaughtExceptionTypes(instruction, ir); - addExceptionDefConstraints(ir, node, peis, def, types); - } - - /** - * Generate constraints which assign exception values into an exception pointer - * - * @param node governing node - * @param peis list of PEI instructions - * @param exceptionVar PointerKey representing a pointer to an exception value - * @param catchClasses the types "caught" by the exceptionVar - */ - protected void addExceptionDefConstraints(IR ir, CGNode node, List peis, PointerKey exceptionVar, - Set catchClasses) { - for (Iterator it = peis.iterator(); it.hasNext();) { - ProgramCounter peiLoc = it.next(); - SSAInstruction pei = ir.getPEI(peiLoc); - - if (pei instanceof SSAAbstractInvokeInstruction) { - SSAAbstractInvokeInstruction s = (SSAAbstractInvokeInstruction) pei; - PointerKey e = heapModel.getPointerKeyForLocal(node, s.getException()); - g.addNode(exceptionVar); - g.addNode(e); - g.addEdge(exceptionVar, e, AssignLabel.noFilter()); - - } else if (pei instanceof SSAAbstractThrowInstruction) { - SSAAbstractThrowInstruction s = (SSAAbstractThrowInstruction) pei; - PointerKey e = heapModel.getPointerKeyForLocal(node, s.getException()); - g.addNode(exceptionVar); - g.addNode(e); - g.addEdge(exceptionVar, e, AssignLabel.noFilter()); - } - - // Account for those exceptions for which we do not actually have a - // points-to set for - // the pei, but just instance keys - Collection types = pei.getExceptionTypes(); - if (types != null) { - for (Iterator it2 = types.iterator(); it2.hasNext();) { - TypeReference type = it2.next(); - if (type != null) { - InstanceKey ik = heapModel.getInstanceKeyForPEI(node, peiLoc, type); - if (ik == null) { - // probably due to exclusions - continue; - } - assert ik instanceof ConcreteTypeKey : "uh oh: need to implement getCaughtException constraints for instance " + ik; - ConcreteTypeKey ck = (ConcreteTypeKey) ik; - IClass klass = ck.getType(); - if (PropagationCallGraphBuilder.catches(catchClasses, klass, cha)) { - g.addNode(exceptionVar); - g.addNode(ik); - g.addEdge(exceptionVar, ik, NewLabel.v()); - } - } - } - } - } - } - - /* - * (non-Javadoc) - * - * @see com.ibm.domo.ssa.SSAInstruction.Visitor#visitPi(com.ibm.domo.ssa.SSAPiInstruction) - */ - @Override - public void visitPi(SSAPiInstruction instruction) { - // for now, ignore condition and just treat it as a copy - PointerKey def = heapModel.getPointerKeyForLocal(node, instruction.getDef()); - PointerKey use = heapModel.getPointerKeyForLocal(node, instruction.getVal()); - g.addNode(def); - g.addNode(use); - g.addEdge(def, use, AssignLabel.noFilter()); - } - - public ISSABasicBlock getBasicBlock() { - return basicBlock; - } - - /** - * The calling loop must call this in each iteration! - */ - public void setBasicBlock(ISSABasicBlock block) { - basicBlock = block; - } - - @Override - public void visitLoadMetadata(SSALoadMetadataInstruction instruction) { - PointerKey def = heapModel.getPointerKeyForLocal(node, instruction.getDef()); - assert instruction.getType() == TypeReference.JavaLangClass; - InstanceKey iKey = heapModel.getInstanceKeyForClassObject((TypeReference) instruction.getToken()); - - g.addNode(iKey); - g.addNode(def); - g.addEdge(def, iKey, NewLabel.v()); - } - } - - public static class NewMultiDimInfo { - - public final Collection> newInstrs; - - // pairs of (base pointer, stored val) - public final Collection> arrStoreInstrs; - - public NewMultiDimInfo(Collection> newInstrs, - Collection> arrStoreInstrs) { - this.newInstrs = newInstrs; - this.arrStoreInstrs = arrStoreInstrs; - } - - } - - /** - * collect information about the new instructions and putfield instructions used to model an allocation of a multi-dimensional - * array. excludes the new instruction itself (i.e., the allocation of the top-level multi-dim array). - */ - public static NewMultiDimInfo getInfoForNewMultiDim(SSANewInstruction instruction, HeapModel heapModel, CGNode node) { - if (heapModel == null) { - throw new IllegalArgumentException("null heapModel"); - } - Collection> newInstrs = HashSetFactory.make(); - Collection> arrStoreInstrs = HashSetFactory.make(); - InstanceKey iKey = heapModel.getInstanceKeyForAllocation(node, instruction.getNewSite()); - if (iKey == null) { - // something went wrong. I hope someone raised a warning. - return null; - } - IClass klass = iKey.getConcreteType(); - // if not a multi-dim array allocation, return null - if (!klass.isArrayClass() || ((ArrayClass) klass).getElementClass() == null - || !((ArrayClass) klass).getElementClass().isArrayClass()) { - return null; - } - PointerKey def = heapModel.getPointerKeyForLocal(node, instruction.getDef()); - - int dim = 0; - InstanceKey lastInstance = iKey; - PointerKey lastVar = def; - while (klass != null && klass.isArrayClass()) { - klass = ((ArrayClass) klass).getElementClass(); - // klass == null means it's a primitive - if (klass != null && klass.isArrayClass()) { - InstanceKey ik = heapModel.getInstanceKeyForMultiNewArray(node, instruction.getNewSite(), dim); - PointerKey pk = heapModel.getPointerKeyForArrayContents(lastInstance); - // if (DEBUG_MULTINEWARRAY) { - // Trace.println("multinewarray constraint: "); - // Trace.println(" pk: " + pk); - // Trace.println(" ik: " + system.findOrCreateIndexForInstanceKey(ik) - // + " concrete type " + ik.getConcreteType() - // + " is " + ik); - // Trace.println(" klass:" + klass); - // } - // g.addEdge(pk, ik, NewLabel.v()); - newInstrs.add(Pair.make(pk, ik)); - arrStoreInstrs.add(Pair.make(lastVar, pk)); - lastInstance = ik; - lastVar = pk; - dim++; - } - } - - return new NewMultiDimInfo(newInstrs, arrStoreInstrs); - } -} +/******************************************************************************* + * 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. + * + * This file is a derivative of code released by the University of + * California under the terms listed below. + * + * Refinement Analysis Tools is Copyright (c) 2007 The Regents of the + * University of California (Regents). Provided that this notice and + * the following two paragraphs are included in any distribution of + * Refinement Analysis Tools or its derivative work, Regents agrees + * not to assert any of Regents' copyright rights in Refinement + * Analysis Tools against recipient for recipient's reproduction, + * preparation of derivative works, public display, public + * performance, distribution or sublicensing of Refinement Analysis + * Tools and derivative works, in source code and object code form. + * This agreement not to assert does not confer, by implication, + * estoppel, or otherwise any license or rights in any intellectual + * property of Regents, including, but not limited to, any patents + * of Regents or Regents' employees. + * + * IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, + * INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, + * INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE + * AND ITS DOCUMENTATION, EVEN IF REGENTS HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE AND FURTHER DISCLAIMS ANY STATUTORY + * WARRANTY OF NON-INFRINGEMENT. THE SOFTWARE AND ACCOMPANYING + * DOCUMENTATION, IF ANY, PROVIDED HEREUNDER IS PROVIDED "AS + * IS". REGENTS HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, + * UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + */ +package com.ibm.wala.demandpa.flowgraph; + +import java.util.Collection; +import java.util.Iterator; +import java.util.List; +import java.util.Set; + +import com.ibm.wala.classLoader.ArrayClass; +import com.ibm.wala.classLoader.IClass; +import com.ibm.wala.classLoader.IField; +import com.ibm.wala.classLoader.ProgramCounter; +import com.ibm.wala.demandpa.util.ArrayContents; +import com.ibm.wala.demandpa.util.MemoryAccessMap; +import com.ibm.wala.demandpa.util.PointerParamValueNumIterator; +import com.ibm.wala.ipa.callgraph.CGNode; +import com.ibm.wala.ipa.callgraph.CallGraph; +import com.ibm.wala.ipa.callgraph.propagation.ConcreteTypeKey; +import com.ibm.wala.ipa.callgraph.propagation.FilteredPointerKey; +import com.ibm.wala.ipa.callgraph.propagation.HeapModel; +import com.ibm.wala.ipa.callgraph.propagation.InstanceKey; +import com.ibm.wala.ipa.callgraph.propagation.PointerKey; +import com.ibm.wala.ipa.callgraph.propagation.PropagationCallGraphBuilder; +import com.ibm.wala.ipa.callgraph.propagation.SSAPropagationCallGraphBuilder; +import com.ibm.wala.ipa.cha.IClassHierarchy; +import com.ibm.wala.ssa.DefUse; +import com.ibm.wala.ssa.IR; +import com.ibm.wala.ssa.ISSABasicBlock; +import com.ibm.wala.ssa.SSAAbstractInvokeInstruction; +import com.ibm.wala.ssa.SSAAbstractThrowInstruction; +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.SSALoadMetadataInstruction; +import com.ibm.wala.ssa.SSANewInstruction; +import com.ibm.wala.ssa.SSAPiInstruction; +import com.ibm.wala.ssa.SSAPutInstruction; +import com.ibm.wala.ssa.SSAReturnInstruction; +import com.ibm.wala.ssa.SSAThrowInstruction; +import com.ibm.wala.ssa.SymbolTable; +import com.ibm.wala.types.FieldReference; +import com.ibm.wala.types.TypeReference; +import com.ibm.wala.util.collections.HashSetFactory; +import com.ibm.wala.util.collections.Pair; + +/** + * A graph representation of statements flowing pointer values, but not primitive values. Nodes are variables, and edges + * are against value flow; assignment x = y yields edge from x to y with label {@link AssignLabel#noFilter()} + */ +public class DemandPointerFlowGraph extends AbstractDemandFlowGraph implements IFlowGraph { + + public DemandPointerFlowGraph(CallGraph cg, HeapModel heapModel, MemoryAccessMap mam, IClassHierarchy cha) { + super(cg, heapModel, mam, cha); + } + + /** + * add nodes for parameters and return values + */ + @Override + protected void addNodesForParameters(CGNode node, IR ir) { + for (Iterator iter = new PointerParamValueNumIterator(node); iter.hasNext();) { + int parameter = iter.next(); + PointerKey paramPk = heapModel.getPointerKeyForLocal(node, parameter); + addNode(paramPk); + params.put(paramPk, node); + } + PointerKey returnKey = heapModel.getPointerKeyForReturnValue(node); + addNode(returnKey); + returns.put(returnKey, node); + PointerKey exceptionReturnKey = heapModel.getPointerKeyForExceptionalReturnValue(node); + addNode(exceptionReturnKey); + returns.put(exceptionReturnKey, node); + } + + @Override + protected FlowStatementVisitor makeVisitor(CGNode node) { + return new StatementVisitor(heapModel, this, cha, cg, node); + } + + /** + * A visitor that generates graph nodes and edges for an IR. + * + * strategy: when visiting a statement, for each use of that statement, add a graph edge from def to use. + * + * TODO: special treatment for parameter passing, etc. + */ + public static class StatementVisitor extends SSAInstruction.Visitor implements FlowStatementVisitor { + + private final HeapModel heapModel; + + private final IFlowGraph g; + + private final IClassHierarchy cha; + + private final CallGraph cg; + + /** + * The node whose statements we are currently traversing + */ + protected final CGNode node; + + /** + * The governing IR + */ + protected final IR ir; + + /** + * The basic block currently being processed + */ + private ISSABasicBlock basicBlock; + + /** + * Governing symbol table + */ + protected final SymbolTable symbolTable; + + /** + * Def-use information + */ + protected final DefUse du; + + public StatementVisitor(HeapModel heapModel, IFlowGraph g, IClassHierarchy cha, CallGraph cg, CGNode node) { + super(); + this.heapModel = heapModel; + this.g = g; + this.cha = cha; + this.cg = cg; + this.node = node; + this.ir = node.getIR(); + this.du = node.getDU(); + this.symbolTable = ir.getSymbolTable(); + assert symbolTable != null; + } + + /* + * @see com.ibm.domo.ssa.SSAInstruction.Visitor#visitArrayLoad(com.ibm.domo.ssa.SSAArrayLoadInstruction) + */ + @Override + public void visitArrayLoad(SSAArrayLoadInstruction instruction) { + // skip arrays of primitive type + if (instruction.typeIsPrimitive()) { + return; + } + PointerKey result = heapModel.getPointerKeyForLocal(node, instruction.getDef()); + PointerKey arrayRef = heapModel.getPointerKeyForLocal(node, instruction.getArrayRef()); + // TODO optimizations for purely local stuff + g.addNode(result); + g.addNode(arrayRef); + g.addEdge(result, arrayRef, GetFieldLabel.make(ArrayContents.v())); + } + + /* + * @see com.ibm.domo.ssa.SSAInstruction.Visitor#visitArrayStore(com.ibm.domo.ssa.SSAArrayStoreInstruction) + */ + @Override + public void visitArrayStore(SSAArrayStoreInstruction instruction) { + // Assertions.UNREACHABLE(); + // skip arrays of primitive type + if (instruction.typeIsPrimitive()) { + return; + } + // make node for used value + PointerKey value = heapModel.getPointerKeyForLocal(node, instruction.getValue()); + PointerKey arrayRef = heapModel.getPointerKeyForLocal(node, instruction.getArrayRef()); + // TODO purely local optimizations + g.addNode(value); + g.addNode(arrayRef); + g.addEdge(arrayRef, value, PutFieldLabel.make(ArrayContents.v())); + } + + /* + * @see com.ibm.domo.ssa.SSAInstruction.Visitor#visitCheckCast(com.ibm.domo.ssa.SSACheckCastInstruction) + */ + @Override + public void visitCheckCast(SSACheckCastInstruction instruction) { + Set types = HashSetFactory.make(); + + for(TypeReference t : instruction.getDeclaredResultTypes()) { + IClass cls = cha.lookupClass(t); + if (cls == null) { + return; + } else { + types.add(cls); + } + } + + FilteredPointerKey.MultipleClassesFilter filter = new FilteredPointerKey.MultipleClassesFilter(types.toArray(new IClass[ types.size() ])); + PointerKey result = heapModel.getPointerKeyForLocal(node, instruction.getResult()); + PointerKey value = heapModel.getPointerKeyForLocal(node, instruction.getVal()); + g.addNode(result); + g.addNode(value); + g.addEdge(result, value, AssignLabel.make(filter)); + } + + /* + * @see com.ibm.domo.ssa.SSAInstruction.Visitor#visitReturn(com.ibm.domo.ssa.SSAReturnInstruction) + */ + @Override + public void visitReturn(SSAReturnInstruction instruction) { + // skip returns of primitive type + if (instruction.returnsPrimitiveType() || instruction.returnsVoid()) { + return; + } else { + // just make a node for the def'd value + PointerKey def = heapModel.getPointerKeyForLocal(node, instruction.getResult()); + g.addNode(def); + PointerKey returnValue = heapModel.getPointerKeyForReturnValue(node); + g.addNode(returnValue); + g.addEdge(returnValue, def, AssignLabel.noFilter()); + } + } + + /* + * @see com.ibm.domo.ssa.SSAInstruction.Visitor#visitGet(com.ibm.domo.ssa.SSAGetInstruction) + */ + @Override + public void visitGet(SSAGetInstruction instruction) { + visitGetInternal(instruction.getDef(), instruction.getRef(), instruction.isStatic(), instruction.getDeclaredField()); + } + + protected void visitGetInternal(int lval, int ref, boolean isStatic, FieldReference field) { + + // skip getfields of primitive type (optimisation) + if (field.getFieldType().isPrimitiveType()) { + return; + } + IField f = cg.getClassHierarchy().resolveField(field); + if (f == null) { + return; + } + PointerKey def = heapModel.getPointerKeyForLocal(node, lval); + assert def != null; + + if (isStatic) { + PointerKey fKey = heapModel.getPointerKeyForStaticField(f); + g.addNode(def); + g.addNode(fKey); + g.addEdge(def, fKey, AssignGlobalLabel.v()); + } else { + PointerKey refKey = heapModel.getPointerKeyForLocal(node, ref); + g.addNode(def); + g.addNode(refKey); + // TODO purely local optimizations + g.addEdge(def, refKey, GetFieldLabel.make(f)); + } + } + + /* + * @see com.ibm.domo.ssa.Instruction.Visitor#visitPut(com.ibm.domo.ssa.PutInstruction) + */ + @Override + public void visitPut(SSAPutInstruction instruction) { + visitPutInternal(instruction.getVal(), instruction.getRef(), instruction.isStatic(), instruction.getDeclaredField()); + } + + public void visitPutInternal(int rval, int ref, boolean isStatic, FieldReference field) { + // skip putfields of primitive type (optimisation) + if (field.getFieldType().isPrimitiveType()) { + return; + } + IField f = cg.getClassHierarchy().resolveField(field); + if (f == null) { + return; + } + PointerKey use = heapModel.getPointerKeyForLocal(node, rval); + assert use != null; + + if (isStatic) { + PointerKey fKey = heapModel.getPointerKeyForStaticField(f); + g.addNode(use); + g.addNode(fKey); + g.addEdge(fKey, use, AssignGlobalLabel.v()); + } else { + PointerKey refKey = heapModel.getPointerKeyForLocal(node, ref); + g.addNode(use); + g.addNode(refKey); + g.addEdge(refKey, use, PutFieldLabel.make(f)); + } + + } + + /* + * @see com.ibm.domo.ssa.Instruction.Visitor#visitInvoke(com.ibm.domo.ssa.InvokeInstruction) + */ + @Override + public void visitInvoke(SSAInvokeInstruction instruction) { + + // for (int i = 0; i < instruction.getNumberOfUses(); i++) { + // // just make nodes for parameters; we'll get to them when + // // traversing + // // from the callee + // PointerKey use = heapModel.getPointerKeyForLocal(node, instruction.getUse(i)); + // g.addNode(use); + // Set s = MapUtil.findOrCreateSet(callParams, use); + // s.add(instruction); + // } + // + // // for any def'd values, keep track of the fact that they are def'd + // // by a call + // if (instruction.hasDef()) { + // PointerKey def = heapModel.getPointerKeyForLocal(node, instruction.getDef()); + // g.addNode(def); + // callDefs.put(def, instruction); + // } + // PointerKey exc = heapModel.getPointerKeyForLocal(node, instruction.getException()); + // g.addNode(exc); + // callDefs.put(exc, instruction); + } + + /* + * @see com.ibm.domo.ssa.Instruction.Visitor#visitNew(com.ibm.domo.ssa.NewInstruction) + */ + @Override + public void visitNew(SSANewInstruction instruction) { + + InstanceKey iKey = heapModel.getInstanceKeyForAllocation(node, instruction.getNewSite()); + if (iKey == null) { + // something went wrong. I hope someone raised a warning. + return; + } + PointerKey def = heapModel.getPointerKeyForLocal(node, instruction.getDef()); + g.addNode(iKey); + g.addNode(def); + g.addEdge(def, iKey, NewLabel.v()); + + NewMultiDimInfo multiDimInfo = getInfoForNewMultiDim(instruction, heapModel, node); + if (multiDimInfo != null) { + for (Pair newInstr : multiDimInfo.newInstrs) { + g.addNode(newInstr.fst); + g.addNode(newInstr.snd); + g.addEdge(newInstr.fst, newInstr.snd, NewLabel.v()); + } + for (Pair arrStoreInstr : multiDimInfo.arrStoreInstrs) { + g.addNode(arrStoreInstr.fst); + g.addNode(arrStoreInstr.snd); + g.addEdge(arrStoreInstr.fst, arrStoreInstr.snd, PutFieldLabel.make(ArrayContents.v())); + } + } + } + + /* + * @see com.ibm.domo.ssa.Instruction.Visitor#visitThrow(com.ibm.domo.ssa.ThrowInstruction) + */ + @Override + public void visitThrow(SSAThrowInstruction instruction) { + // don't do anything: we handle exceptional edges + // in a separate pass + } + + /* + * @see com.ibm.domo.ssa.Instruction.Visitor#visitGetCaughtException(com.ibm.domo.ssa.GetCaughtExceptionInstruction) + */ + @Override + public void visitGetCaughtException(SSAGetCaughtExceptionInstruction instruction) { + List peis = SSAPropagationCallGraphBuilder.getIncomingPEIs(ir, getBasicBlock()); + PointerKey def = heapModel.getPointerKeyForLocal(node, instruction.getDef()); + + Set types = SSAPropagationCallGraphBuilder.getCaughtExceptionTypes(instruction, ir); + addExceptionDefConstraints(ir, node, peis, def, types); + } + + /** + * Generate constraints which assign exception values into an exception pointer + * + * @param node governing node + * @param peis list of PEI instructions + * @param exceptionVar PointerKey representing a pointer to an exception value + * @param catchClasses the types "caught" by the exceptionVar + */ + protected void addExceptionDefConstraints(IR ir, CGNode node, List peis, PointerKey exceptionVar, + Set catchClasses) { + for (Iterator it = peis.iterator(); it.hasNext();) { + ProgramCounter peiLoc = it.next(); + SSAInstruction pei = ir.getPEI(peiLoc); + + if (pei instanceof SSAAbstractInvokeInstruction) { + SSAAbstractInvokeInstruction s = (SSAAbstractInvokeInstruction) pei; + PointerKey e = heapModel.getPointerKeyForLocal(node, s.getException()); + g.addNode(exceptionVar); + g.addNode(e); + g.addEdge(exceptionVar, e, AssignLabel.noFilter()); + + } else if (pei instanceof SSAAbstractThrowInstruction) { + SSAAbstractThrowInstruction s = (SSAAbstractThrowInstruction) pei; + PointerKey e = heapModel.getPointerKeyForLocal(node, s.getException()); + g.addNode(exceptionVar); + g.addNode(e); + g.addEdge(exceptionVar, e, AssignLabel.noFilter()); + } + + // Account for those exceptions for which we do not actually have a + // points-to set for + // the pei, but just instance keys + Collection types = pei.getExceptionTypes(); + if (types != null) { + for (Iterator it2 = types.iterator(); it2.hasNext();) { + TypeReference type = it2.next(); + if (type != null) { + InstanceKey ik = heapModel.getInstanceKeyForPEI(node, peiLoc, type); + if (ik == null) { + // probably due to exclusions + continue; + } + assert ik instanceof ConcreteTypeKey : "uh oh: need to implement getCaughtException constraints for instance " + ik; + ConcreteTypeKey ck = (ConcreteTypeKey) ik; + IClass klass = ck.getType(); + if (PropagationCallGraphBuilder.catches(catchClasses, klass, cha)) { + g.addNode(exceptionVar); + g.addNode(ik); + g.addEdge(exceptionVar, ik, NewLabel.v()); + } + } + } + } + } + } + + /* + * (non-Javadoc) + * + * @see com.ibm.domo.ssa.SSAInstruction.Visitor#visitPi(com.ibm.domo.ssa.SSAPiInstruction) + */ + @Override + public void visitPi(SSAPiInstruction instruction) { + // for now, ignore condition and just treat it as a copy + PointerKey def = heapModel.getPointerKeyForLocal(node, instruction.getDef()); + PointerKey use = heapModel.getPointerKeyForLocal(node, instruction.getVal()); + g.addNode(def); + g.addNode(use); + g.addEdge(def, use, AssignLabel.noFilter()); + } + + public ISSABasicBlock getBasicBlock() { + return basicBlock; + } + + /** + * The calling loop must call this in each iteration! + */ + public void setBasicBlock(ISSABasicBlock block) { + basicBlock = block; + } + + @Override + public void visitLoadMetadata(SSALoadMetadataInstruction instruction) { + PointerKey def = heapModel.getPointerKeyForLocal(node, instruction.getDef()); + assert instruction.getType() == TypeReference.JavaLangClass; + InstanceKey iKey = heapModel.getInstanceKeyForClassObject((TypeReference) instruction.getToken()); + + g.addNode(iKey); + g.addNode(def); + g.addEdge(def, iKey, NewLabel.v()); + } + } + + public static class NewMultiDimInfo { + + public final Collection> newInstrs; + + // pairs of (base pointer, stored val) + public final Collection> arrStoreInstrs; + + public NewMultiDimInfo(Collection> newInstrs, + Collection> arrStoreInstrs) { + this.newInstrs = newInstrs; + this.arrStoreInstrs = arrStoreInstrs; + } + + } + + /** + * collect information about the new instructions and putfield instructions used to model an allocation of a multi-dimensional + * array. excludes the new instruction itself (i.e., the allocation of the top-level multi-dim array). + */ + public static NewMultiDimInfo getInfoForNewMultiDim(SSANewInstruction instruction, HeapModel heapModel, CGNode node) { + if (heapModel == null) { + throw new IllegalArgumentException("null heapModel"); + } + Collection> newInstrs = HashSetFactory.make(); + Collection> arrStoreInstrs = HashSetFactory.make(); + InstanceKey iKey = heapModel.getInstanceKeyForAllocation(node, instruction.getNewSite()); + if (iKey == null) { + // something went wrong. I hope someone raised a warning. + return null; + } + IClass klass = iKey.getConcreteType(); + // if not a multi-dim array allocation, return null + if (!klass.isArrayClass() || ((ArrayClass) klass).getElementClass() == null + || !((ArrayClass) klass).getElementClass().isArrayClass()) { + return null; + } + PointerKey def = heapModel.getPointerKeyForLocal(node, instruction.getDef()); + + int dim = 0; + InstanceKey lastInstance = iKey; + PointerKey lastVar = def; + while (klass != null && klass.isArrayClass()) { + klass = ((ArrayClass) klass).getElementClass(); + // klass == null means it's a primitive + if (klass != null && klass.isArrayClass()) { + InstanceKey ik = heapModel.getInstanceKeyForMultiNewArray(node, instruction.getNewSite(), dim); + PointerKey pk = heapModel.getPointerKeyForArrayContents(lastInstance); + // if (DEBUG_MULTINEWARRAY) { + // Trace.println("multinewarray constraint: "); + // Trace.println(" pk: " + pk); + // Trace.println(" ik: " + system.findOrCreateIndexForInstanceKey(ik) + // + " concrete type " + ik.getConcreteType() + // + " is " + ik); + // Trace.println(" klass:" + klass); + // } + // g.addEdge(pk, ik, NewLabel.v()); + newInstrs.add(Pair.make(pk, ik)); + arrStoreInstrs.add(Pair.make(lastVar, pk)); + lastInstance = ik; + lastVar = pk; + dim++; + } + } + + return new NewMultiDimInfo(newInstrs, arrStoreInstrs); + } +} diff --git a/com.ibm.wala.core/src/com/ibm/wala/demandpa/flowgraph/DemandValueFlowGraph.java b/com.ibm.wala.core/src/com/ibm/wala/demandpa/flowgraph/DemandValueFlowGraph.java index 9624d656a..a7f6475cf 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/demandpa/flowgraph/DemandValueFlowGraph.java +++ b/com.ibm.wala.core/src/com/ibm/wala/demandpa/flowgraph/DemandValueFlowGraph.java @@ -1,458 +1,458 @@ -/******************************************************************************* - * 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. - * - * This file is a derivative of code released by the University of - * California under the terms listed below. - * - * Refinement Analysis Tools is Copyright (c) 2007 The Regents of the - * University of California (Regents). Provided that this notice and - * the following two paragraphs are included in any distribution of - * Refinement Analysis Tools or its derivative work, Regents agrees - * not to assert any of Regents' copyright rights in Refinement - * Analysis Tools against recipient for recipient's reproduction, - * preparation of derivative works, public display, public - * performance, distribution or sublicensing of Refinement Analysis - * Tools and derivative works, in source code and object code form. - * This agreement not to assert does not confer, by implication, - * estoppel, or otherwise any license or rights in any intellectual - * property of Regents, including, but not limited to, any patents - * of Regents or Regents' employees. - * - * IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, - * INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, - * INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE - * AND ITS DOCUMENTATION, EVEN IF REGENTS HAS BEEN ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE AND FURTHER DISCLAIMS ANY STATUTORY - * WARRANTY OF NON-INFRINGEMENT. THE SOFTWARE AND ACCOMPANYING - * DOCUMENTATION, IF ANY, PROVIDED HEREUNDER IS PROVIDED "AS - * IS". REGENTS HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, - * UPDATES, ENHANCEMENTS, OR MODIFICATIONS. - */ -package com.ibm.wala.demandpa.flowgraph; - -import java.util.List; -import java.util.Set; - -import com.ibm.wala.classLoader.ArrayClass; -import com.ibm.wala.classLoader.IClass; -import com.ibm.wala.classLoader.IField; -import com.ibm.wala.classLoader.ProgramCounter; -import com.ibm.wala.demandpa.util.ArrayContents; -import com.ibm.wala.demandpa.util.MemoryAccessMap; -import com.ibm.wala.ipa.callgraph.CGNode; -import com.ibm.wala.ipa.callgraph.CallGraph; -import com.ibm.wala.ipa.callgraph.propagation.FilteredPointerKey; -import com.ibm.wala.ipa.callgraph.propagation.HeapModel; -import com.ibm.wala.ipa.callgraph.propagation.InstanceKey; -import com.ibm.wala.ipa.callgraph.propagation.PointerKey; -import com.ibm.wala.ipa.callgraph.propagation.SSAPropagationCallGraphBuilder; -import com.ibm.wala.ipa.cha.ClassHierarchy; -import com.ibm.wala.ssa.DefUse; -import com.ibm.wala.ssa.IR; -import com.ibm.wala.ssa.ISSABasicBlock; -import com.ibm.wala.ssa.SSAArrayLengthInstruction; -import com.ibm.wala.ssa.SSAArrayLoadInstruction; -import com.ibm.wala.ssa.SSAArrayStoreInstruction; -import com.ibm.wala.ssa.SSABinaryOpInstruction; -import com.ibm.wala.ssa.SSACheckCastInstruction; -import com.ibm.wala.ssa.SSAComparisonInstruction; -import com.ibm.wala.ssa.SSAConversionInstruction; -import com.ibm.wala.ssa.SSAGetCaughtExceptionInstruction; -import com.ibm.wala.ssa.SSAGetInstruction; -import com.ibm.wala.ssa.SSAInstanceofInstruction; -import com.ibm.wala.ssa.SSAInstruction; -import com.ibm.wala.ssa.SSAInstruction.Visitor; -import com.ibm.wala.ssa.SSAInvokeInstruction; -import com.ibm.wala.ssa.SSALoadMetadataInstruction; -import com.ibm.wala.ssa.SSANewInstruction; -import com.ibm.wala.ssa.SSAPiInstruction; -import com.ibm.wala.ssa.SSAPutInstruction; -import com.ibm.wala.ssa.SSAReturnInstruction; -import com.ibm.wala.ssa.SSAThrowInstruction; -import com.ibm.wala.ssa.SSAUnaryOpInstruction; -import com.ibm.wala.ssa.SymbolTable; -import com.ibm.wala.types.FieldReference; -import com.ibm.wala.types.TypeReference; -import com.ibm.wala.util.collections.HashSetFactory; -import com.ibm.wala.util.collections.MapUtil; -import com.ibm.wala.util.debug.Assertions; - -/** - * A flow graph including both pointer and primitive values. - * - * TODO share more code with {@link DemandPointerFlowGraph} - * - * @author Manu Sridharan - * - */ -public class DemandValueFlowGraph extends AbstractDemandFlowGraph { - - public DemandValueFlowGraph(CallGraph cg, HeapModel heapModel, MemoryAccessMap mam, ClassHierarchy cha) { - super(cg, heapModel, mam, cha); - } - - @Override - protected void addNodesForParameters(CGNode node, IR ir) { - SymbolTable symbolTable = ir.getSymbolTable(); - int numParams = symbolTable.getNumberOfParameters(); - for (int i = 0; i < numParams; i++) { - int parameter = symbolTable.getParameter(i); - PointerKey paramPk = heapModel.getPointerKeyForLocal(node, parameter); - addNode(paramPk); - params.put(paramPk, node); - } - PointerKey returnKey = heapModel.getPointerKeyForReturnValue(node); - addNode(returnKey); - returns.put(returnKey, node); - PointerKey exceptionReturnKey = heapModel.getPointerKeyForExceptionalReturnValue(node); - addNode(exceptionReturnKey); - returns.put(exceptionReturnKey, node); - } - - @Override - protected FlowStatementVisitor makeVisitor(CGNode node) { - return new AllValsStatementVisitor(node); - } - - private class AllValsStatementVisitor extends Visitor implements FlowStatementVisitor { - - /** - * The node whose statements we are currently traversing - */ - protected final CGNode node; - - /** - * The governing IR - */ - protected final IR ir; - - /** - * The basic block currently being processed - */ - private ISSABasicBlock basicBlock; - - /** - * Governing symbol table - */ - protected final SymbolTable symbolTable; - - /** - * Def-use information - */ - protected final DefUse du; - - public AllValsStatementVisitor(CGNode node) { - this.node = node; - this.ir = node.getIR(); - this.symbolTable = ir.getSymbolTable(); - assert symbolTable != null; - this.du = node.getDU(); - } - - /* - * @see com.ibm.domo.ssa.SSAInstruction.Visitor#visitArrayLoad(com.ibm.domo.ssa.SSAArrayLoadInstruction) - */ - @Override - public void visitArrayLoad(SSAArrayLoadInstruction instruction) { - PointerKey result = heapModel.getPointerKeyForLocal(node, instruction.getDef()); - PointerKey arrayRef = heapModel.getPointerKeyForLocal(node, instruction.getArrayRef()); - // TODO optimizations for purely local stuff - addNode(result); - addNode(arrayRef); - addEdge(result, arrayRef, GetFieldLabel.make(ArrayContents.v())); - } - - /* - * @see com.ibm.domo.ssa.SSAInstruction.Visitor#visitArrayStore(com.ibm.domo.ssa.SSAArrayStoreInstruction) - */ - @Override - public void visitArrayStore(SSAArrayStoreInstruction instruction) { - // make node for used value - PointerKey value = heapModel.getPointerKeyForLocal(node, instruction.getValue()); - PointerKey arrayRef = heapModel.getPointerKeyForLocal(node, instruction.getArrayRef()); - // TODO purely local optimizations - addNode(value); - addNode(arrayRef); - addEdge(arrayRef, value, PutFieldLabel.make(ArrayContents.v())); - } - - /* - * @see com.ibm.domo.ssa.SSAInstruction.Visitor#visitCheckCast(com.ibm.domo.ssa.SSACheckCastInstruction) - */ - @Override - public void visitCheckCast(SSACheckCastInstruction instruction) { - Set types = HashSetFactory.make(); - - for(TypeReference t : instruction.getDeclaredResultTypes()) { - IClass cls = cha.lookupClass(t); - if (cls == null) { - return; - } else { - types.add(cls); - } - } - - - PointerKey result = heapModel.getFilteredPointerKeyForLocal(node, - instruction.getResult(), - new FilteredPointerKey.MultipleClassesFilter(types.toArray(new IClass[ types.size() ])) ); - - PointerKey value = heapModel.getPointerKeyForLocal(node, instruction.getVal()); - - addNode(result); - addNode(value); - addEdge(result, value, AssignLabel.noFilter()); - } - - /* - * @see com.ibm.domo.ssa.SSAInstruction.Visitor#visitReturn(com.ibm.domo.ssa.SSAReturnInstruction) - */ - @Override - public void visitReturn(SSAReturnInstruction instruction) { - // skip returns of primitive type - if (instruction.returnsVoid()) { - return; - } else { - // just make a node for the def'd value - PointerKey def = heapModel.getPointerKeyForLocal(node, instruction.getResult()); - addNode(def); - PointerKey returnValue = heapModel.getPointerKeyForReturnValue(node); - addNode(returnValue); - addEdge(returnValue, def, AssignLabel.noFilter()); - } - } - - /* - * @see com.ibm.domo.ssa.SSAInstruction.Visitor#visitGet(com.ibm.domo.ssa.SSAGetInstruction) - */ - @Override - public void visitGet(SSAGetInstruction instruction) { - visitGetInternal(instruction.getDef(), instruction.getRef(), instruction.isStatic(), instruction.getDeclaredField()); - } - - protected void visitGetInternal(int lval, int ref, boolean isStatic, FieldReference field) { - - IField f = cg.getClassHierarchy().resolveField(field); - if (f == null) { - return; - } - PointerKey def = heapModel.getPointerKeyForLocal(node, lval); - assert def != null; - - if (isStatic) { - PointerKey fKey = heapModel.getPointerKeyForStaticField(f); - addNode(def); - addNode(fKey); - // TODO assign global edge for context-sensitive - addEdge(def, fKey, AssignGlobalLabel.v()); - } else { - PointerKey refKey = heapModel.getPointerKeyForLocal(node, ref); - addNode(def); - addNode(refKey); - // TODO purely local optimizations - addEdge(def, refKey, GetFieldLabel.make(f)); - } - } - - /* - * @see com.ibm.domo.ssa.Instruction.Visitor#visitPut(com.ibm.domo.ssa.PutInstruction) - */ - @Override - public void visitPut(SSAPutInstruction instruction) { - visitPutInternal(instruction.getVal(), instruction.getRef(), instruction.isStatic(), instruction.getDeclaredField()); - } - - public void visitPutInternal(int rval, int ref, boolean isStatic, FieldReference field) { - IField f = cg.getClassHierarchy().resolveField(field); - if (f == null) { - return; - } - PointerKey use = heapModel.getPointerKeyForLocal(node, rval); - assert use != null; - - if (isStatic) { - PointerKey fKey = heapModel.getPointerKeyForStaticField(f); - addNode(use); - addNode(fKey); - // TODO assign global edge - addEdge(fKey, use, AssignGlobalLabel.v()); - } else { - PointerKey refKey = heapModel.getPointerKeyForLocal(node, ref); - addNode(use); - addNode(refKey); - addEdge(refKey, use, PutFieldLabel.make(f)); - } - - } - - /* - * @see com.ibm.domo.ssa.Instruction.Visitor#visitInvoke(com.ibm.domo.ssa.InvokeInstruction) - */ - @Override - public void visitInvoke(SSAInvokeInstruction instruction) { - - for (int i = 0; i < instruction.getNumberOfUses(); i++) { - // just make nodes for parameters; we'll get to them when - // traversing - // from the callee - PointerKey use = heapModel.getPointerKeyForLocal(node, instruction.getUse(i)); - addNode(use); - Set s = MapUtil.findOrCreateSet(callParams, use); - s.add(instruction); - } - - // for any def'd values, keep track of the fact that they are def'd - // by a call - if (instruction.hasDef()) { - PointerKey def = heapModel.getPointerKeyForLocal(node, instruction.getDef()); - addNode(def); - callDefs.put(def, instruction); - } - PointerKey exc = heapModel.getPointerKeyForLocal(node, instruction.getException()); - addNode(exc); - callDefs.put(exc, instruction); - } - - /* - * @see com.ibm.domo.ssa.Instruction.Visitor#visitNew(com.ibm.domo.ssa.NewInstruction) - */ - @Override - public void visitNew(SSANewInstruction instruction) { - - InstanceKey iKey = heapModel.getInstanceKeyForAllocation(node, instruction.getNewSite()); - if (iKey == null) { - // something went wrong. I hope someone raised a warning. - return; - } - PointerKey def = heapModel.getPointerKeyForLocal(node, instruction.getDef()); - addNode(iKey); - addNode(def); - addEdge(def, iKey, NewLabel.v()); - - IClass klass = iKey.getConcreteType(); - int dim = 0; - InstanceKey lastInstance = iKey; - PointerKey lastVar = def; - while (klass != null && klass.isArrayClass()) { - klass = ((ArrayClass) klass).getElementClass(); - // klass == null means it's a primitive - if (klass != null && klass.isArrayClass()) { - InstanceKey ik = heapModel.getInstanceKeyForMultiNewArray(node, instruction.getNewSite(), dim); - PointerKey pk = heapModel.getPointerKeyForArrayContents(lastInstance); - addNode(ik); - addNode(pk); - addEdge(pk, ik, NewLabel.v()); - addEdge(lastVar, pk, PutFieldLabel.make(ArrayContents.v())); - lastInstance = ik; - lastVar = pk; - dim++; - } - } - - } - - /* - * (non-Javadoc) - * - * @see com.ibm.domo.ssa.Instruction.Visitor#visitThrow(com.ibm.domo.ssa.ThrowInstruction) - */ - @Override - public void visitThrow(SSAThrowInstruction instruction) { - // don't do anything: we handle exceptional edges - // in a separate pass - } - - /* - * @see com.ibm.domo.ssa.Instruction.Visitor#visitGetCaughtException(com.ibm.domo.ssa.GetCaughtExceptionInstruction) - */ - @Override - public void visitGetCaughtException(SSAGetCaughtExceptionInstruction instruction) { - List peis = SSAPropagationCallGraphBuilder.getIncomingPEIs(ir, getBasicBlock()); - PointerKey def = heapModel.getPointerKeyForLocal(node, instruction.getDef()); - - Set types = SSAPropagationCallGraphBuilder.getCaughtExceptionTypes(instruction, ir); - addExceptionDefConstraints(ir, node, peis, def, types); - } - - /* - * @see com.ibm.domo.ssa.SSAInstruction.Visitor#visitPi(com.ibm.domo.ssa.SSAPiInstruction) - */ - @Override - public void visitPi(SSAPiInstruction instruction) { - PointerKey src = heapModel.getPointerKeyForLocal(node, instruction.getDef()); - PointerKey dst = heapModel.getPointerKeyForLocal(node, instruction.getVal()); - addNode(src); - addNode(dst); - addEdge(src, dst, AssignLabel.noFilter()); - } - - private void handleNonHeapInstruction(SSAInstruction instruction) { - for (int i = 0; i < instruction.getNumberOfDefs(); i++) { - int def = instruction.getDef(i); - PointerKey defPk = heapModel.getPointerKeyForLocal(node, def); - addNode(defPk); - for (int j = 0; j < instruction.getNumberOfUses(); j++) { - int use = instruction.getUse(j); - PointerKey usePk = heapModel.getPointerKeyForLocal(node, use); - addNode(usePk); - addEdge(defPk, usePk, AssignLabel.noFilter()); - } - } - } - - @Override - public void visitArrayLength(SSAArrayLengthInstruction instruction) { - handleNonHeapInstruction(instruction); - } - - @Override - public void visitBinaryOp(SSABinaryOpInstruction instruction) { - handleNonHeapInstruction(instruction); - } - - @Override - public void visitComparison(SSAComparisonInstruction instruction) { - handleNonHeapInstruction(instruction); - } - - @Override - public void visitConversion(SSAConversionInstruction instruction) { - handleNonHeapInstruction(instruction); - } - - @Override - public void visitInstanceof(SSAInstanceofInstruction instruction) { - handleNonHeapInstruction(instruction); - } - - @Override - public void visitUnaryOp(SSAUnaryOpInstruction instruction) { - handleNonHeapInstruction(instruction); - } - - public ISSABasicBlock getBasicBlock() { - return basicBlock; - } - - /** - * The calling loop must call this in each iteration! - */ - public void setBasicBlock(ISSABasicBlock block) { - basicBlock = block; - } - - @Override - public void visitLoadMetadata(SSALoadMetadataInstruction instruction) { - Assertions.UNREACHABLE(); - } - - } - -} +/******************************************************************************* + * 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. + * + * This file is a derivative of code released by the University of + * California under the terms listed below. + * + * Refinement Analysis Tools is Copyright (c) 2007 The Regents of the + * University of California (Regents). Provided that this notice and + * the following two paragraphs are included in any distribution of + * Refinement Analysis Tools or its derivative work, Regents agrees + * not to assert any of Regents' copyright rights in Refinement + * Analysis Tools against recipient for recipient's reproduction, + * preparation of derivative works, public display, public + * performance, distribution or sublicensing of Refinement Analysis + * Tools and derivative works, in source code and object code form. + * This agreement not to assert does not confer, by implication, + * estoppel, or otherwise any license or rights in any intellectual + * property of Regents, including, but not limited to, any patents + * of Regents or Regents' employees. + * + * IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, + * INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, + * INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE + * AND ITS DOCUMENTATION, EVEN IF REGENTS HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE AND FURTHER DISCLAIMS ANY STATUTORY + * WARRANTY OF NON-INFRINGEMENT. THE SOFTWARE AND ACCOMPANYING + * DOCUMENTATION, IF ANY, PROVIDED HEREUNDER IS PROVIDED "AS + * IS". REGENTS HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, + * UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + */ +package com.ibm.wala.demandpa.flowgraph; + +import java.util.List; +import java.util.Set; + +import com.ibm.wala.classLoader.ArrayClass; +import com.ibm.wala.classLoader.IClass; +import com.ibm.wala.classLoader.IField; +import com.ibm.wala.classLoader.ProgramCounter; +import com.ibm.wala.demandpa.util.ArrayContents; +import com.ibm.wala.demandpa.util.MemoryAccessMap; +import com.ibm.wala.ipa.callgraph.CGNode; +import com.ibm.wala.ipa.callgraph.CallGraph; +import com.ibm.wala.ipa.callgraph.propagation.FilteredPointerKey; +import com.ibm.wala.ipa.callgraph.propagation.HeapModel; +import com.ibm.wala.ipa.callgraph.propagation.InstanceKey; +import com.ibm.wala.ipa.callgraph.propagation.PointerKey; +import com.ibm.wala.ipa.callgraph.propagation.SSAPropagationCallGraphBuilder; +import com.ibm.wala.ipa.cha.ClassHierarchy; +import com.ibm.wala.ssa.DefUse; +import com.ibm.wala.ssa.IR; +import com.ibm.wala.ssa.ISSABasicBlock; +import com.ibm.wala.ssa.SSAArrayLengthInstruction; +import com.ibm.wala.ssa.SSAArrayLoadInstruction; +import com.ibm.wala.ssa.SSAArrayStoreInstruction; +import com.ibm.wala.ssa.SSABinaryOpInstruction; +import com.ibm.wala.ssa.SSACheckCastInstruction; +import com.ibm.wala.ssa.SSAComparisonInstruction; +import com.ibm.wala.ssa.SSAConversionInstruction; +import com.ibm.wala.ssa.SSAGetCaughtExceptionInstruction; +import com.ibm.wala.ssa.SSAGetInstruction; +import com.ibm.wala.ssa.SSAInstanceofInstruction; +import com.ibm.wala.ssa.SSAInstruction; +import com.ibm.wala.ssa.SSAInstruction.Visitor; +import com.ibm.wala.ssa.SSAInvokeInstruction; +import com.ibm.wala.ssa.SSALoadMetadataInstruction; +import com.ibm.wala.ssa.SSANewInstruction; +import com.ibm.wala.ssa.SSAPiInstruction; +import com.ibm.wala.ssa.SSAPutInstruction; +import com.ibm.wala.ssa.SSAReturnInstruction; +import com.ibm.wala.ssa.SSAThrowInstruction; +import com.ibm.wala.ssa.SSAUnaryOpInstruction; +import com.ibm.wala.ssa.SymbolTable; +import com.ibm.wala.types.FieldReference; +import com.ibm.wala.types.TypeReference; +import com.ibm.wala.util.collections.HashSetFactory; +import com.ibm.wala.util.collections.MapUtil; +import com.ibm.wala.util.debug.Assertions; + +/** + * A flow graph including both pointer and primitive values. + * + * TODO share more code with {@link DemandPointerFlowGraph} + * + * @author Manu Sridharan + * + */ +public class DemandValueFlowGraph extends AbstractDemandFlowGraph { + + public DemandValueFlowGraph(CallGraph cg, HeapModel heapModel, MemoryAccessMap mam, ClassHierarchy cha) { + super(cg, heapModel, mam, cha); + } + + @Override + protected void addNodesForParameters(CGNode node, IR ir) { + SymbolTable symbolTable = ir.getSymbolTable(); + int numParams = symbolTable.getNumberOfParameters(); + for (int i = 0; i < numParams; i++) { + int parameter = symbolTable.getParameter(i); + PointerKey paramPk = heapModel.getPointerKeyForLocal(node, parameter); + addNode(paramPk); + params.put(paramPk, node); + } + PointerKey returnKey = heapModel.getPointerKeyForReturnValue(node); + addNode(returnKey); + returns.put(returnKey, node); + PointerKey exceptionReturnKey = heapModel.getPointerKeyForExceptionalReturnValue(node); + addNode(exceptionReturnKey); + returns.put(exceptionReturnKey, node); + } + + @Override + protected FlowStatementVisitor makeVisitor(CGNode node) { + return new AllValsStatementVisitor(node); + } + + private class AllValsStatementVisitor extends Visitor implements FlowStatementVisitor { + + /** + * The node whose statements we are currently traversing + */ + protected final CGNode node; + + /** + * The governing IR + */ + protected final IR ir; + + /** + * The basic block currently being processed + */ + private ISSABasicBlock basicBlock; + + /** + * Governing symbol table + */ + protected final SymbolTable symbolTable; + + /** + * Def-use information + */ + protected final DefUse du; + + public AllValsStatementVisitor(CGNode node) { + this.node = node; + this.ir = node.getIR(); + this.symbolTable = ir.getSymbolTable(); + assert symbolTable != null; + this.du = node.getDU(); + } + + /* + * @see com.ibm.domo.ssa.SSAInstruction.Visitor#visitArrayLoad(com.ibm.domo.ssa.SSAArrayLoadInstruction) + */ + @Override + public void visitArrayLoad(SSAArrayLoadInstruction instruction) { + PointerKey result = heapModel.getPointerKeyForLocal(node, instruction.getDef()); + PointerKey arrayRef = heapModel.getPointerKeyForLocal(node, instruction.getArrayRef()); + // TODO optimizations for purely local stuff + addNode(result); + addNode(arrayRef); + addEdge(result, arrayRef, GetFieldLabel.make(ArrayContents.v())); + } + + /* + * @see com.ibm.domo.ssa.SSAInstruction.Visitor#visitArrayStore(com.ibm.domo.ssa.SSAArrayStoreInstruction) + */ + @Override + public void visitArrayStore(SSAArrayStoreInstruction instruction) { + // make node for used value + PointerKey value = heapModel.getPointerKeyForLocal(node, instruction.getValue()); + PointerKey arrayRef = heapModel.getPointerKeyForLocal(node, instruction.getArrayRef()); + // TODO purely local optimizations + addNode(value); + addNode(arrayRef); + addEdge(arrayRef, value, PutFieldLabel.make(ArrayContents.v())); + } + + /* + * @see com.ibm.domo.ssa.SSAInstruction.Visitor#visitCheckCast(com.ibm.domo.ssa.SSACheckCastInstruction) + */ + @Override + public void visitCheckCast(SSACheckCastInstruction instruction) { + Set types = HashSetFactory.make(); + + for(TypeReference t : instruction.getDeclaredResultTypes()) { + IClass cls = cha.lookupClass(t); + if (cls == null) { + return; + } else { + types.add(cls); + } + } + + + PointerKey result = heapModel.getFilteredPointerKeyForLocal(node, + instruction.getResult(), + new FilteredPointerKey.MultipleClassesFilter(types.toArray(new IClass[ types.size() ])) ); + + PointerKey value = heapModel.getPointerKeyForLocal(node, instruction.getVal()); + + addNode(result); + addNode(value); + addEdge(result, value, AssignLabel.noFilter()); + } + + /* + * @see com.ibm.domo.ssa.SSAInstruction.Visitor#visitReturn(com.ibm.domo.ssa.SSAReturnInstruction) + */ + @Override + public void visitReturn(SSAReturnInstruction instruction) { + // skip returns of primitive type + if (instruction.returnsVoid()) { + return; + } else { + // just make a node for the def'd value + PointerKey def = heapModel.getPointerKeyForLocal(node, instruction.getResult()); + addNode(def); + PointerKey returnValue = heapModel.getPointerKeyForReturnValue(node); + addNode(returnValue); + addEdge(returnValue, def, AssignLabel.noFilter()); + } + } + + /* + * @see com.ibm.domo.ssa.SSAInstruction.Visitor#visitGet(com.ibm.domo.ssa.SSAGetInstruction) + */ + @Override + public void visitGet(SSAGetInstruction instruction) { + visitGetInternal(instruction.getDef(), instruction.getRef(), instruction.isStatic(), instruction.getDeclaredField()); + } + + protected void visitGetInternal(int lval, int ref, boolean isStatic, FieldReference field) { + + IField f = cg.getClassHierarchy().resolveField(field); + if (f == null) { + return; + } + PointerKey def = heapModel.getPointerKeyForLocal(node, lval); + assert def != null; + + if (isStatic) { + PointerKey fKey = heapModel.getPointerKeyForStaticField(f); + addNode(def); + addNode(fKey); + // TODO assign global edge for context-sensitive + addEdge(def, fKey, AssignGlobalLabel.v()); + } else { + PointerKey refKey = heapModel.getPointerKeyForLocal(node, ref); + addNode(def); + addNode(refKey); + // TODO purely local optimizations + addEdge(def, refKey, GetFieldLabel.make(f)); + } + } + + /* + * @see com.ibm.domo.ssa.Instruction.Visitor#visitPut(com.ibm.domo.ssa.PutInstruction) + */ + @Override + public void visitPut(SSAPutInstruction instruction) { + visitPutInternal(instruction.getVal(), instruction.getRef(), instruction.isStatic(), instruction.getDeclaredField()); + } + + public void visitPutInternal(int rval, int ref, boolean isStatic, FieldReference field) { + IField f = cg.getClassHierarchy().resolveField(field); + if (f == null) { + return; + } + PointerKey use = heapModel.getPointerKeyForLocal(node, rval); + assert use != null; + + if (isStatic) { + PointerKey fKey = heapModel.getPointerKeyForStaticField(f); + addNode(use); + addNode(fKey); + // TODO assign global edge + addEdge(fKey, use, AssignGlobalLabel.v()); + } else { + PointerKey refKey = heapModel.getPointerKeyForLocal(node, ref); + addNode(use); + addNode(refKey); + addEdge(refKey, use, PutFieldLabel.make(f)); + } + + } + + /* + * @see com.ibm.domo.ssa.Instruction.Visitor#visitInvoke(com.ibm.domo.ssa.InvokeInstruction) + */ + @Override + public void visitInvoke(SSAInvokeInstruction instruction) { + + for (int i = 0; i < instruction.getNumberOfUses(); i++) { + // just make nodes for parameters; we'll get to them when + // traversing + // from the callee + PointerKey use = heapModel.getPointerKeyForLocal(node, instruction.getUse(i)); + addNode(use); + Set s = MapUtil.findOrCreateSet(callParams, use); + s.add(instruction); + } + + // for any def'd values, keep track of the fact that they are def'd + // by a call + if (instruction.hasDef()) { + PointerKey def = heapModel.getPointerKeyForLocal(node, instruction.getDef()); + addNode(def); + callDefs.put(def, instruction); + } + PointerKey exc = heapModel.getPointerKeyForLocal(node, instruction.getException()); + addNode(exc); + callDefs.put(exc, instruction); + } + + /* + * @see com.ibm.domo.ssa.Instruction.Visitor#visitNew(com.ibm.domo.ssa.NewInstruction) + */ + @Override + public void visitNew(SSANewInstruction instruction) { + + InstanceKey iKey = heapModel.getInstanceKeyForAllocation(node, instruction.getNewSite()); + if (iKey == null) { + // something went wrong. I hope someone raised a warning. + return; + } + PointerKey def = heapModel.getPointerKeyForLocal(node, instruction.getDef()); + addNode(iKey); + addNode(def); + addEdge(def, iKey, NewLabel.v()); + + IClass klass = iKey.getConcreteType(); + int dim = 0; + InstanceKey lastInstance = iKey; + PointerKey lastVar = def; + while (klass != null && klass.isArrayClass()) { + klass = ((ArrayClass) klass).getElementClass(); + // klass == null means it's a primitive + if (klass != null && klass.isArrayClass()) { + InstanceKey ik = heapModel.getInstanceKeyForMultiNewArray(node, instruction.getNewSite(), dim); + PointerKey pk = heapModel.getPointerKeyForArrayContents(lastInstance); + addNode(ik); + addNode(pk); + addEdge(pk, ik, NewLabel.v()); + addEdge(lastVar, pk, PutFieldLabel.make(ArrayContents.v())); + lastInstance = ik; + lastVar = pk; + dim++; + } + } + + } + + /* + * (non-Javadoc) + * + * @see com.ibm.domo.ssa.Instruction.Visitor#visitThrow(com.ibm.domo.ssa.ThrowInstruction) + */ + @Override + public void visitThrow(SSAThrowInstruction instruction) { + // don't do anything: we handle exceptional edges + // in a separate pass + } + + /* + * @see com.ibm.domo.ssa.Instruction.Visitor#visitGetCaughtException(com.ibm.domo.ssa.GetCaughtExceptionInstruction) + */ + @Override + public void visitGetCaughtException(SSAGetCaughtExceptionInstruction instruction) { + List peis = SSAPropagationCallGraphBuilder.getIncomingPEIs(ir, getBasicBlock()); + PointerKey def = heapModel.getPointerKeyForLocal(node, instruction.getDef()); + + Set types = SSAPropagationCallGraphBuilder.getCaughtExceptionTypes(instruction, ir); + addExceptionDefConstraints(ir, node, peis, def, types); + } + + /* + * @see com.ibm.domo.ssa.SSAInstruction.Visitor#visitPi(com.ibm.domo.ssa.SSAPiInstruction) + */ + @Override + public void visitPi(SSAPiInstruction instruction) { + PointerKey src = heapModel.getPointerKeyForLocal(node, instruction.getDef()); + PointerKey dst = heapModel.getPointerKeyForLocal(node, instruction.getVal()); + addNode(src); + addNode(dst); + addEdge(src, dst, AssignLabel.noFilter()); + } + + private void handleNonHeapInstruction(SSAInstruction instruction) { + for (int i = 0; i < instruction.getNumberOfDefs(); i++) { + int def = instruction.getDef(i); + PointerKey defPk = heapModel.getPointerKeyForLocal(node, def); + addNode(defPk); + for (int j = 0; j < instruction.getNumberOfUses(); j++) { + int use = instruction.getUse(j); + PointerKey usePk = heapModel.getPointerKeyForLocal(node, use); + addNode(usePk); + addEdge(defPk, usePk, AssignLabel.noFilter()); + } + } + } + + @Override + public void visitArrayLength(SSAArrayLengthInstruction instruction) { + handleNonHeapInstruction(instruction); + } + + @Override + public void visitBinaryOp(SSABinaryOpInstruction instruction) { + handleNonHeapInstruction(instruction); + } + + @Override + public void visitComparison(SSAComparisonInstruction instruction) { + handleNonHeapInstruction(instruction); + } + + @Override + public void visitConversion(SSAConversionInstruction instruction) { + handleNonHeapInstruction(instruction); + } + + @Override + public void visitInstanceof(SSAInstanceofInstruction instruction) { + handleNonHeapInstruction(instruction); + } + + @Override + public void visitUnaryOp(SSAUnaryOpInstruction instruction) { + handleNonHeapInstruction(instruction); + } + + public ISSABasicBlock getBasicBlock() { + return basicBlock; + } + + /** + * The calling loop must call this in each iteration! + */ + public void setBasicBlock(ISSABasicBlock block) { + basicBlock = block; + } + + @Override + public void visitLoadMetadata(SSALoadMetadataInstruction instruction) { + Assertions.UNREACHABLE(); + } + + } + +} diff --git a/com.ibm.wala.core/src/com/ibm/wala/demandpa/flowgraph/GetFieldBarLabel.java b/com.ibm.wala.core/src/com/ibm/wala/demandpa/flowgraph/GetFieldBarLabel.java index cf691ea58..8acfe1397 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/demandpa/flowgraph/GetFieldBarLabel.java +++ b/com.ibm.wala.core/src/com/ibm/wala/demandpa/flowgraph/GetFieldBarLabel.java @@ -1,114 +1,114 @@ -/******************************************************************************* - * 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. - * - * This file is a derivative of code released by the University of - * California under the terms listed below. - * - * Refinement Analysis Tools is Copyright (c) 2007 The Regents of the - * University of California (Regents). Provided that this notice and - * the following two paragraphs are included in any distribution of - * Refinement Analysis Tools or its derivative work, Regents agrees - * not to assert any of Regents' copyright rights in Refinement - * Analysis Tools against recipient for recipient's reproduction, - * preparation of derivative works, public display, public - * performance, distribution or sublicensing of Refinement Analysis - * Tools and derivative works, in source code and object code form. - * This agreement not to assert does not confer, by implication, - * estoppel, or otherwise any license or rights in any intellectual - * property of Regents, including, but not limited to, any patents - * of Regents or Regents' employees. - * - * IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, - * INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, - * INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE - * AND ITS DOCUMENTATION, EVEN IF REGENTS HAS BEEN ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE AND FURTHER DISCLAIMS ANY STATUTORY - * WARRANTY OF NON-INFRINGEMENT. THE SOFTWARE AND ACCOMPANYING - * DOCUMENTATION, IF ANY, PROVIDED HEREUNDER IS PROVIDED "AS - * IS". REGENTS HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, - * UPDATES, ENHANCEMENTS, OR MODIFICATIONS. - */ -package com.ibm.wala.demandpa.flowgraph; - -import com.ibm.wala.classLoader.IField; - -/** - * @author Manu Sridharan - * - */ -public class GetFieldBarLabel implements IFlowLabel { - - private final IField field; - - private GetFieldBarLabel(final IField field) { - this.field = field; - } - - public static GetFieldBarLabel make(IField field) { - // TODO cache these? - return new GetFieldBarLabel(field); - } - - public IField getField() { - return field; - } - - /* - * (non-Javadoc) - * - * @see demandGraph.IFlowLabel#bar() - */ - public GetFieldLabel bar() { - return GetFieldLabel.make(field); - } - - /* - * (non-Javadoc) - * - * @see demandGraph.IFlowLabel#visit(demandGraph.IFlowLabel.IFlowLabelVisitor, - * java.lang.Object) - */ - public void visit(IFlowLabelVisitor v, Object dst) throws IllegalArgumentException { - if (v == null) { - throw new IllegalArgumentException("v == null"); - } - v.visitGetFieldBar(this, dst); - } - - @Override - public int hashCode() { - final int PRIME = 31; - int result = 1; - result = PRIME * result + ((field == null) ? 0 : field.hashCode()); - return result; - } - - @Override - public boolean equals(Object obj) { - if (this == obj) - return true; - if (obj == null) - return false; - if (getClass() != obj.getClass()) - return false; - final GetFieldBarLabel other = (GetFieldBarLabel) obj; - if (field == null) { - if (other.field != null) - return false; - } else if (!field.equals(other.field)) - return false; - return true; - } - - public boolean isBarred() { - return true; - } - -} +/******************************************************************************* + * 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. + * + * This file is a derivative of code released by the University of + * California under the terms listed below. + * + * Refinement Analysis Tools is Copyright (c) 2007 The Regents of the + * University of California (Regents). Provided that this notice and + * the following two paragraphs are included in any distribution of + * Refinement Analysis Tools or its derivative work, Regents agrees + * not to assert any of Regents' copyright rights in Refinement + * Analysis Tools against recipient for recipient's reproduction, + * preparation of derivative works, public display, public + * performance, distribution or sublicensing of Refinement Analysis + * Tools and derivative works, in source code and object code form. + * This agreement not to assert does not confer, by implication, + * estoppel, or otherwise any license or rights in any intellectual + * property of Regents, including, but not limited to, any patents + * of Regents or Regents' employees. + * + * IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, + * INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, + * INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE + * AND ITS DOCUMENTATION, EVEN IF REGENTS HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE AND FURTHER DISCLAIMS ANY STATUTORY + * WARRANTY OF NON-INFRINGEMENT. THE SOFTWARE AND ACCOMPANYING + * DOCUMENTATION, IF ANY, PROVIDED HEREUNDER IS PROVIDED "AS + * IS". REGENTS HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, + * UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + */ +package com.ibm.wala.demandpa.flowgraph; + +import com.ibm.wala.classLoader.IField; + +/** + * @author Manu Sridharan + * + */ +public class GetFieldBarLabel implements IFlowLabel { + + private final IField field; + + private GetFieldBarLabel(final IField field) { + this.field = field; + } + + public static GetFieldBarLabel make(IField field) { + // TODO cache these? + return new GetFieldBarLabel(field); + } + + public IField getField() { + return field; + } + + /* + * (non-Javadoc) + * + * @see demandGraph.IFlowLabel#bar() + */ + public GetFieldLabel bar() { + return GetFieldLabel.make(field); + } + + /* + * (non-Javadoc) + * + * @see demandGraph.IFlowLabel#visit(demandGraph.IFlowLabel.IFlowLabelVisitor, + * java.lang.Object) + */ + public void visit(IFlowLabelVisitor v, Object dst) throws IllegalArgumentException { + if (v == null) { + throw new IllegalArgumentException("v == null"); + } + v.visitGetFieldBar(this, dst); + } + + @Override + public int hashCode() { + final int PRIME = 31; + int result = 1; + result = PRIME * result + ((field == null) ? 0 : field.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + final GetFieldBarLabel other = (GetFieldBarLabel) obj; + if (field == null) { + if (other.field != null) + return false; + } else if (!field.equals(other.field)) + return false; + return true; + } + + public boolean isBarred() { + return true; + } + +} diff --git a/com.ibm.wala.core/src/com/ibm/wala/demandpa/flowgraph/GetFieldLabel.java b/com.ibm.wala.core/src/com/ibm/wala/demandpa/flowgraph/GetFieldLabel.java index 153e60499..bccddfcfb 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/demandpa/flowgraph/GetFieldLabel.java +++ b/com.ibm.wala.core/src/com/ibm/wala/demandpa/flowgraph/GetFieldLabel.java @@ -1,104 +1,104 @@ -/******************************************************************************* - * 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. - * - * This file is a derivative of code released by the University of - * California under the terms listed below. - * - * Refinement Analysis Tools is Copyright (c) 2007 The Regents of the - * University of California (Regents). Provided that this notice and - * the following two paragraphs are included in any distribution of - * Refinement Analysis Tools or its derivative work, Regents agrees - * not to assert any of Regents' copyright rights in Refinement - * Analysis Tools against recipient for recipient's reproduction, - * preparation of derivative works, public display, public - * performance, distribution or sublicensing of Refinement Analysis - * Tools and derivative works, in source code and object code form. - * This agreement not to assert does not confer, by implication, - * estoppel, or otherwise any license or rights in any intellectual - * property of Regents, including, but not limited to, any patents - * of Regents or Regents' employees. - * - * IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, - * INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, - * INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE - * AND ITS DOCUMENTATION, EVEN IF REGENTS HAS BEEN ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE AND FURTHER DISCLAIMS ANY STATUTORY - * WARRANTY OF NON-INFRINGEMENT. THE SOFTWARE AND ACCOMPANYING - * DOCUMENTATION, IF ANY, PROVIDED HEREUNDER IS PROVIDED "AS - * IS". REGENTS HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, - * UPDATES, ENHANCEMENTS, OR MODIFICATIONS. - */ -package com.ibm.wala.demandpa.flowgraph; - -import com.ibm.wala.classLoader.IField; - -public class GetFieldLabel implements IFlowLabel { - - private final IField field; - - private GetFieldLabel(final IField field) { - this.field = field; - } - - public static GetFieldLabel make(IField field) { - // TODO cache these? - return new GetFieldLabel(field); - } - - public IField getField() { - return field; - } - - @Override - public int hashCode() { - final int PRIME = 31; - int result = 1; - result = PRIME * result + ((field == null) ? 0 : field.hashCode()); - return result; - } - - @Override - public boolean equals(Object obj) { - if (this == obj) - return true; - if (obj == null) - return false; - if (getClass() != obj.getClass()) - return false; - final GetFieldLabel other = (GetFieldLabel) obj; - if (field == null) { - if (other.field != null) - return false; - } else if (!field.equals(other.field)) - return false; - return true; - } - - public void visit(IFlowLabelVisitor v, Object dst) throws IllegalArgumentException { - if (v == null) { - throw new IllegalArgumentException("v == null"); - } - v.visitGetField(this, dst); - } - - @Override - public String toString() { - return "getfield[" + field + "]"; - } - - public GetFieldBarLabel bar() { - return GetFieldBarLabel.make(field); - } - - public boolean isBarred() { - return false; - } - -} +/******************************************************************************* + * 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. + * + * This file is a derivative of code released by the University of + * California under the terms listed below. + * + * Refinement Analysis Tools is Copyright (c) 2007 The Regents of the + * University of California (Regents). Provided that this notice and + * the following two paragraphs are included in any distribution of + * Refinement Analysis Tools or its derivative work, Regents agrees + * not to assert any of Regents' copyright rights in Refinement + * Analysis Tools against recipient for recipient's reproduction, + * preparation of derivative works, public display, public + * performance, distribution or sublicensing of Refinement Analysis + * Tools and derivative works, in source code and object code form. + * This agreement not to assert does not confer, by implication, + * estoppel, or otherwise any license or rights in any intellectual + * property of Regents, including, but not limited to, any patents + * of Regents or Regents' employees. + * + * IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, + * INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, + * INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE + * AND ITS DOCUMENTATION, EVEN IF REGENTS HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE AND FURTHER DISCLAIMS ANY STATUTORY + * WARRANTY OF NON-INFRINGEMENT. THE SOFTWARE AND ACCOMPANYING + * DOCUMENTATION, IF ANY, PROVIDED HEREUNDER IS PROVIDED "AS + * IS". REGENTS HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, + * UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + */ +package com.ibm.wala.demandpa.flowgraph; + +import com.ibm.wala.classLoader.IField; + +public class GetFieldLabel implements IFlowLabel { + + private final IField field; + + private GetFieldLabel(final IField field) { + this.field = field; + } + + public static GetFieldLabel make(IField field) { + // TODO cache these? + return new GetFieldLabel(field); + } + + public IField getField() { + return field; + } + + @Override + public int hashCode() { + final int PRIME = 31; + int result = 1; + result = PRIME * result + ((field == null) ? 0 : field.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + final GetFieldLabel other = (GetFieldLabel) obj; + if (field == null) { + if (other.field != null) + return false; + } else if (!field.equals(other.field)) + return false; + return true; + } + + public void visit(IFlowLabelVisitor v, Object dst) throws IllegalArgumentException { + if (v == null) { + throw new IllegalArgumentException("v == null"); + } + v.visitGetField(this, dst); + } + + @Override + public String toString() { + return "getfield[" + field + "]"; + } + + public GetFieldBarLabel bar() { + return GetFieldBarLabel.make(field); + } + + public boolean isBarred() { + return false; + } + +} diff --git a/com.ibm.wala.core/src/com/ibm/wala/demandpa/flowgraph/IFlowLabel.java b/com.ibm.wala.core/src/com/ibm/wala/demandpa/flowgraph/IFlowLabel.java index 0bb322436..49f6d96b7 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/demandpa/flowgraph/IFlowLabel.java +++ b/com.ibm.wala.core/src/com/ibm/wala/demandpa/flowgraph/IFlowLabel.java @@ -1,98 +1,98 @@ -/******************************************************************************* - * 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. - * - * This file is a derivative of code released by the University of - * California under the terms listed below. - * - * Refinement Analysis Tools is Copyright (c) 2007 The Regents of the - * University of California (Regents). Provided that this notice and - * the following two paragraphs are included in any distribution of - * Refinement Analysis Tools or its derivative work, Regents agrees - * not to assert any of Regents' copyright rights in Refinement - * Analysis Tools against recipient for recipient's reproduction, - * preparation of derivative works, public display, public - * performance, distribution or sublicensing of Refinement Analysis - * Tools and derivative works, in source code and object code form. - * This agreement not to assert does not confer, by implication, - * estoppel, or otherwise any license or rights in any intellectual - * property of Regents, including, but not limited to, any patents - * of Regents or Regents' employees. - * - * IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, - * INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, - * INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE - * AND ITS DOCUMENTATION, EVEN IF REGENTS HAS BEEN ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE AND FURTHER DISCLAIMS ANY STATUTORY - * WARRANTY OF NON-INFRINGEMENT. THE SOFTWARE AND ACCOMPANYING - * DOCUMENTATION, IF ANY, PROVIDED HEREUNDER IS PROVIDED "AS - * IS". REGENTS HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, - * UPDATES, ENHANCEMENTS, OR MODIFICATIONS. - */ -package com.ibm.wala.demandpa.flowgraph; - -/** - * An edge label in a flow graph - * - * @author manu - * - */ -public interface IFlowLabel { - - public void visit(IFlowLabelVisitor v, Object dst); - - /** - * - * @return the bar (inverse) edge corresponding to this edge - */ - public IFlowLabel bar(); - - public interface IFlowLabelVisitor { - - void visitAssignGlobal(AssignGlobalLabel label, Object dst); - - void visitAssign(AssignLabel label, Object dst); - - void visitGetField(GetFieldLabel label, Object dst); - - void visitMatch(MatchLabel label, Object dst); - - void visitNew(NewLabel label, Object dst); - - void visitPutField(PutFieldLabel label, Object dst); - - void visitParam(ParamLabel label, Object dst); - - void visitReturn(ReturnLabel label, Object dst); - - void visitAssignGlobalBar(AssignGlobalBarLabel label, Object dst); - - void visitAssignBar(AssignBarLabel label, Object dst); - - void visitGetFieldBar(GetFieldBarLabel label, Object dst); - - void visitMatchBar(MatchBarLabel label, Object dst); - - void visitNewBar(NewBarLabel label, Object dst); - - void visitPutFieldBar(PutFieldBarLabel label, Object dst); - - void visitReturnBar(ReturnBarLabel label, Object dst); - - void visitParamBar(ParamBarLabel label, Object dst); - - } - - /** - * - * @return true if this is a "barred" edge - */ - public boolean isBarred(); - -} +/******************************************************************************* + * 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. + * + * This file is a derivative of code released by the University of + * California under the terms listed below. + * + * Refinement Analysis Tools is Copyright (c) 2007 The Regents of the + * University of California (Regents). Provided that this notice and + * the following two paragraphs are included in any distribution of + * Refinement Analysis Tools or its derivative work, Regents agrees + * not to assert any of Regents' copyright rights in Refinement + * Analysis Tools against recipient for recipient's reproduction, + * preparation of derivative works, public display, public + * performance, distribution or sublicensing of Refinement Analysis + * Tools and derivative works, in source code and object code form. + * This agreement not to assert does not confer, by implication, + * estoppel, or otherwise any license or rights in any intellectual + * property of Regents, including, but not limited to, any patents + * of Regents or Regents' employees. + * + * IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, + * INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, + * INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE + * AND ITS DOCUMENTATION, EVEN IF REGENTS HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE AND FURTHER DISCLAIMS ANY STATUTORY + * WARRANTY OF NON-INFRINGEMENT. THE SOFTWARE AND ACCOMPANYING + * DOCUMENTATION, IF ANY, PROVIDED HEREUNDER IS PROVIDED "AS + * IS". REGENTS HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, + * UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + */ +package com.ibm.wala.demandpa.flowgraph; + +/** + * An edge label in a flow graph + * + * @author manu + * + */ +public interface IFlowLabel { + + public void visit(IFlowLabelVisitor v, Object dst); + + /** + * + * @return the bar (inverse) edge corresponding to this edge + */ + public IFlowLabel bar(); + + public interface IFlowLabelVisitor { + + void visitAssignGlobal(AssignGlobalLabel label, Object dst); + + void visitAssign(AssignLabel label, Object dst); + + void visitGetField(GetFieldLabel label, Object dst); + + void visitMatch(MatchLabel label, Object dst); + + void visitNew(NewLabel label, Object dst); + + void visitPutField(PutFieldLabel label, Object dst); + + void visitParam(ParamLabel label, Object dst); + + void visitReturn(ReturnLabel label, Object dst); + + void visitAssignGlobalBar(AssignGlobalBarLabel label, Object dst); + + void visitAssignBar(AssignBarLabel label, Object dst); + + void visitGetFieldBar(GetFieldBarLabel label, Object dst); + + void visitMatchBar(MatchBarLabel label, Object dst); + + void visitNewBar(NewBarLabel label, Object dst); + + void visitPutFieldBar(PutFieldBarLabel label, Object dst); + + void visitReturnBar(ReturnBarLabel label, Object dst); + + void visitParamBar(ParamBarLabel label, Object dst); + + } + + /** + * + * @return true if this is a "barred" edge + */ + public boolean isBarred(); + +} diff --git a/com.ibm.wala.core/src/com/ibm/wala/demandpa/flowgraph/MatchBarLabel.java b/com.ibm.wala.core/src/com/ibm/wala/demandpa/flowgraph/MatchBarLabel.java index 092ab9f2b..9b0a45b19 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/demandpa/flowgraph/MatchBarLabel.java +++ b/com.ibm.wala.core/src/com/ibm/wala/demandpa/flowgraph/MatchBarLabel.java @@ -1,77 +1,77 @@ -/******************************************************************************* - * 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. - * - * This file is a derivative of code released by the University of - * California under the terms listed below. - * - * Refinement Analysis Tools is Copyright (c) 2007 The Regents of the - * University of California (Regents). Provided that this notice and - * the following two paragraphs are included in any distribution of - * Refinement Analysis Tools or its derivative work, Regents agrees - * not to assert any of Regents' copyright rights in Refinement - * Analysis Tools against recipient for recipient's reproduction, - * preparation of derivative works, public display, public - * performance, distribution or sublicensing of Refinement Analysis - * Tools and derivative works, in source code and object code form. - * This agreement not to assert does not confer, by implication, - * estoppel, or otherwise any license or rights in any intellectual - * property of Regents, including, but not limited to, any patents - * of Regents or Regents' employees. - * - * IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, - * INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, - * INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE - * AND ITS DOCUMENTATION, EVEN IF REGENTS HAS BEEN ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE AND FURTHER DISCLAIMS ANY STATUTORY - * WARRANTY OF NON-INFRINGEMENT. THE SOFTWARE AND ACCOMPANYING - * DOCUMENTATION, IF ANY, PROVIDED HEREUNDER IS PROVIDED "AS - * IS". REGENTS HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, - * UPDATES, ENHANCEMENTS, OR MODIFICATIONS. - */ -package com.ibm.wala.demandpa.flowgraph; - -/** - * @author Manu Sridharan - * - */ -public class MatchBarLabel implements IFlowLabel { - - private static final MatchBarLabel theInstance = new MatchBarLabel(); - - private MatchBarLabel() { - } - - public static MatchBarLabel v() { - return theInstance; - } - - /* - * @see demandGraph.IFlowLabel#bar() - */ - public MatchLabel bar() { - return MatchLabel.v(); - } - - /* - * @see demandGraph.IFlowLabel#visit(demandGraph.IFlowLabel.IFlowLabelVisitor, - * java.lang.Object) - */ - public void visit(IFlowLabelVisitor v, Object dst) throws IllegalArgumentException { - if (v == null) { - throw new IllegalArgumentException("v == null"); - } - v.visitMatchBar(this, dst); - } - - public boolean isBarred() { - return true; - } - -} +/******************************************************************************* + * 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. + * + * This file is a derivative of code released by the University of + * California under the terms listed below. + * + * Refinement Analysis Tools is Copyright (c) 2007 The Regents of the + * University of California (Regents). Provided that this notice and + * the following two paragraphs are included in any distribution of + * Refinement Analysis Tools or its derivative work, Regents agrees + * not to assert any of Regents' copyright rights in Refinement + * Analysis Tools against recipient for recipient's reproduction, + * preparation of derivative works, public display, public + * performance, distribution or sublicensing of Refinement Analysis + * Tools and derivative works, in source code and object code form. + * This agreement not to assert does not confer, by implication, + * estoppel, or otherwise any license or rights in any intellectual + * property of Regents, including, but not limited to, any patents + * of Regents or Regents' employees. + * + * IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, + * INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, + * INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE + * AND ITS DOCUMENTATION, EVEN IF REGENTS HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE AND FURTHER DISCLAIMS ANY STATUTORY + * WARRANTY OF NON-INFRINGEMENT. THE SOFTWARE AND ACCOMPANYING + * DOCUMENTATION, IF ANY, PROVIDED HEREUNDER IS PROVIDED "AS + * IS". REGENTS HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, + * UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + */ +package com.ibm.wala.demandpa.flowgraph; + +/** + * @author Manu Sridharan + * + */ +public class MatchBarLabel implements IFlowLabel { + + private static final MatchBarLabel theInstance = new MatchBarLabel(); + + private MatchBarLabel() { + } + + public static MatchBarLabel v() { + return theInstance; + } + + /* + * @see demandGraph.IFlowLabel#bar() + */ + public MatchLabel bar() { + return MatchLabel.v(); + } + + /* + * @see demandGraph.IFlowLabel#visit(demandGraph.IFlowLabel.IFlowLabelVisitor, + * java.lang.Object) + */ + public void visit(IFlowLabelVisitor v, Object dst) throws IllegalArgumentException { + if (v == null) { + throw new IllegalArgumentException("v == null"); + } + v.visitMatchBar(this, dst); + } + + public boolean isBarred() { + return true; + } + +} diff --git a/com.ibm.wala.core/src/com/ibm/wala/demandpa/flowgraph/MatchLabel.java b/com.ibm.wala.core/src/com/ibm/wala/demandpa/flowgraph/MatchLabel.java index 4e8200807..d4da54995 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/demandpa/flowgraph/MatchLabel.java +++ b/com.ibm.wala.core/src/com/ibm/wala/demandpa/flowgraph/MatchLabel.java @@ -1,70 +1,70 @@ -/******************************************************************************* - * 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. - * - * This file is a derivative of code released by the University of - * California under the terms listed below. - * - * Refinement Analysis Tools is Copyright (c) 2007 The Regents of the - * University of California (Regents). Provided that this notice and - * the following two paragraphs are included in any distribution of - * Refinement Analysis Tools or its derivative work, Regents agrees - * not to assert any of Regents' copyright rights in Refinement - * Analysis Tools against recipient for recipient's reproduction, - * preparation of derivative works, public display, public - * performance, distribution or sublicensing of Refinement Analysis - * Tools and derivative works, in source code and object code form. - * This agreement not to assert does not confer, by implication, - * estoppel, or otherwise any license or rights in any intellectual - * property of Regents, including, but not limited to, any patents - * of Regents or Regents' employees. - * - * IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, - * INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, - * INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE - * AND ITS DOCUMENTATION, EVEN IF REGENTS HAS BEEN ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE AND FURTHER DISCLAIMS ANY STATUTORY - * WARRANTY OF NON-INFRINGEMENT. THE SOFTWARE AND ACCOMPANYING - * DOCUMENTATION, IF ANY, PROVIDED HEREUNDER IS PROVIDED "AS - * IS". REGENTS HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, - * UPDATES, ENHANCEMENTS, OR MODIFICATIONS. - */ -package com.ibm.wala.demandpa.flowgraph; - -public class MatchLabel implements IFlowLabel { - - private static final MatchLabel theInstance = new MatchLabel(); - - private MatchLabel() { - } - - public static MatchLabel v() { - return theInstance; - } - - public void visit(IFlowLabelVisitor v, Object dst) throws IllegalArgumentException { - if (v == null) { - throw new IllegalArgumentException("v == null"); - } - v.visitMatch(this, dst); - } - - @Override - public String toString() { - return "match"; - } - - public MatchBarLabel bar() { - return MatchBarLabel.v(); - } - - public boolean isBarred() { - return false; - } -} +/******************************************************************************* + * 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. + * + * This file is a derivative of code released by the University of + * California under the terms listed below. + * + * Refinement Analysis Tools is Copyright (c) 2007 The Regents of the + * University of California (Regents). Provided that this notice and + * the following two paragraphs are included in any distribution of + * Refinement Analysis Tools or its derivative work, Regents agrees + * not to assert any of Regents' copyright rights in Refinement + * Analysis Tools against recipient for recipient's reproduction, + * preparation of derivative works, public display, public + * performance, distribution or sublicensing of Refinement Analysis + * Tools and derivative works, in source code and object code form. + * This agreement not to assert does not confer, by implication, + * estoppel, or otherwise any license or rights in any intellectual + * property of Regents, including, but not limited to, any patents + * of Regents or Regents' employees. + * + * IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, + * INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, + * INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE + * AND ITS DOCUMENTATION, EVEN IF REGENTS HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE AND FURTHER DISCLAIMS ANY STATUTORY + * WARRANTY OF NON-INFRINGEMENT. THE SOFTWARE AND ACCOMPANYING + * DOCUMENTATION, IF ANY, PROVIDED HEREUNDER IS PROVIDED "AS + * IS". REGENTS HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, + * UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + */ +package com.ibm.wala.demandpa.flowgraph; + +public class MatchLabel implements IFlowLabel { + + private static final MatchLabel theInstance = new MatchLabel(); + + private MatchLabel() { + } + + public static MatchLabel v() { + return theInstance; + } + + public void visit(IFlowLabelVisitor v, Object dst) throws IllegalArgumentException { + if (v == null) { + throw new IllegalArgumentException("v == null"); + } + v.visitMatch(this, dst); + } + + @Override + public String toString() { + return "match"; + } + + public MatchBarLabel bar() { + return MatchBarLabel.v(); + } + + public boolean isBarred() { + return false; + } +} diff --git a/com.ibm.wala.core/src/com/ibm/wala/demandpa/flowgraph/NewBarLabel.java b/com.ibm.wala.core/src/com/ibm/wala/demandpa/flowgraph/NewBarLabel.java index c436f09ee..d56e45926 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/demandpa/flowgraph/NewBarLabel.java +++ b/com.ibm.wala.core/src/com/ibm/wala/demandpa/flowgraph/NewBarLabel.java @@ -1,77 +1,77 @@ -/******************************************************************************* - * 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. - * - * This file is a derivative of code released by the University of - * California under the terms listed below. - * - * Refinement Analysis Tools is Copyright (c) 2007 The Regents of the - * University of California (Regents). Provided that this notice and - * the following two paragraphs are included in any distribution of - * Refinement Analysis Tools or its derivative work, Regents agrees - * not to assert any of Regents' copyright rights in Refinement - * Analysis Tools against recipient for recipient's reproduction, - * preparation of derivative works, public display, public - * performance, distribution or sublicensing of Refinement Analysis - * Tools and derivative works, in source code and object code form. - * This agreement not to assert does not confer, by implication, - * estoppel, or otherwise any license or rights in any intellectual - * property of Regents, including, but not limited to, any patents - * of Regents or Regents' employees. - * - * IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, - * INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, - * INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE - * AND ITS DOCUMENTATION, EVEN IF REGENTS HAS BEEN ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE AND FURTHER DISCLAIMS ANY STATUTORY - * WARRANTY OF NON-INFRINGEMENT. THE SOFTWARE AND ACCOMPANYING - * DOCUMENTATION, IF ANY, PROVIDED HEREUNDER IS PROVIDED "AS - * IS". REGENTS HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, - * UPDATES, ENHANCEMENTS, OR MODIFICATIONS. - */ -package com.ibm.wala.demandpa.flowgraph; - -/** - * @author Manu Sridharan - * - */ -public class NewBarLabel implements IFlowLabel { - - private static final NewBarLabel theInstance = new NewBarLabel(); - - private NewBarLabel() { - } - - public static NewBarLabel v() { - return theInstance; - } - - /* - * @see demandGraph.IFlowLabel#bar() - */ - public NewLabel bar() { - return NewLabel.v(); - } - - /* - * @see demandGraph.IFlowLabel#visit(demandGraph.IFlowLabel.IFlowLabelVisitor, - * java.lang.Object) - */ - public void visit(IFlowLabelVisitor v, Object dst) throws IllegalArgumentException { - if (v == null) { - throw new IllegalArgumentException("v == null"); - } - v.visitNewBar(this, dst); - } - - public boolean isBarred() { - return true; - } - -} +/******************************************************************************* + * 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. + * + * This file is a derivative of code released by the University of + * California under the terms listed below. + * + * Refinement Analysis Tools is Copyright (c) 2007 The Regents of the + * University of California (Regents). Provided that this notice and + * the following two paragraphs are included in any distribution of + * Refinement Analysis Tools or its derivative work, Regents agrees + * not to assert any of Regents' copyright rights in Refinement + * Analysis Tools against recipient for recipient's reproduction, + * preparation of derivative works, public display, public + * performance, distribution or sublicensing of Refinement Analysis + * Tools and derivative works, in source code and object code form. + * This agreement not to assert does not confer, by implication, + * estoppel, or otherwise any license or rights in any intellectual + * property of Regents, including, but not limited to, any patents + * of Regents or Regents' employees. + * + * IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, + * INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, + * INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE + * AND ITS DOCUMENTATION, EVEN IF REGENTS HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE AND FURTHER DISCLAIMS ANY STATUTORY + * WARRANTY OF NON-INFRINGEMENT. THE SOFTWARE AND ACCOMPANYING + * DOCUMENTATION, IF ANY, PROVIDED HEREUNDER IS PROVIDED "AS + * IS". REGENTS HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, + * UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + */ +package com.ibm.wala.demandpa.flowgraph; + +/** + * @author Manu Sridharan + * + */ +public class NewBarLabel implements IFlowLabel { + + private static final NewBarLabel theInstance = new NewBarLabel(); + + private NewBarLabel() { + } + + public static NewBarLabel v() { + return theInstance; + } + + /* + * @see demandGraph.IFlowLabel#bar() + */ + public NewLabel bar() { + return NewLabel.v(); + } + + /* + * @see demandGraph.IFlowLabel#visit(demandGraph.IFlowLabel.IFlowLabelVisitor, + * java.lang.Object) + */ + public void visit(IFlowLabelVisitor v, Object dst) throws IllegalArgumentException { + if (v == null) { + throw new IllegalArgumentException("v == null"); + } + v.visitNewBar(this, dst); + } + + public boolean isBarred() { + return true; + } + +} diff --git a/com.ibm.wala.core/src/com/ibm/wala/demandpa/flowgraph/NewLabel.java b/com.ibm.wala.core/src/com/ibm/wala/demandpa/flowgraph/NewLabel.java index 8348460cf..a1209ec91 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/demandpa/flowgraph/NewLabel.java +++ b/com.ibm.wala.core/src/com/ibm/wala/demandpa/flowgraph/NewLabel.java @@ -1,70 +1,70 @@ -/******************************************************************************* - * 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. - * - * This file is a derivative of code released by the University of - * California under the terms listed below. - * - * Refinement Analysis Tools is Copyright (c) 2007 The Regents of the - * University of California (Regents). Provided that this notice and - * the following two paragraphs are included in any distribution of - * Refinement Analysis Tools or its derivative work, Regents agrees - * not to assert any of Regents' copyright rights in Refinement - * Analysis Tools against recipient for recipient's reproduction, - * preparation of derivative works, public display, public - * performance, distribution or sublicensing of Refinement Analysis - * Tools and derivative works, in source code and object code form. - * This agreement not to assert does not confer, by implication, - * estoppel, or otherwise any license or rights in any intellectual - * property of Regents, including, but not limited to, any patents - * of Regents or Regents' employees. - * - * IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, - * INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, - * INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE - * AND ITS DOCUMENTATION, EVEN IF REGENTS HAS BEEN ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE AND FURTHER DISCLAIMS ANY STATUTORY - * WARRANTY OF NON-INFRINGEMENT. THE SOFTWARE AND ACCOMPANYING - * DOCUMENTATION, IF ANY, PROVIDED HEREUNDER IS PROVIDED "AS - * IS". REGENTS HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, - * UPDATES, ENHANCEMENTS, OR MODIFICATIONS. - */ -package com.ibm.wala.demandpa.flowgraph; - -public class NewLabel implements IFlowLabel { - - private static final NewLabel theInstance = new NewLabel(); - - private NewLabel() { - } - - public static NewLabel v() { - return theInstance; - } - - public void visit(IFlowLabelVisitor v, Object dst) throws IllegalArgumentException { - if (v == null) { - throw new IllegalArgumentException("v == null"); - } - v.visitNew(this, dst); - } - - @Override - public String toString() { - return "new"; - } - - public NewBarLabel bar() { - return NewBarLabel.v(); - } - - public boolean isBarred() { - return false; - } -} +/******************************************************************************* + * 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. + * + * This file is a derivative of code released by the University of + * California under the terms listed below. + * + * Refinement Analysis Tools is Copyright (c) 2007 The Regents of the + * University of California (Regents). Provided that this notice and + * the following two paragraphs are included in any distribution of + * Refinement Analysis Tools or its derivative work, Regents agrees + * not to assert any of Regents' copyright rights in Refinement + * Analysis Tools against recipient for recipient's reproduction, + * preparation of derivative works, public display, public + * performance, distribution or sublicensing of Refinement Analysis + * Tools and derivative works, in source code and object code form. + * This agreement not to assert does not confer, by implication, + * estoppel, or otherwise any license or rights in any intellectual + * property of Regents, including, but not limited to, any patents + * of Regents or Regents' employees. + * + * IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, + * INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, + * INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE + * AND ITS DOCUMENTATION, EVEN IF REGENTS HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE AND FURTHER DISCLAIMS ANY STATUTORY + * WARRANTY OF NON-INFRINGEMENT. THE SOFTWARE AND ACCOMPANYING + * DOCUMENTATION, IF ANY, PROVIDED HEREUNDER IS PROVIDED "AS + * IS". REGENTS HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, + * UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + */ +package com.ibm.wala.demandpa.flowgraph; + +public class NewLabel implements IFlowLabel { + + private static final NewLabel theInstance = new NewLabel(); + + private NewLabel() { + } + + public static NewLabel v() { + return theInstance; + } + + public void visit(IFlowLabelVisitor v, Object dst) throws IllegalArgumentException { + if (v == null) { + throw new IllegalArgumentException("v == null"); + } + v.visitNew(this, dst); + } + + @Override + public String toString() { + return "new"; + } + + public NewBarLabel bar() { + return NewBarLabel.v(); + } + + public boolean isBarred() { + return false; + } +} diff --git a/com.ibm.wala.core/src/com/ibm/wala/demandpa/flowgraph/ParamBarLabel.java b/com.ibm.wala.core/src/com/ibm/wala/demandpa/flowgraph/ParamBarLabel.java index 8e4b7d147..eaabf93c2 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/demandpa/flowgraph/ParamBarLabel.java +++ b/com.ibm.wala.core/src/com/ibm/wala/demandpa/flowgraph/ParamBarLabel.java @@ -1,81 +1,81 @@ -/******************************************************************************* - * 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. - * - * This file is a derivative of code released by the University of - * California under the terms listed below. - * - * Refinement Analysis Tools is Copyright (c) 2007 The Regents of the - * University of California (Regents). Provided that this notice and - * the following two paragraphs are included in any distribution of - * Refinement Analysis Tools or its derivative work, Regents agrees - * not to assert any of Regents' copyright rights in Refinement - * Analysis Tools against recipient for recipient's reproduction, - * preparation of derivative works, public display, public - * performance, distribution or sublicensing of Refinement Analysis - * Tools and derivative works, in source code and object code form. - * This agreement not to assert does not confer, by implication, - * estoppel, or otherwise any license or rights in any intellectual - * property of Regents, including, but not limited to, any patents - * of Regents or Regents' employees. - * - * IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, - * INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, - * INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE - * AND ITS DOCUMENTATION, EVEN IF REGENTS HAS BEEN ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE AND FURTHER DISCLAIMS ANY STATUTORY - * WARRANTY OF NON-INFRINGEMENT. THE SOFTWARE AND ACCOMPANYING - * DOCUMENTATION, IF ANY, PROVIDED HEREUNDER IS PROVIDED "AS - * IS". REGENTS HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, - * UPDATES, ENHANCEMENTS, OR MODIFICATIONS. - */ -package com.ibm.wala.demandpa.flowgraph; - -import com.ibm.wala.ipa.callgraph.propagation.cfa.CallerSiteContext; - -/** - */ -public class ParamBarLabel extends CallLabel { - - private ParamBarLabel(CallerSiteContext callSite) { - super(callSite); - } - - public static ParamBarLabel make(CallerSiteContext callSite) { - return new ParamBarLabel(callSite); - } - - /* - * @see demandGraph.IFlowLabel#bar() - */ - public ParamLabel bar() { - return ParamLabel.make(callSite); - } - - /* - * @see demandGraph.IFlowLabel#visit(demandGraph.IFlowLabel.IFlowLabelVisitor, - * java.lang.Object) - */ - public void visit(IFlowLabelVisitor v, Object dst) throws IllegalArgumentException { - if (v == null) { - throw new IllegalArgumentException("v == null"); - } - v.visitParamBar(this, dst); - } - - public boolean isBarred() { - return true; - } - - @Override - public String toString() { - return "paramBar[" + callSite + "]"; - } - -} +/******************************************************************************* + * 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. + * + * This file is a derivative of code released by the University of + * California under the terms listed below. + * + * Refinement Analysis Tools is Copyright (c) 2007 The Regents of the + * University of California (Regents). Provided that this notice and + * the following two paragraphs are included in any distribution of + * Refinement Analysis Tools or its derivative work, Regents agrees + * not to assert any of Regents' copyright rights in Refinement + * Analysis Tools against recipient for recipient's reproduction, + * preparation of derivative works, public display, public + * performance, distribution or sublicensing of Refinement Analysis + * Tools and derivative works, in source code and object code form. + * This agreement not to assert does not confer, by implication, + * estoppel, or otherwise any license or rights in any intellectual + * property of Regents, including, but not limited to, any patents + * of Regents or Regents' employees. + * + * IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, + * INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, + * INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE + * AND ITS DOCUMENTATION, EVEN IF REGENTS HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE AND FURTHER DISCLAIMS ANY STATUTORY + * WARRANTY OF NON-INFRINGEMENT. THE SOFTWARE AND ACCOMPANYING + * DOCUMENTATION, IF ANY, PROVIDED HEREUNDER IS PROVIDED "AS + * IS". REGENTS HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, + * UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + */ +package com.ibm.wala.demandpa.flowgraph; + +import com.ibm.wala.ipa.callgraph.propagation.cfa.CallerSiteContext; + +/** + */ +public class ParamBarLabel extends CallLabel { + + private ParamBarLabel(CallerSiteContext callSite) { + super(callSite); + } + + public static ParamBarLabel make(CallerSiteContext callSite) { + return new ParamBarLabel(callSite); + } + + /* + * @see demandGraph.IFlowLabel#bar() + */ + public ParamLabel bar() { + return ParamLabel.make(callSite); + } + + /* + * @see demandGraph.IFlowLabel#visit(demandGraph.IFlowLabel.IFlowLabelVisitor, + * java.lang.Object) + */ + public void visit(IFlowLabelVisitor v, Object dst) throws IllegalArgumentException { + if (v == null) { + throw new IllegalArgumentException("v == null"); + } + v.visitParamBar(this, dst); + } + + public boolean isBarred() { + return true; + } + + @Override + public String toString() { + return "paramBar[" + callSite + "]"; + } + +} diff --git a/com.ibm.wala.core/src/com/ibm/wala/demandpa/flowgraph/ParamLabel.java b/com.ibm.wala.core/src/com/ibm/wala/demandpa/flowgraph/ParamLabel.java index e476f34f6..085b0655c 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/demandpa/flowgraph/ParamLabel.java +++ b/com.ibm.wala.core/src/com/ibm/wala/demandpa/flowgraph/ParamLabel.java @@ -1,72 +1,72 @@ -/******************************************************************************* - * 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. - * - * This file is a derivative of code released by the University of - * California under the terms listed below. - * - * Refinement Analysis Tools is Copyright (c) 2007 The Regents of the - * University of California (Regents). Provided that this notice and - * the following two paragraphs are included in any distribution of - * Refinement Analysis Tools or its derivative work, Regents agrees - * not to assert any of Regents' copyright rights in Refinement - * Analysis Tools against recipient for recipient's reproduction, - * preparation of derivative works, public display, public - * performance, distribution or sublicensing of Refinement Analysis - * Tools and derivative works, in source code and object code form. - * This agreement not to assert does not confer, by implication, - * estoppel, or otherwise any license or rights in any intellectual - * property of Regents, including, but not limited to, any patents - * of Regents or Regents' employees. - * - * IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, - * INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, - * INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE - * AND ITS DOCUMENTATION, EVEN IF REGENTS HAS BEEN ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE AND FURTHER DISCLAIMS ANY STATUTORY - * WARRANTY OF NON-INFRINGEMENT. THE SOFTWARE AND ACCOMPANYING - * DOCUMENTATION, IF ANY, PROVIDED HEREUNDER IS PROVIDED "AS - * IS". REGENTS HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, - * UPDATES, ENHANCEMENTS, OR MODIFICATIONS. - */ -package com.ibm.wala.demandpa.flowgraph; - -import com.ibm.wala.ipa.callgraph.propagation.cfa.CallerSiteContext; - -public class ParamLabel extends CallLabel { - - private ParamLabel(CallerSiteContext callSite) { - super(callSite); - } - - public static ParamLabel make(CallerSiteContext callSite) { - return new ParamLabel(callSite); - } - - public void visit(IFlowLabelVisitor v, Object dst) throws IllegalArgumentException { - if (v == null) { - throw new IllegalArgumentException("v == null"); - } - v.visitParam(this, dst); - } - - @Override - public String toString() { - return "param[" + callSite + "]"; - } - - public ParamBarLabel bar() { - return ParamBarLabel.make(callSite); - } - - public boolean isBarred() { - return false; - } - -} +/******************************************************************************* + * 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. + * + * This file is a derivative of code released by the University of + * California under the terms listed below. + * + * Refinement Analysis Tools is Copyright (c) 2007 The Regents of the + * University of California (Regents). Provided that this notice and + * the following two paragraphs are included in any distribution of + * Refinement Analysis Tools or its derivative work, Regents agrees + * not to assert any of Regents' copyright rights in Refinement + * Analysis Tools against recipient for recipient's reproduction, + * preparation of derivative works, public display, public + * performance, distribution or sublicensing of Refinement Analysis + * Tools and derivative works, in source code and object code form. + * This agreement not to assert does not confer, by implication, + * estoppel, or otherwise any license or rights in any intellectual + * property of Regents, including, but not limited to, any patents + * of Regents or Regents' employees. + * + * IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, + * INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, + * INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE + * AND ITS DOCUMENTATION, EVEN IF REGENTS HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE AND FURTHER DISCLAIMS ANY STATUTORY + * WARRANTY OF NON-INFRINGEMENT. THE SOFTWARE AND ACCOMPANYING + * DOCUMENTATION, IF ANY, PROVIDED HEREUNDER IS PROVIDED "AS + * IS". REGENTS HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, + * UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + */ +package com.ibm.wala.demandpa.flowgraph; + +import com.ibm.wala.ipa.callgraph.propagation.cfa.CallerSiteContext; + +public class ParamLabel extends CallLabel { + + private ParamLabel(CallerSiteContext callSite) { + super(callSite); + } + + public static ParamLabel make(CallerSiteContext callSite) { + return new ParamLabel(callSite); + } + + public void visit(IFlowLabelVisitor v, Object dst) throws IllegalArgumentException { + if (v == null) { + throw new IllegalArgumentException("v == null"); + } + v.visitParam(this, dst); + } + + @Override + public String toString() { + return "param[" + callSite + "]"; + } + + public ParamBarLabel bar() { + return ParamBarLabel.make(callSite); + } + + public boolean isBarred() { + return false; + } + +} diff --git a/com.ibm.wala.core/src/com/ibm/wala/demandpa/flowgraph/PointerKeyAndCallSite.java b/com.ibm.wala.core/src/com/ibm/wala/demandpa/flowgraph/PointerKeyAndCallSite.java index f1251f9a2..4a7984583 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/demandpa/flowgraph/PointerKeyAndCallSite.java +++ b/com.ibm.wala.core/src/com/ibm/wala/demandpa/flowgraph/PointerKeyAndCallSite.java @@ -1,92 +1,92 @@ -/******************************************************************************* - * 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. - * - * This file is a derivative of code released by the University of - * California under the terms listed below. - * - * Refinement Analysis Tools is Copyright (c) 2007 The Regents of the - * University of California (Regents). Provided that this notice and - * the following two paragraphs are included in any distribution of - * Refinement Analysis Tools or its derivative work, Regents agrees - * not to assert any of Regents' copyright rights in Refinement - * Analysis Tools against recipient for recipient's reproduction, - * preparation of derivative works, public display, public - * performance, distribution or sublicensing of Refinement Analysis - * Tools and derivative works, in source code and object code form. - * This agreement not to assert does not confer, by implication, - * estoppel, or otherwise any license or rights in any intellectual - * property of Regents, including, but not limited to, any patents - * of Regents or Regents' employees. - * - * IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, - * INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, - * INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE - * AND ITS DOCUMENTATION, EVEN IF REGENTS HAS BEEN ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE AND FURTHER DISCLAIMS ANY STATUTORY - * WARRANTY OF NON-INFRINGEMENT. THE SOFTWARE AND ACCOMPANYING - * DOCUMENTATION, IF ANY, PROVIDED HEREUNDER IS PROVIDED "AS - * IS". REGENTS HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, - * UPDATES, ENHANCEMENTS, OR MODIFICATIONS. - */ -package com.ibm.wala.demandpa.flowgraph; - -import com.ibm.wala.classLoader.CallSiteReference; -import com.ibm.wala.ipa.callgraph.propagation.PointerKey; - -public class PointerKeyAndCallSite { - - private final PointerKey key; - - private final CallSiteReference callSiteRef; - - public PointerKeyAndCallSite(final PointerKey key, final CallSiteReference callSiteRef) { - if (key == null) { - throw new IllegalArgumentException("null key"); - } - if (callSiteRef == null) { - throw new IllegalArgumentException("null callSiteRef"); - } - this.key = key; - this.callSiteRef = callSiteRef; - } - - public CallSiteReference getCallSiteRef() { - return callSiteRef; - } - - public PointerKey getKey() { - return key; - } - - @Override - public int hashCode() { - final int PRIME = 31; - int result = 1; - result = PRIME * result + callSiteRef.hashCode(); - result = PRIME * result + key.hashCode(); - return result; - } - - @Override - public boolean equals(Object obj) { - if (this == obj) - return true; - if (obj == null) - return false; - if (getClass() != obj.getClass()) - return false; - final PointerKeyAndCallSite other = (PointerKeyAndCallSite) obj; - if (!callSiteRef.equals(other.callSiteRef)) - return false; - if (!key.equals(other.key)) - return false; - return true; - } +/******************************************************************************* + * 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. + * + * This file is a derivative of code released by the University of + * California under the terms listed below. + * + * Refinement Analysis Tools is Copyright (c) 2007 The Regents of the + * University of California (Regents). Provided that this notice and + * the following two paragraphs are included in any distribution of + * Refinement Analysis Tools or its derivative work, Regents agrees + * not to assert any of Regents' copyright rights in Refinement + * Analysis Tools against recipient for recipient's reproduction, + * preparation of derivative works, public display, public + * performance, distribution or sublicensing of Refinement Analysis + * Tools and derivative works, in source code and object code form. + * This agreement not to assert does not confer, by implication, + * estoppel, or otherwise any license or rights in any intellectual + * property of Regents, including, but not limited to, any patents + * of Regents or Regents' employees. + * + * IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, + * INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, + * INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE + * AND ITS DOCUMENTATION, EVEN IF REGENTS HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE AND FURTHER DISCLAIMS ANY STATUTORY + * WARRANTY OF NON-INFRINGEMENT. THE SOFTWARE AND ACCOMPANYING + * DOCUMENTATION, IF ANY, PROVIDED HEREUNDER IS PROVIDED "AS + * IS". REGENTS HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, + * UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + */ +package com.ibm.wala.demandpa.flowgraph; + +import com.ibm.wala.classLoader.CallSiteReference; +import com.ibm.wala.ipa.callgraph.propagation.PointerKey; + +public class PointerKeyAndCallSite { + + private final PointerKey key; + + private final CallSiteReference callSiteRef; + + public PointerKeyAndCallSite(final PointerKey key, final CallSiteReference callSiteRef) { + if (key == null) { + throw new IllegalArgumentException("null key"); + } + if (callSiteRef == null) { + throw new IllegalArgumentException("null callSiteRef"); + } + this.key = key; + this.callSiteRef = callSiteRef; + } + + public CallSiteReference getCallSiteRef() { + return callSiteRef; + } + + public PointerKey getKey() { + return key; + } + + @Override + public int hashCode() { + final int PRIME = 31; + int result = 1; + result = PRIME * result + callSiteRef.hashCode(); + result = PRIME * result + key.hashCode(); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + final PointerKeyAndCallSite other = (PointerKeyAndCallSite) obj; + if (!callSiteRef.equals(other.callSiteRef)) + return false; + if (!key.equals(other.key)) + return false; + return true; + } } \ No newline at end of file diff --git a/com.ibm.wala.core/src/com/ibm/wala/demandpa/flowgraph/PutFieldBarLabel.java b/com.ibm.wala.core/src/com/ibm/wala/demandpa/flowgraph/PutFieldBarLabel.java index df68a3885..e920d1986 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/demandpa/flowgraph/PutFieldBarLabel.java +++ b/com.ibm.wala.core/src/com/ibm/wala/demandpa/flowgraph/PutFieldBarLabel.java @@ -1,115 +1,115 @@ -/******************************************************************************* - * 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. - * - * This file is a derivative of code released by the University of - * California under the terms listed below. - * - * Refinement Analysis Tools is Copyright (c) 2007 The Regents of the - * University of California (Regents). Provided that this notice and - * the following two paragraphs are included in any distribution of - * Refinement Analysis Tools or its derivative work, Regents agrees - * not to assert any of Regents' copyright rights in Refinement - * Analysis Tools against recipient for recipient's reproduction, - * preparation of derivative works, public display, public - * performance, distribution or sublicensing of Refinement Analysis - * Tools and derivative works, in source code and object code form. - * This agreement not to assert does not confer, by implication, - * estoppel, or otherwise any license or rights in any intellectual - * property of Regents, including, but not limited to, any patents - * of Regents or Regents' employees. - * - * IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, - * INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, - * INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE - * AND ITS DOCUMENTATION, EVEN IF REGENTS HAS BEEN ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE AND FURTHER DISCLAIMS ANY STATUTORY - * WARRANTY OF NON-INFRINGEMENT. THE SOFTWARE AND ACCOMPANYING - * DOCUMENTATION, IF ANY, PROVIDED HEREUNDER IS PROVIDED "AS - * IS". REGENTS HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, - * UPDATES, ENHANCEMENTS, OR MODIFICATIONS. - */ -package com.ibm.wala.demandpa.flowgraph; - -import com.ibm.wala.classLoader.IField; - -/** - * @author Manu Sridharan - * - */ -public class PutFieldBarLabel implements IFlowLabel { - - private final IField field; - - @Override - public int hashCode() { - final int PRIME = 31; - int result = 1; - result = PRIME * result + ((field == null) ? 0 : field.hashCode()); - return result; - } - - @Override - public boolean equals(Object obj) { - if (this == obj) - return true; - if (obj == null) - return false; - if (getClass() != obj.getClass()) - return false; - final PutFieldBarLabel other = (PutFieldBarLabel) obj; - if (field == null) { - if (other.field != null) - return false; - } else if (!field.equals(other.field)) - return false; - return true; - } - - private PutFieldBarLabel(final IField field) { - this.field = field; - } - - public static PutFieldBarLabel make(IField field) { - // TODO cache these? - return new PutFieldBarLabel(field); - } - - public IField getField() { - return field; - } - - /* - * @see demandGraph.IFlowLabel#bar() - */ - public PutFieldLabel bar() { - return PutFieldLabel.make(field); - } - - /* - * @see demandGraph.IFlowLabel#visit(demandGraph.IFlowLabel.IFlowLabelVisitor, - * java.lang.Object) - */ - public void visit(IFlowLabelVisitor v, Object dst) throws IllegalArgumentException { - if (v == null) { - throw new IllegalArgumentException("v == null"); - } - v.visitPutFieldBar(this, dst); - } - - public boolean isBarred() { - return true; - } - - @Override - public String toString() { - return "putfield_bar[" + field + "]"; - } - -} +/******************************************************************************* + * 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. + * + * This file is a derivative of code released by the University of + * California under the terms listed below. + * + * Refinement Analysis Tools is Copyright (c) 2007 The Regents of the + * University of California (Regents). Provided that this notice and + * the following two paragraphs are included in any distribution of + * Refinement Analysis Tools or its derivative work, Regents agrees + * not to assert any of Regents' copyright rights in Refinement + * Analysis Tools against recipient for recipient's reproduction, + * preparation of derivative works, public display, public + * performance, distribution or sublicensing of Refinement Analysis + * Tools and derivative works, in source code and object code form. + * This agreement not to assert does not confer, by implication, + * estoppel, or otherwise any license or rights in any intellectual + * property of Regents, including, but not limited to, any patents + * of Regents or Regents' employees. + * + * IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, + * INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, + * INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE + * AND ITS DOCUMENTATION, EVEN IF REGENTS HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE AND FURTHER DISCLAIMS ANY STATUTORY + * WARRANTY OF NON-INFRINGEMENT. THE SOFTWARE AND ACCOMPANYING + * DOCUMENTATION, IF ANY, PROVIDED HEREUNDER IS PROVIDED "AS + * IS". REGENTS HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, + * UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + */ +package com.ibm.wala.demandpa.flowgraph; + +import com.ibm.wala.classLoader.IField; + +/** + * @author Manu Sridharan + * + */ +public class PutFieldBarLabel implements IFlowLabel { + + private final IField field; + + @Override + public int hashCode() { + final int PRIME = 31; + int result = 1; + result = PRIME * result + ((field == null) ? 0 : field.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + final PutFieldBarLabel other = (PutFieldBarLabel) obj; + if (field == null) { + if (other.field != null) + return false; + } else if (!field.equals(other.field)) + return false; + return true; + } + + private PutFieldBarLabel(final IField field) { + this.field = field; + } + + public static PutFieldBarLabel make(IField field) { + // TODO cache these? + return new PutFieldBarLabel(field); + } + + public IField getField() { + return field; + } + + /* + * @see demandGraph.IFlowLabel#bar() + */ + public PutFieldLabel bar() { + return PutFieldLabel.make(field); + } + + /* + * @see demandGraph.IFlowLabel#visit(demandGraph.IFlowLabel.IFlowLabelVisitor, + * java.lang.Object) + */ + public void visit(IFlowLabelVisitor v, Object dst) throws IllegalArgumentException { + if (v == null) { + throw new IllegalArgumentException("v == null"); + } + v.visitPutFieldBar(this, dst); + } + + public boolean isBarred() { + return true; + } + + @Override + public String toString() { + return "putfield_bar[" + field + "]"; + } + +} diff --git a/com.ibm.wala.core/src/com/ibm/wala/demandpa/flowgraph/PutFieldLabel.java b/com.ibm.wala.core/src/com/ibm/wala/demandpa/flowgraph/PutFieldLabel.java index dc64868a1..fe634f986 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/demandpa/flowgraph/PutFieldLabel.java +++ b/com.ibm.wala.core/src/com/ibm/wala/demandpa/flowgraph/PutFieldLabel.java @@ -1,104 +1,104 @@ -/******************************************************************************* - * 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. - * - * This file is a derivative of code released by the University of - * California under the terms listed below. - * - * Refinement Analysis Tools is Copyright (c) 2007 The Regents of the - * University of California (Regents). Provided that this notice and - * the following two paragraphs are included in any distribution of - * Refinement Analysis Tools or its derivative work, Regents agrees - * not to assert any of Regents' copyright rights in Refinement - * Analysis Tools against recipient for recipient's reproduction, - * preparation of derivative works, public display, public - * performance, distribution or sublicensing of Refinement Analysis - * Tools and derivative works, in source code and object code form. - * This agreement not to assert does not confer, by implication, - * estoppel, or otherwise any license or rights in any intellectual - * property of Regents, including, but not limited to, any patents - * of Regents or Regents' employees. - * - * IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, - * INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, - * INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE - * AND ITS DOCUMENTATION, EVEN IF REGENTS HAS BEEN ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE AND FURTHER DISCLAIMS ANY STATUTORY - * WARRANTY OF NON-INFRINGEMENT. THE SOFTWARE AND ACCOMPANYING - * DOCUMENTATION, IF ANY, PROVIDED HEREUNDER IS PROVIDED "AS - * IS". REGENTS HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, - * UPDATES, ENHANCEMENTS, OR MODIFICATIONS. - */ -package com.ibm.wala.demandpa.flowgraph; - -import com.ibm.wala.classLoader.IField; - -public class PutFieldLabel implements IFlowLabel { - - private final IField field; - - private PutFieldLabel(final IField field) { - this.field = field; - } - - public static PutFieldLabel make(IField field) { - // TODO cache these? - return new PutFieldLabel(field); - } - - public IField getField() { - return field; - } - - @Override - public int hashCode() { - final int PRIME = 31; - int result = 1; - result = PRIME * result + ((field == null) ? 0 : field.hashCode()); - return result; - } - - @Override - public boolean equals(Object obj) { - if (this == obj) - return true; - if (obj == null) - return false; - if (getClass() != obj.getClass()) - return false; - final PutFieldLabel other = (PutFieldLabel) obj; - if (field == null) { - if (other.field != null) - return false; - } else if (!field.equals(other.field)) - return false; - return true; - } - - public void visit(IFlowLabelVisitor v, Object dst) throws IllegalArgumentException { - if (v == null) { - throw new IllegalArgumentException("v == null"); - } - v.visitPutField(this, dst); - } - - @Override - public String toString() { - return "putfield[" + field + "]"; - } - - public PutFieldBarLabel bar() { - return PutFieldBarLabel.make(field); - } - - public boolean isBarred() { - return false; - } - -} +/******************************************************************************* + * 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. + * + * This file is a derivative of code released by the University of + * California under the terms listed below. + * + * Refinement Analysis Tools is Copyright (c) 2007 The Regents of the + * University of California (Regents). Provided that this notice and + * the following two paragraphs are included in any distribution of + * Refinement Analysis Tools or its derivative work, Regents agrees + * not to assert any of Regents' copyright rights in Refinement + * Analysis Tools against recipient for recipient's reproduction, + * preparation of derivative works, public display, public + * performance, distribution or sublicensing of Refinement Analysis + * Tools and derivative works, in source code and object code form. + * This agreement not to assert does not confer, by implication, + * estoppel, or otherwise any license or rights in any intellectual + * property of Regents, including, but not limited to, any patents + * of Regents or Regents' employees. + * + * IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, + * INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, + * INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE + * AND ITS DOCUMENTATION, EVEN IF REGENTS HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE AND FURTHER DISCLAIMS ANY STATUTORY + * WARRANTY OF NON-INFRINGEMENT. THE SOFTWARE AND ACCOMPANYING + * DOCUMENTATION, IF ANY, PROVIDED HEREUNDER IS PROVIDED "AS + * IS". REGENTS HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, + * UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + */ +package com.ibm.wala.demandpa.flowgraph; + +import com.ibm.wala.classLoader.IField; + +public class PutFieldLabel implements IFlowLabel { + + private final IField field; + + private PutFieldLabel(final IField field) { + this.field = field; + } + + public static PutFieldLabel make(IField field) { + // TODO cache these? + return new PutFieldLabel(field); + } + + public IField getField() { + return field; + } + + @Override + public int hashCode() { + final int PRIME = 31; + int result = 1; + result = PRIME * result + ((field == null) ? 0 : field.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + final PutFieldLabel other = (PutFieldLabel) obj; + if (field == null) { + if (other.field != null) + return false; + } else if (!field.equals(other.field)) + return false; + return true; + } + + public void visit(IFlowLabelVisitor v, Object dst) throws IllegalArgumentException { + if (v == null) { + throw new IllegalArgumentException("v == null"); + } + v.visitPutField(this, dst); + } + + @Override + public String toString() { + return "putfield[" + field + "]"; + } + + public PutFieldBarLabel bar() { + return PutFieldBarLabel.make(field); + } + + public boolean isBarred() { + return false; + } + +} diff --git a/com.ibm.wala.core/src/com/ibm/wala/demandpa/flowgraph/ReturnBarLabel.java b/com.ibm.wala.core/src/com/ibm/wala/demandpa/flowgraph/ReturnBarLabel.java index 72b1d625d..04f17a178 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/demandpa/flowgraph/ReturnBarLabel.java +++ b/com.ibm.wala.core/src/com/ibm/wala/demandpa/flowgraph/ReturnBarLabel.java @@ -1,81 +1,81 @@ -/******************************************************************************* - * 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. - * - * This file is a derivative of code released by the University of - * California under the terms listed below. - * - * Refinement Analysis Tools is Copyright (c) 2007 The Regents of the - * University of California (Regents). Provided that this notice and - * the following two paragraphs are included in any distribution of - * Refinement Analysis Tools or its derivative work, Regents agrees - * not to assert any of Regents' copyright rights in Refinement - * Analysis Tools against recipient for recipient's reproduction, - * preparation of derivative works, public display, public - * performance, distribution or sublicensing of Refinement Analysis - * Tools and derivative works, in source code and object code form. - * This agreement not to assert does not confer, by implication, - * estoppel, or otherwise any license or rights in any intellectual - * property of Regents, including, but not limited to, any patents - * of Regents or Regents' employees. - * - * IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, - * INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, - * INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE - * AND ITS DOCUMENTATION, EVEN IF REGENTS HAS BEEN ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE AND FURTHER DISCLAIMS ANY STATUTORY - * WARRANTY OF NON-INFRINGEMENT. THE SOFTWARE AND ACCOMPANYING - * DOCUMENTATION, IF ANY, PROVIDED HEREUNDER IS PROVIDED "AS - * IS". REGENTS HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, - * UPDATES, ENHANCEMENTS, OR MODIFICATIONS. - */ -package com.ibm.wala.demandpa.flowgraph; - -import com.ibm.wala.ipa.callgraph.propagation.cfa.CallerSiteContext; - -/** - */ -public class ReturnBarLabel extends CallLabel { - - private ReturnBarLabel(CallerSiteContext callSite) { - super(callSite); - } - - public static ReturnBarLabel make(CallerSiteContext callSite) { - return new ReturnBarLabel(callSite); - } - - /* - * @see demandGraph.IFlowLabel#bar() - */ - public ReturnLabel bar() { - return ReturnLabel.make(callSite); - } - - /* - * @see demandGraph.IFlowLabel#visit(demandGraph.IFlowLabel.IFlowLabelVisitor, - * java.lang.Object) - */ - public void visit(IFlowLabelVisitor v, Object dst) throws IllegalArgumentException { - if (v == null) { - throw new IllegalArgumentException("v == null"); - } - v.visitReturnBar(this, dst); - } - - public boolean isBarred() { - return true; - } - - @Override - public String toString() { - return "returnBar[" + callSite + "]"; - } - -} +/******************************************************************************* + * 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. + * + * This file is a derivative of code released by the University of + * California under the terms listed below. + * + * Refinement Analysis Tools is Copyright (c) 2007 The Regents of the + * University of California (Regents). Provided that this notice and + * the following two paragraphs are included in any distribution of + * Refinement Analysis Tools or its derivative work, Regents agrees + * not to assert any of Regents' copyright rights in Refinement + * Analysis Tools against recipient for recipient's reproduction, + * preparation of derivative works, public display, public + * performance, distribution or sublicensing of Refinement Analysis + * Tools and derivative works, in source code and object code form. + * This agreement not to assert does not confer, by implication, + * estoppel, or otherwise any license or rights in any intellectual + * property of Regents, including, but not limited to, any patents + * of Regents or Regents' employees. + * + * IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, + * INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, + * INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE + * AND ITS DOCUMENTATION, EVEN IF REGENTS HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE AND FURTHER DISCLAIMS ANY STATUTORY + * WARRANTY OF NON-INFRINGEMENT. THE SOFTWARE AND ACCOMPANYING + * DOCUMENTATION, IF ANY, PROVIDED HEREUNDER IS PROVIDED "AS + * IS". REGENTS HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, + * UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + */ +package com.ibm.wala.demandpa.flowgraph; + +import com.ibm.wala.ipa.callgraph.propagation.cfa.CallerSiteContext; + +/** + */ +public class ReturnBarLabel extends CallLabel { + + private ReturnBarLabel(CallerSiteContext callSite) { + super(callSite); + } + + public static ReturnBarLabel make(CallerSiteContext callSite) { + return new ReturnBarLabel(callSite); + } + + /* + * @see demandGraph.IFlowLabel#bar() + */ + public ReturnLabel bar() { + return ReturnLabel.make(callSite); + } + + /* + * @see demandGraph.IFlowLabel#visit(demandGraph.IFlowLabel.IFlowLabelVisitor, + * java.lang.Object) + */ + public void visit(IFlowLabelVisitor v, Object dst) throws IllegalArgumentException { + if (v == null) { + throw new IllegalArgumentException("v == null"); + } + v.visitReturnBar(this, dst); + } + + public boolean isBarred() { + return true; + } + + @Override + public String toString() { + return "returnBar[" + callSite + "]"; + } + +} diff --git a/com.ibm.wala.core/src/com/ibm/wala/demandpa/flowgraph/ReturnLabel.java b/com.ibm.wala.core/src/com/ibm/wala/demandpa/flowgraph/ReturnLabel.java index 1254b3ffd..70ca370b9 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/demandpa/flowgraph/ReturnLabel.java +++ b/com.ibm.wala.core/src/com/ibm/wala/demandpa/flowgraph/ReturnLabel.java @@ -1,72 +1,72 @@ -/******************************************************************************* - * 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. - * - * This file is a derivative of code released by the University of - * California under the terms listed below. - * - * Refinement Analysis Tools is Copyright (c) 2007 The Regents of the - * University of California (Regents). Provided that this notice and - * the following two paragraphs are included in any distribution of - * Refinement Analysis Tools or its derivative work, Regents agrees - * not to assert any of Regents' copyright rights in Refinement - * Analysis Tools against recipient for recipient's reproduction, - * preparation of derivative works, public display, public - * performance, distribution or sublicensing of Refinement Analysis - * Tools and derivative works, in source code and object code form. - * This agreement not to assert does not confer, by implication, - * estoppel, or otherwise any license or rights in any intellectual - * property of Regents, including, but not limited to, any patents - * of Regents or Regents' employees. - * - * IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, - * INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, - * INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE - * AND ITS DOCUMENTATION, EVEN IF REGENTS HAS BEEN ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE AND FURTHER DISCLAIMS ANY STATUTORY - * WARRANTY OF NON-INFRINGEMENT. THE SOFTWARE AND ACCOMPANYING - * DOCUMENTATION, IF ANY, PROVIDED HEREUNDER IS PROVIDED "AS - * IS". REGENTS HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, - * UPDATES, ENHANCEMENTS, OR MODIFICATIONS. - */ -package com.ibm.wala.demandpa.flowgraph; - -import com.ibm.wala.ipa.callgraph.propagation.cfa.CallerSiteContext; - -public class ReturnLabel extends CallLabel { - - private ReturnLabel(CallerSiteContext callSite) { - super(callSite); - } - - public static ReturnLabel make(CallerSiteContext callSite) { - return new ReturnLabel(callSite); - } - - public void visit(IFlowLabelVisitor v, Object dst) throws IllegalArgumentException { - if (v == null) { - throw new IllegalArgumentException("v == null"); - } - v.visitReturn(this, dst); - } - - @Override - public String toString() { - return "return[" + callSite + "]"; - } - - public ReturnBarLabel bar() { - return ReturnBarLabel.make(callSite); - } - - public boolean isBarred() { - return false; - } - -} +/******************************************************************************* + * 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. + * + * This file is a derivative of code released by the University of + * California under the terms listed below. + * + * Refinement Analysis Tools is Copyright (c) 2007 The Regents of the + * University of California (Regents). Provided that this notice and + * the following two paragraphs are included in any distribution of + * Refinement Analysis Tools or its derivative work, Regents agrees + * not to assert any of Regents' copyright rights in Refinement + * Analysis Tools against recipient for recipient's reproduction, + * preparation of derivative works, public display, public + * performance, distribution or sublicensing of Refinement Analysis + * Tools and derivative works, in source code and object code form. + * This agreement not to assert does not confer, by implication, + * estoppel, or otherwise any license or rights in any intellectual + * property of Regents, including, but not limited to, any patents + * of Regents or Regents' employees. + * + * IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, + * INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, + * INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE + * AND ITS DOCUMENTATION, EVEN IF REGENTS HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE AND FURTHER DISCLAIMS ANY STATUTORY + * WARRANTY OF NON-INFRINGEMENT. THE SOFTWARE AND ACCOMPANYING + * DOCUMENTATION, IF ANY, PROVIDED HEREUNDER IS PROVIDED "AS + * IS". REGENTS HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, + * UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + */ +package com.ibm.wala.demandpa.flowgraph; + +import com.ibm.wala.ipa.callgraph.propagation.cfa.CallerSiteContext; + +public class ReturnLabel extends CallLabel { + + private ReturnLabel(CallerSiteContext callSite) { + super(callSite); + } + + public static ReturnLabel make(CallerSiteContext callSite) { + return new ReturnLabel(callSite); + } + + public void visit(IFlowLabelVisitor v, Object dst) throws IllegalArgumentException { + if (v == null) { + throw new IllegalArgumentException("v == null"); + } + v.visitReturn(this, dst); + } + + @Override + public String toString() { + return "return[" + callSite + "]"; + } + + public ReturnBarLabel bar() { + return ReturnBarLabel.make(callSite); + } + + public boolean isBarred() { + return false; + } + +} diff --git a/com.ibm.wala.core/src/com/ibm/wala/demandpa/flowgraph/SimpleDemandPointerFlowGraph.java b/com.ibm.wala.core/src/com/ibm/wala/demandpa/flowgraph/SimpleDemandPointerFlowGraph.java index b39806ec4..21b246dea 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/demandpa/flowgraph/SimpleDemandPointerFlowGraph.java +++ b/com.ibm.wala.core/src/com/ibm/wala/demandpa/flowgraph/SimpleDemandPointerFlowGraph.java @@ -1,1317 +1,1317 @@ -/******************************************************************************* - * Copyright (c) 2007 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.demandpa.flowgraph; - -import java.util.Collection; -import java.util.Collections; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.Set; - -import com.ibm.wala.analysis.typeInference.TypeAbstraction; -import com.ibm.wala.analysis.typeInference.TypeInference; -import com.ibm.wala.cfg.ControlFlowGraph; -import com.ibm.wala.cfg.IBasicBlock; -import com.ibm.wala.classLoader.CallSiteReference; -import com.ibm.wala.classLoader.IClass; -import com.ibm.wala.classLoader.IField; -import com.ibm.wala.classLoader.ProgramCounter; -import com.ibm.wala.demandpa.util.MemoryAccess; -import com.ibm.wala.demandpa.util.MemoryAccessMap; -import com.ibm.wala.ipa.callgraph.CGNode; -import com.ibm.wala.ipa.callgraph.CallGraph; -import com.ibm.wala.ipa.callgraph.impl.ExplicitCallGraph; -import com.ibm.wala.ipa.callgraph.propagation.ConcreteTypeKey; -import com.ibm.wala.ipa.callgraph.propagation.FilteredPointerKey; -import com.ibm.wala.ipa.callgraph.propagation.HeapModel; -import com.ibm.wala.ipa.callgraph.propagation.InstanceKey; -import com.ibm.wala.ipa.callgraph.propagation.LocalPointerKey; -import com.ibm.wala.ipa.callgraph.propagation.PointerKey; -import com.ibm.wala.ipa.callgraph.propagation.PropagationCallGraphBuilder; -import com.ibm.wala.ipa.callgraph.propagation.SSAPropagationCallGraphBuilder; -import com.ibm.wala.ipa.callgraph.propagation.StaticFieldKey; -import com.ibm.wala.ipa.cha.IClassHierarchy; -import com.ibm.wala.ssa.DefUse; -import com.ibm.wala.ssa.IR; -import com.ibm.wala.ssa.ISSABasicBlock; -import com.ibm.wala.ssa.SSAAbstractInvokeInstruction; -import com.ibm.wala.ssa.SSAAbstractThrowInstruction; -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.SSALoadMetadataInstruction; -import com.ibm.wala.ssa.SSANewInstruction; -import com.ibm.wala.ssa.SSAPhiInstruction; -import com.ibm.wala.ssa.SSAPiInstruction; -import com.ibm.wala.ssa.SSAPutInstruction; -import com.ibm.wala.ssa.SSAReturnInstruction; -import com.ibm.wala.ssa.SSAThrowInstruction; -import com.ibm.wala.ssa.SymbolTable; -import com.ibm.wala.types.FieldReference; -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.UnimplementedError; -import com.ibm.wala.util.graph.impl.SlowSparseNumberedGraph; -import com.ibm.wala.util.intset.BitVectorIntSet; -import com.ibm.wala.util.intset.IntSet; -import com.ibm.wala.util.ref.ReferenceCleanser; - -/** - * The nodes in this graph are PointerKeys corresponding to local variables and static fields, InstanceKeys, and FieldRefs (see - * below). - * - * This graph is constructed on-demand during a traversal. - * - * The edges represent - *
          - *
        • flow from local -> local representing assignment (i.e. phi,pi) - *
        • flow from instancekey -> local for news - *
        • flow from formal -> actual parameter - *
        • flow from return value -> local - *
        • match edges - *
        • local -> local edges representing loads/stores (e.g. x = y.f will have a edge x->y, labelled with f) for a getstatic x = Y.f, - * we have an edge from x -> Y.f. - *
        - * - * N.B: Edges go OPPOSITE the flow of values. - * - * Edges carry labels if they arise from loads/stores, or calls - */ -public class SimpleDemandPointerFlowGraph extends SlowSparseNumberedGraph { - - private final static boolean DEBUG = false; - - /** - * Counter for wiping soft caches - */ - private static int wipeCount = 0; - - private final CallGraph cg; - - private final HeapModel heapModel; - - private final MemoryAccessMap fam; - - private final IClassHierarchy cha; - - /** - * node numbers of CGNodes we have already visited - */ - final BitVectorIntSet cgNodesVisited = new BitVectorIntSet(); - - /** - * Map: LocalPointerKey -> IField. if we have (x,f), that means x was def'fed by a getfield on f. - */ - final Map getFieldDefs = HashMapFactory.make(); - - final Collection arrayDefs = HashSetFactory.make(); - - /** - * Map: LocalPointerKey -> SSAInvokeInstruction. If we have (x, foo()), that means that x was def'fed by the return value from a - * call to foo() - */ - final Map callDefs = HashMapFactory.make(); - - /** - * Map: LocalPointerKey -> CGNode. If we have (x, foo), then x is a parameter of method foo. For now, we have to re-discover the - * parameter position. - */ - final Map params = HashMapFactory.make(); - - public SimpleDemandPointerFlowGraph(CallGraph cg, HeapModel heapModel, MemoryAccessMap fam, IClassHierarchy cha) { - super(); - if (cg == null) { - throw new IllegalArgumentException("null cg"); - } - this.cg = cg; - this.heapModel = heapModel; - this.fam = fam; - this.cha = cha; - } - - public void addSubgraphForNode(CGNode node) { - int n = cg.getNumber(node); - if (!cgNodesVisited.contains(n)) { - cgNodesVisited.add(n); - unconditionallyAddConstraintsFromNode(node); - addNodesForParameters(node); - } - } - - /** - * add nodes for parameters and return values - * - * @param node - */ - private void addNodesForParameters(CGNode node) { - // TODO Auto-generated method stub - IR ir = node.getIR(); - TypeInference ti = TypeInference.make(ir, false); - SymbolTable symbolTable = ir.getSymbolTable(); - for (int i = 0; i < symbolTable.getNumberOfParameters(); i++) { - int parameter = symbolTable.getParameter(i); - TypeAbstraction t = ti.getType(parameter); - if (t != null) { - PointerKey paramPk = heapModel.getPointerKeyForLocal(node, parameter); - addNode(paramPk); - params.put(paramPk, node); - } - } - addNode(heapModel.getPointerKeyForReturnValue(node)); - addNode(heapModel.getPointerKeyForExceptionalReturnValue(node)); - } - - /** - * @return Returns the heapModel. - */ - protected HeapModel getHeapModel() { - return heapModel; - } - - /* - * @see com.ibm.capa.util.graph.AbstractNumberedGraph#getPredNodeNumbers(java.lang.Object) - */ - @Override - public IntSet getPredNodeNumbers(Object node) throws UnimplementedError { - if (node instanceof StaticFieldKey) { - Assertions.UNREACHABLE(); - return null; - } else { - return super.getPredNodeNumbers(node); - } - } - - /* - * @see com.ibm.capa.util.graph.AbstractNumberedGraph#getSuccNodeNumbers(java.lang.Object) - */ - @Override - public IntSet getSuccNodeNumbers(Object node) throws IllegalArgumentException { - if (node instanceof com.ibm.wala.ipa.callgraph.propagation.StaticFieldKey) { - throw new IllegalArgumentException("node instanceof com.ibm.wala.ipa.callgraph.propagation.StaticFieldKey"); - } - return super.getSuccNodeNumbers(node); - } - - /* - * @see com.ibm.capa.util.graph.AbstractGraph#getPredNodeCount(java.lang.Object) - */ - @Override - public int getPredNodeCount(Object N) throws UnimplementedError { - if (N instanceof StaticFieldKey) { - Assertions.UNREACHABLE(); - return -1; - } else { - return super.getPredNodeCount(N); - } - } - - /* - * @see com.ibm.capa.util.graph.AbstractGraph#getPredNodes(java.lang.Object) - */ - @Override - public Iterator getPredNodes(Object N) throws IllegalArgumentException { - if (N instanceof com.ibm.wala.ipa.callgraph.propagation.StaticFieldKey) { - throw new IllegalArgumentException("N instanceof com.ibm.wala.ipa.callgraph.propagation.StaticFieldKey"); - } - return super.getPredNodes(N); - } - - /* - * @see com.ibm.capa.util.graph.AbstractGraph#getSuccNodeCount(java.lang.Object) - */ - @Override - public int getSuccNodeCount(Object N) throws UnimplementedError { - if (N instanceof StaticFieldKey) { - Assertions.UNREACHABLE(); - return -1; - } else { - return super.getSuccNodeCount(N); - } - } - - /* - * @see com.ibm.capa.util.graph.AbstractGraph#getSuccNodes(java.lang.Object) - */ - @Override - public Iterator getSuccNodes(Object N) { - if (N instanceof StaticFieldKey) { - addNodesThatWriteToStaticField(((StaticFieldKey) N).getField()); - } else { - IField f = getFieldDefs.get(N); - if (f != null) { - addMatchEdges((LocalPointerKey) N, f); - } else { - SSAInvokeInstruction callInstr = callDefs.get(N); - if (callInstr != null) { - addReturnEdges((LocalPointerKey) N, callInstr); - } else { - CGNode node = params.get(N); - if (node != null) { - addParamEdges((LocalPointerKey) N, node); - } else { - if (arrayDefs.contains(N)) { - addArrayMatchEdges((LocalPointerKey) N); - } - } - } - } - } - return super.getSuccNodes(N); - } - - private void addArrayMatchEdges(LocalPointerKey pk) { - Collection arrayWrites = fam.getArrayWrites(null); - for (MemoryAccess a : arrayWrites) { - addSubgraphForNode(a.getNode()); - } - for (MemoryAccess a : arrayWrites) { - IR ir = a.getNode().getIR(); - SSAArrayStoreInstruction s = (SSAArrayStoreInstruction) ir.getInstructions()[a.getInstructionIndex()]; - PointerKey r = heapModel.getPointerKeyForLocal(a.getNode(), s.getValue()); - assert containsNode(r); - assert containsNode(pk); - addMatchEdge(pk, r); - } - } - - private void addParamEdges(LocalPointerKey pk, CGNode node) { - // get parameter position: value number - 1? - int paramPos = pk.getValueNumber() - 1; - // iterate over callers - for (CGNode caller : cg) { - // TODO we don't need to add the graph if null is passed - // as the argument - addSubgraphForNode(caller); - IR ir = caller.getIR(); - for (Iterator iterator = ir.iterateCallSites(); iterator.hasNext();) { - CallSiteReference call = iterator.next(); - if (cg.getPossibleTargets(caller, call).contains(node)) { - SSAAbstractInvokeInstruction[] callInstrs = ir.getCalls(call); - for (int i = 0; i < callInstrs.length; i++) { - SSAAbstractInvokeInstruction callInstr = callInstrs[i]; - PointerKey actualPk = heapModel.getPointerKeyForLocal(caller, callInstr.getUse(paramPos)); - assert containsNode(actualPk); - assert containsNode(pk); - addEdge(pk, actualPk); - - } - } - } - } - } - - /** - * @param pk value being def'fed by a call instruction (either normal or exceptional) - */ - private void addReturnEdges(LocalPointerKey pk, SSAInvokeInstruction callInstr) { - boolean isExceptional = pk.getValueNumber() == callInstr.getException(); - - // get call targets - Collection possibleCallees = cg.getPossibleTargets(pk.getNode(), callInstr.getCallSite()); - // construct graph for each target - for (CGNode callee : possibleCallees) { - addSubgraphForNode(callee); - PointerKey retVal = isExceptional ? heapModel.getPointerKeyForExceptionalReturnValue(callee) : heapModel - .getPointerKeyForReturnValue(callee); - assert containsNode(retVal); - addEdge(pk, retVal); - } - } - - private void addMatchEdges(LocalPointerKey pk, IField f) { - Collection fieldWrites = fam.getFieldWrites(null, f); - addMatchHelper(pk, fieldWrites); - } - - private void addMatchHelper(LocalPointerKey pk, Collection writes) { - for (MemoryAccess a : writes) { - addSubgraphForNode(a.getNode()); - } - for (MemoryAccess a : writes) { - IR ir = a.getNode().getIR(); - SSAPutInstruction s = (SSAPutInstruction) ir.getInstructions()[a.getInstructionIndex()]; - PointerKey r = heapModel.getPointerKeyForLocal(a.getNode(), s.getVal()); - assert containsNode(r); - assert containsNode(pk); - addMatchEdge(pk, r); - } - } - - private void addMatchEdge(LocalPointerKey pk, PointerKey r) { - addEdge(pk, r); - } - - private void addNodesThatWriteToStaticField(IField field) { - Collection fieldWrites = fam.getStaticFieldWrites(field); - for (MemoryAccess a : fieldWrites) { - addSubgraphForNode(a.getNode()); - } - } - - /* - * (non-Javadoc) - * - * @see com.ibm.capa.util.graph.AbstractGraph#hasEdge(java.lang.Object, java.lang.Object) - */ - public boolean hasEdge(PointerKey src, PointerKey dst) { - // TODO Auto-generated method stub - return super.hasEdge(src, dst); - } - - protected void unconditionallyAddConstraintsFromNode(CGNode node) { - - if (DEBUG) { - System.err.println(("Visiting CGNode " + node)); - } - - if (SSAPropagationCallGraphBuilder.PERIODIC_WIPE_SOFT_CACHES) { - wipeCount++; - if (wipeCount >= SSAPropagationCallGraphBuilder.WIPE_SOFT_CACHE_INTERVAL) { - wipeCount = 0; - ReferenceCleanser.clearSoftCaches(); - } - } - - IR ir = node.getIR(); - debugPrintIR(ir); - - if (ir == null) { - return; - } - - DefUse du = node.getDU(); - addNodeInstructionConstraints(node, ir, du); - addNodePassthruExceptionConstraints(node, ir); - } - - /** - * Add constraints to represent the flow of exceptions to the exceptional return value for this node - */ - protected void addNodePassthruExceptionConstraints(CGNode node, IR ir) { - // add constraints relating to thrown exceptions that reach the exit block. - List peis = SSAPropagationCallGraphBuilder.getIncomingPEIs(ir, ir.getExitBlock()); - PointerKey exception = heapModel.getPointerKeyForExceptionalReturnValue(node); - IClass c = node.getClassHierarchy().lookupClass(TypeReference.JavaLangThrowable); - - addExceptionDefConstraints(ir, node, peis, exception, Collections.singleton(c)); - } - - /** - * Generate constraints which assign exception values into an exception pointer - * - * @param node governing node - * @param peis list of PEI instructions - * @param exceptionVar PointerKey representing a pointer to an exception value - * @param catchClasses the types "caught" by the exceptionVar - */ - private void addExceptionDefConstraints(IR ir, CGNode node, List peis, PointerKey exceptionVar, - Set catchClasses) { - for (ProgramCounter peiLoc : peis) { - SSAInstruction pei = ir.getPEI(peiLoc); - - if (pei instanceof SSAAbstractInvokeInstruction) { - SSAAbstractInvokeInstruction s = (SSAAbstractInvokeInstruction) pei; - PointerKey e = heapModel.getPointerKeyForLocal(node, s.getException()); - addNode(exceptionVar); - addNode(e); - addEdge(exceptionVar, e); - - } else if (pei instanceof SSAAbstractThrowInstruction) { - SSAAbstractThrowInstruction s = (SSAAbstractThrowInstruction) pei; - PointerKey e = heapModel.getPointerKeyForLocal(node, s.getException()); - addNode(exceptionVar); - addNode(e); - addEdge(exceptionVar, e); - } - - // Account for those exceptions for which we do not actually have a - // points-to set for - // the pei, but just instance keys - Collection types = pei.getExceptionTypes(); - if (types != null) { - for (TypeReference type : types) { - if (type != null) { - InstanceKey ik = heapModel.getInstanceKeyForPEI(node, peiLoc, type); - assert ik instanceof ConcreteTypeKey : "uh oh: need to implement getCaughtException constraints for instance " + ik; - ConcreteTypeKey ck = (ConcreteTypeKey) ik; - IClass klass = ck.getType(); - if (PropagationCallGraphBuilder.catches(catchClasses, klass, cha)) { - addNode(exceptionVar); - addNode(ik); - addEdge(exceptionVar, ik); - } - } - } - } - } - } - - /** - * Add pointer flow constraints based on instructions in a given node - */ - protected void addNodeInstructionConstraints(CGNode node, IR ir, DefUse du) { - StatementVisitor v = makeVisitor((ExplicitCallGraph.ExplicitNode) node, ir, du); - ControlFlowGraph cfg = ir.getControlFlowGraph(); - for (ISSABasicBlock b : cfg) { - addBlockInstructionConstraints(node, cfg, b, v); - } - } - - /** - * Add constraints for a particular basic block. - */ - protected void addBlockInstructionConstraints(CGNode node, ControlFlowGraph cfg, - ISSABasicBlock b, StatementVisitor v) { - v.setBasicBlock(b); - - // visit each instruction in the basic block. - for (Iterator it = b.iterator(); it.hasNext();) { - SSAInstruction s = it.next(); - if (s != null) { - s.visit(v); - } - } - - addPhiConstraints(node, cfg, b); - } - - private void addPhiConstraints(CGNode node, ControlFlowGraph cfg, ISSABasicBlock b) { - - // visit each phi instruction in each successor block - for (Iterator sbs = cfg.getSuccNodes(b); sbs.hasNext();) { - ISSABasicBlock sb = (ISSABasicBlock) sbs.next(); - if (sb.isExitBlock()) { - // an optimization based on invariant that exit blocks should have no - // phis. - continue; - } - int n = 0; - // set n to be whichPred(this, sb); - for (Iterator back = cfg.getPredNodes(sb); back.hasNext(); n++) { - if (back.next() == b) { - break; - } - } - assert n < cfg.getPredNodeCount(sb); - for (Iterator phis = sb.iteratePhis(); phis.hasNext();) { - SSAPhiInstruction phi = phis.next(); - if (phi == null) { - continue; - } - PointerKey def = heapModel.getPointerKeyForLocal(node, phi.getDef()); - if (phi.getUse(n) > 0) { - PointerKey use = heapModel.getPointerKeyForLocal(node, phi.getUse(n)); - addNode(def); - addNode(use); - addEdge(def, use); - } - // } - // } - } - } - } - - protected StatementVisitor makeVisitor(ExplicitCallGraph.ExplicitNode node, IR ir, DefUse du) { - return new StatementVisitor(node, ir, du); - } - - private void debugPrintIR(IR ir) { - if (DEBUG) { - if (ir == null) { - System.err.println("\n No statements\n"); - } else { - try { - System.err.println(ir.toString()); - } catch (Error e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - } - } - } - - /** - * A visitor that generates graph nodes and edges for an IR. - * - * strategy: when visiting a statement, for each use of that statement, add a graph edge from def to use. - * - * TODO: special treatment for parameter passing, etc. - */ - protected class StatementVisitor extends SSAInstruction.Visitor { - - /** - * The node whose statements we are currently traversing - */ - protected final CGNode node; - - /** - * The governing IR - */ - protected final IR ir; - - /** - * The basic block currently being processed - */ - private ISSABasicBlock basicBlock; - - /** - * Governing symbol table - */ - protected final SymbolTable symbolTable; - - /** - * Def-use information - */ - protected final DefUse du; - - public StatementVisitor(CGNode node, IR ir, DefUse du) { - this.node = node; - this.ir = ir; - this.symbolTable = ir.getSymbolTable(); - assert symbolTable != null; - this.du = du; - } - - /* - * (non-Javadoc) - * - * @see com.ibm.domo.ssa.SSAInstruction.Visitor#visitArrayLoad(com.ibm.domo.ssa.SSAArrayLoadInstruction) - */ - @Override - public void visitArrayLoad(SSAArrayLoadInstruction instruction) { - // skip arrays of primitive type - if (instruction.typeIsPrimitive()) { - return; - } - PointerKey result = heapModel.getPointerKeyForLocal(node, instruction.getDef()); - arrayDefs.add(result); - // PointerKey arrayRef = getPointerKeyForLocal(node, - // instruction.getArrayRef()); - // if (hasNoInterestingUses(instruction.getDef(), du)) { - // system.recordImplicitPointsToSet(result); - // } else { - // if (contentsAreInvariant(symbolTable, du, instruction.getArrayRef())) { - // system.recordImplicitPointsToSet(arrayRef); - // InstanceKey[] ik = getInvariantContents(symbolTable, du, node, - // instruction.getArrayRef(), - // SSAPropagationCallGraphBuilder.this); - // for (int i = 0; i < ik.length; i++) { - // system.findOrCreateIndexForInstanceKey(ik[i]); - // PointerKey p = getPointerKeyForArrayContents(ik[i]); - // if (p == null) { - // getWarnings().add(ResolutionFailure.create(node, - // ik[i].getConcreteType())); - // } else { - // system.newConstraint(result, assignOperator, p); - // } - // } - // } else { - // if (Assertions.verifyAssertions) { - // Assertions._assert(!system.isUnified(result)); - // Assertions._assert(!system.isUnified(arrayRef)); - // } - // system.newSideEffect(new - // ArrayLoadOperator(system.findOrCreatePointsToSet(result)), arrayRef); - // } - // } - } - - /* - * (non-Javadoc) - * - * @see com.ibm.domo.ssa.SSAInstruction.Visitor#visitArrayStore(com.ibm.domo.ssa.SSAArrayStoreInstruction) - */ - @Override - public void visitArrayStore(SSAArrayStoreInstruction instruction) { - // Assertions.UNREACHABLE(); - // skip arrays of primitive type - if (instruction.typeIsPrimitive()) { - return; - } - // make node for used value - PointerKey value = heapModel.getPointerKeyForLocal(node, instruction.getValue()); - addNode(value); - // - // // (requires the creation of assign constraints as - // // the set points-to(a[]) grows.) - // PointerKey arrayRef = getPointerKeyForLocal(node, - // instruction.getArrayRef()); - // // if (!supportFullPointerFlowGraph && - // // contentsAreInvariant(instruction.getArrayRef())) { - // if (contentsAreInvariant(symbolTable, du, instruction.getArrayRef())) { - // system.recordImplicitPointsToSet(arrayRef); - // InstanceKey[] ik = getInvariantContents(symbolTable, du, node, - // instruction.getArrayRef(), - // SSAPropagationCallGraphBuilder.this); - // - // for (int i = 0; i < ik.length; i++) { - // system.findOrCreateIndexForInstanceKey(ik[i]); - // PointerKey p = getPointerKeyForArrayContents(ik[i]); - // IClass contents = ((ArrayClass) - // ik[i].getConcreteType()).getElementClass(); - // if (p == null) { - // getWarnings().add(ResolutionFailure.create(node, - // ik[i].getConcreteType())); - // } else { - // if (DEBUG_TRACK_INSTANCE) { - // if (system.findOrCreateIndexForInstanceKey(ik[i]) == - // DEBUG_INSTANCE_KEY) { - // Assertions.UNREACHABLE(); - // } - // } - // if (contentsAreInvariant(symbolTable, du, instruction.getValue())) { - // system.recordImplicitPointsToSet(value); - // InstanceKey[] vk = getInvariantContents(symbolTable, du, node, - // instruction.getValue(), - // SSAPropagationCallGraphBuilder.this); - // for (int j = 0; j < vk.length; j++) { - // system.findOrCreateIndexForInstanceKey(vk[j]); - // if (vk[j].getConcreteType() != null) { - // if (contents.isInterface()) { - // if (getClassHierarchy().implementsInterface(vk[j].getConcreteType(), - // contents.getReference())) { - // system.newConstraint(p, vk[j]); - // } - // } else { - // if (getClassHierarchy().isSubclassOf(vk[j].getConcreteType(), - // contents)) { - // system.newConstraint(p, vk[j]); - // } - // } - // } - // } - // } else { - // if (isRootType(contents)) { - // system.newConstraint(p, assignOperator, value); - // } else { - // system.newConstraint(p, filterOperator, value); - // } - // } - // } - // } - // } else { - // if (contentsAreInvariant(symbolTable, du, instruction.getValue())) { - // system.recordImplicitPointsToSet(value); - // InstanceKey[] ik = getInvariantContents(symbolTable, du, node, - // instruction.getValue(), - // SSAPropagationCallGraphBuilder.this); - // for (int i = 0; i < ik.length; i++) { - // system.findOrCreateIndexForInstanceKey(ik[i]); - // if (Assertions.verifyAssertions) { - // Assertions._assert(!system.isUnified(arrayRef)); - // } - // system.newSideEffect(new InstanceArrayStoreOperator(ik[i]), arrayRef); - // } - // } else { - // system.newSideEffect(new - // ArrayStoreOperator(system.findOrCreatePointsToSet(value)), arrayRef); - // } - // } - } - - /* - * (non-Javadoc) - * - * @see com.ibm.domo.ssa.SSAInstruction.Visitor#visitCheckCast(com.ibm.domo.ssa.SSACheckCastInstruction) - */ - @Override - public void visitCheckCast(SSACheckCastInstruction instruction) { - Set types = HashSetFactory.make(); - - for(TypeReference t : instruction.getDeclaredResultTypes()) { - IClass cls = cha.lookupClass(t); - if (cls == null) { - return; - } else { - types.add(cls); - } - } - - - PointerKey result = heapModel.getFilteredPointerKeyForLocal(node, - instruction.getResult(), - new FilteredPointerKey.MultipleClassesFilter(types.toArray(new IClass[ types.size() ])) ); - - PointerKey value = heapModel.getPointerKeyForLocal(node, instruction.getVal()); - // TODO actually use the cast type - addNode(result); - addNode(value); - addEdge(result, value); - // - // if (hasNoInterestingUses(instruction.getDef(), du)) { - // system.recordImplicitPointsToSet(result); - // } else { - // if (contentsAreInvariant(symbolTable, du, instruction.getVal())) { - // system.recordImplicitPointsToSet(value); - // InstanceKey[] ik = getInvariantContents(symbolTable, du, node, - // instruction.getVal(), SSAPropagationCallGraphBuilder.this); - // if (cls.isInterface()) { - // for (int i = 0; i < ik.length; i++) { - // system.findOrCreateIndexForInstanceKey(ik[i]); - // if (getClassHierarchy().implementsInterface(ik[i].getConcreteType(), - // cls.getReference())) { - // system.newConstraint(result, ik[i]); - // } - // } - // } else { - // for (int i = 0; i < ik.length; i++) { - // system.findOrCreateIndexForInstanceKey(ik[i]); - // if (getClassHierarchy().isSubclassOf(ik[i].getConcreteType(), cls)) { - // system.newConstraint(result, ik[i]); - // } - // } - // } - // } else { - // if (cls == null) { - // getWarnings().add(ResolutionFailure.create(node, - // instruction.getDeclaredResultType())); - // cls = getJavaLangObject(); - // } - // if (isRootType(cls)) { - // system.newConstraint(result, assignOperator, value); - // } else { - // system.newConstraint(result, filterOperator, value); - // } - // } - // } - } - - /* - * (non-Javadoc) - * - * @see com.ibm.domo.ssa.SSAInstruction.Visitor#visitReturn(com.ibm.domo.ssa.SSAReturnInstruction) - */ - @Override - public void visitReturn(SSAReturnInstruction instruction) { - // skip returns of primitive type - if (instruction.returnsPrimitiveType() || instruction.returnsVoid()) { - return; - } else { - // just make a node for the def'd value - PointerKey def = heapModel.getPointerKeyForLocal(node, instruction.getResult()); - addNode(def); - PointerKey returnValue = heapModel.getPointerKeyForReturnValue(node); - addNode(returnValue); - addEdge(returnValue, def); - } - // PointerKey returnValue = getPointerKeyForReturnValue(node); - // PointerKey result = getPointerKeyForLocal(node, - // instruction.getResult()); - // // if (!supportFullPointerFlowGraph && - // // contentsAreInvariant(instruction.getResult())) { - // if (contentsAreInvariant(symbolTable, du, instruction.getResult())) { - // system.recordImplicitPointsToSet(result); - // InstanceKey[] ik = getInvariantContents(symbolTable, du, node, - // instruction.getResult(), SSAPropagationCallGraphBuilder.this); - // for (int i = 0; i < ik.length; i++) { - // system.newConstraint(returnValue, ik[i]); - // } - // } else { - // system.newConstraint(returnValue, assignOperator, result); - // } - } - - /* - * (non-Javadoc) - * - * @see com.ibm.domo.ssa.SSAInstruction.Visitor#visitGet(com.ibm.domo.ssa.SSAGetInstruction) - */ - @Override - public void visitGet(SSAGetInstruction instruction) { - visitGetInternal(instruction.getDef(), instruction.isStatic(), instruction.getDeclaredField()); - } - - protected void visitGetInternal(int lval, boolean isStatic, FieldReference field) { - - // skip getfields of primitive type (optimisation) - if (field.getFieldType().isPrimitiveType()) { - return; - } - IField f = cg.getClassHierarchy().resolveField(field); - if (f == null) { - return; - } - PointerKey def = heapModel.getPointerKeyForLocal(node, lval); - assert def != null; - - if (isStatic) { - PointerKey fKey = heapModel.getPointerKeyForStaticField(f); - addNode(def); - addNode(fKey); - addEdge(def, fKey); - } else { - addNode(def); - getFieldDefs.put(def, f); - } - // system.newConstraint(def, assignOperator, fKey); - // IClass klass = getClassHierarchy().lookupClass(field.getType()); - // if (klass == null) { - // getWarnings().add(ResolutionFailure.create(node, field.getType())); - // } else { - // // side effect of getstatic: may call class initializer - // if (DEBUG) { - // Trace.guardedPrintln("getstatic call class init " + klass, - // DEBUG_METHOD_SUBSTRING); - // } - - // - // if (hasNoInterestingUses(lval, du)) { - // system.recordImplicitPointsToSet(def); - // } else { - // if (isStatic) { - // PointerKey fKey = getPointerKeyForStaticField(f); - // system.newConstraint(def, assignOperator, fKey); - // IClass klass = getClassHierarchy().lookupClass(field.getType()); - // if (klass == null) { - // getWarnings().add(ResolutionFailure.create(node, field.getType())); - // } else { - // // side effect of getstatic: may call class initializer - // if (DEBUG) { - // Trace.guardedPrintln("getstatic call class init " + klass, - // DEBUG_METHOD_SUBSTRING); - // } - // processClassInitializer(klass); - // } - // } else { - // PointerKey refKey = getPointerKeyForLocal(node, ref); - // // if (!supportFullPointerFlowGraph && - // // contentsAreInvariant(ref)) { - // if (contentsAreInvariant(symbolTable, du, ref)) { - // system.recordImplicitPointsToSet(refKey); - // InstanceKey[] ik = getInvariantContents(symbolTable, du, node, ref, - // SSAPropagationCallGraphBuilder.this); - // for (int i = 0; i < ik.length; i++) { - // system.findOrCreateIndexForInstanceKey(ik[i]); - // PointerKey p = getPointerKeyForInstanceField(ik[i], f); - // system.newConstraint(def, assignOperator, p); - // } - // } else { - // system.newSideEffect(new GetFieldOperator(f, - // system.findOrCreatePointsToSet(def)), refKey); - // } - // } - // } - } - - /* - * (non-Javadoc) - * - * @see com.ibm.domo.ssa.Instruction.Visitor#visitPut(com.ibm.domo.ssa.PutInstruction) - */ - @Override - public void visitPut(SSAPutInstruction instruction) { - visitPutInternal(instruction.getVal(), instruction.isStatic(), instruction.getDeclaredField()); - } - - public void visitPutInternal(int rval, boolean isStatic, FieldReference field) { - // skip putfields of primitive type (optimisation) - if (field.getFieldType().isPrimitiveType()) { - return; - } - IField f = cg.getClassHierarchy().resolveField(field); - if (f == null) { - return; - } - PointerKey use = heapModel.getPointerKeyForLocal(node, rval); - assert use != null; - - if (isStatic) { - PointerKey fKey = heapModel.getPointerKeyForStaticField(f); - addNode(use); - addNode(fKey); - addEdge(fKey, use); - } else { - addNode(use); - } - } - - /* - * @see com.ibm.domo.ssa.Instruction.Visitor#visitInvoke(com.ibm.domo.ssa.InvokeInstruction) - */ - @Override - public void visitInvoke(SSAInvokeInstruction instruction) { - - for (int i = 0; i < instruction.getNumberOfUses(); i++) { - // just make nodes for parameters; we'll get to them when traversing - // from the callee - PointerKey use = heapModel.getPointerKeyForLocal(node, instruction.getUse(i)); - addNode(use); - } - - // for any def'd values, keep track of the fact that they are def'd - // by a call - if (instruction.hasDef()) { - PointerKey def = heapModel.getPointerKeyForLocal(node, instruction.getDef()); - addNode(def); - callDefs.put(def, instruction); - } - PointerKey exc = heapModel.getPointerKeyForLocal(node, instruction.getException()); - addNode(exc); - callDefs.put(exc, instruction); - // TODO handle exceptions - // if (DEBUG && debug) { - // Trace.println("visitInvoke: " + instruction); - // } - // - // PointerKey uniqueCatch = null; - // if (hasUniqueCatchBlock(instruction, ir)) { - // uniqueCatch = getUniqueCatchKey(instruction, ir, node); - // } - // - // if (instruction.getCallSite().isStatic()) { - // CGNode n = getTargetForCall(node, instruction.getCallSite(), - // (InstanceKey) null); - // if (n == null) { - // getWarnings().add(ResolutionFailure.create(node, instruction)); - // } else { - // processResolvedCall(node, instruction, n, - // computeInvariantParameters(instruction), uniqueCatch); - // if (DEBUG) { - // Trace.guardedPrintln("visitInvoke class init " + n, - // DEBUG_METHOD_SUBSTRING); - // } - // - // // side effect of invoke: may call class initializer - // processClassInitializer(n.getMethod().getDeclaringClass()); - // } - // } else { - // // Add a side effect that will fire when we determine a value - // // for the receiver. This side effect will create a new node - // // and new constraints based on the new callee context. - // // NOTE: This will not be adequate for CPA-style context selectors, - // // where the callee context may depend on state other than the - // // receiver. TODO: rectify this when needed. - // PointerKey receiver = getPointerKeyForLocal(node, - // instruction.getReceiver()); - // // if (!supportFullPointerFlowGraph && - // // contentsAreInvariant(instruction.getReceiver())) { - // if (contentsAreInvariant(symbolTable, du, instruction.getReceiver())) { - // system.recordImplicitPointsToSet(receiver); - // InstanceKey[] ik = getInvariantContents(symbolTable, du, node, - // instruction.getReceiver(), - // SSAPropagationCallGraphBuilder.this); - // for (int i = 0; i < ik.length; i++) { - // system.findOrCreateIndexForInstanceKey(ik[i]); - // CGNode n = getTargetForCall(node, instruction.getCallSite(), ik[i]); - // if (n == null) { - // getWarnings().add(ResolutionFailure.create(node, instruction)); - // } else { - // processResolvedCall(node, instruction, n, - // computeInvariantParameters(instruction), uniqueCatch); - // // side effect of invoke: may call class initializer - // processClassInitializer(n.getMethod().getDeclaringClass()); - // } - // } - // } else { - // if (DEBUG && debug) { - // Trace.println("Add side effect, dispatch to " + instruction + ", - // receiver " + receiver); - // } - // DispatchOperator dispatchOperator = new DispatchOperator(instruction, - // node, computeInvariantParameters(instruction), - // uniqueCatch); - // system.newSideEffect(dispatchOperator, receiver); - // } - // } - } - - /* - * (non-Javadoc) - * - * @see com.ibm.domo.ssa.Instruction.Visitor#visitNew(com.ibm.domo.ssa.NewInstruction) - */ - @Override - public void visitNew(SSANewInstruction instruction) { - - InstanceKey iKey = heapModel.getInstanceKeyForAllocation(node, instruction.getNewSite()); - if (iKey == null) { - // something went wrong. I hope someone raised a warning. - return; - } - PointerKey def = heapModel.getPointerKeyForLocal(node, instruction.getDef()); - addNode(iKey); - addNode(def); - addEdge(def, iKey); - // IClass klass = iKey.getConcreteType(); - // - // if (DEBUG && debug) { - // Trace.println("visitNew: " + instruction + " " + iKey + " " + - // system.findOrCreateIndexForInstanceKey(iKey)); - // } - // - // if (klass == null) { - // getWarnings().add(ResolutionFailure.create(node, - // instruction.getConcreteType())); - // return; - // } - // - // if (!contentsAreInvariant(symbolTable, du, instruction.getDef())) { - // system.newConstraint(def, iKey); - // } else { - // system.findOrCreateIndexForInstanceKey(iKey); - // system.recordImplicitPointsToSet(def); - // } - // - // // side effect of new: may call class initializer - // if (DEBUG) { - // Trace.guardedPrintln("visitNew call clinit: " + klass, - // DEBUG_METHOD_SUBSTRING); - // } - // processClassInitializer(klass); - // - // // add instance keys and pointer keys for array contents - // int dim = 0; - // InstanceKey lastInstance = iKey; - // while (klass != null && klass.isArrayClass()) { - // klass = ((ArrayClass) klass).getElementClass(); - // // klass == null means it's a primitive - // if (klass != null && klass.isArrayClass()) { - // InstanceKey ik = getInstanceKeyForMultiNewArray(node, - // instruction.getNewSite(), dim); - // PointerKey pk = getPointerKeyForArrayContents(lastInstance); - // if (DEBUG_MULTINEWARRAY) { - // Trace.println("multinewarray constraint: "); - // Trace.println(" pk: " + pk); - // Trace.println(" ik: " + system.findOrCreateIndexForInstanceKey(ik) + " - // concrete type " + ik.getConcreteType() - // + " is " + ik); - // Trace.println(" klass:" + klass); - // } - // system.newConstraint(pk, ik); - // lastInstance = ik; - // dim++; - // } - // } - } - - /* - * (non-Javadoc) - * - * @see com.ibm.domo.ssa.Instruction.Visitor#visitThrow(com.ibm.domo.ssa.ThrowInstruction) - */ - @Override - public void visitThrow(SSAThrowInstruction instruction) { - // Assertions.UNREACHABLE(); - // don't do anything: we handle exceptional edges - // in a separate pass - } - - /* - * (non-Javadoc) - * - * @see com.ibm.domo.ssa.Instruction.Visitor#visitGetCaughtException(com.ibm.domo.ssa.GetCaughtExceptionInstruction) - */ - @Override - public void visitGetCaughtException(SSAGetCaughtExceptionInstruction instruction) { - List peis = SSAPropagationCallGraphBuilder.getIncomingPEIs(ir, getBasicBlock()); - PointerKey def = heapModel.getPointerKeyForLocal(node, instruction.getDef()); - - Set types = SSAPropagationCallGraphBuilder.getCaughtExceptionTypes(instruction, ir); - addExceptionDefConstraints(ir, node, peis, def, types); - } - - // private int booleanConstantTest(SSAConditionalBranchInstruction c, int v) - // { - // int result = 0; - // - // // right for OPR_eq - // if ((symbolTable.isZero(c.getUse(0)) && c.getUse(1) == v) || - // (symbolTable.isZero(c.getUse(1)) && c.getUse(0) == v)) { - // result = -1; - // } else if ((symbolTable.isOne(c.getUse(0)) && c.getUse(1) == v) || - // (symbolTable.isOne(c.getUse(1)) && c.getUse(0) == v)) { - // result = 1; - // } - // - // if (c.getOperator() == Constants.OPR_ne) { - // result = -result; - // } - // - // return result; - // } - // - // private int nullConstantTest(SSAConditionalBranchInstruction c, int v) { - // if ((symbolTable.isNullConstant(c.getUse(0)) && c.getUse(1) == v) - // || (symbolTable.isNullConstant(c.getUse(1)) && c.getUse(0) == v)) { - // if (c.getOperator() == Constants.OPR_eq) { - // return 1; - // } else { - // return -1; - // } - // } else { - // return 0; - // } - // } - - /* - * (non-Javadoc) - * - * @see com.ibm.domo.ssa.SSAInstruction.Visitor#visitPi(com.ibm.domo.ssa.SSAPiInstruction) - */ - @Override - public void visitPi(SSAPiInstruction instruction) { - Assertions.UNREACHABLE(); - // int dir; - // ControlFlowGraph CFG = ir.getControlFlowGraph(); - // PointerKey src = getPointerKeyForLocal(node, instruction.getVal()); - // if (hasNoInterestingUses(instruction.getDef(), du)) { - // PointerKey dst = getPointerKeyForLocal(node, instruction.getDef()); - // system.recordImplicitPointsToSet(dst); - // } else { - // if (com.ibm.domo.cfg.Util.endsWithConditionalBranch(CFG, - // getBasicBlock()) && CFG.getSuccNodeCount(getBasicBlock()) == 2) { - // SSAConditionalBranchInstruction cond = - // com.ibm.domo.cfg.Util.getConditionalBranch(CFG, getBasicBlock()); - // SSAInstruction cause = instruction.getCause(); - // BasicBlock target = (BasicBlock) - // CFG.getNode(instruction.getSuccessor()); - // if ((cause instanceof SSAInstanceofInstruction) && ((dir = - // booleanConstantTest(cond, cause.getDef())) != 0)) { - // TypeReference type = ((SSAInstanceofInstruction) - // cause).getCheckedType(); - // IClass cls = cha.lookupClass(type); - // if (cls == null) { - // getWarnings().add(ResolutionFailure.create(node, type)); - // PointerKey dst = getPointerKeyForLocal(node, instruction.getDef()); - // system.newConstraint(dst, assignOperator, src); - // } else { - // PointerKey dst = getFilteredPointerKeyForLocal(node, - // instruction.getDef(), cls); - // if ((target == com.ibm.domo.cfg.Util.getTrueSuccessor(CFG, - // getBasicBlock()) && dir == 1) - // || (target == com.ibm.domo.cfg.Util.getFalseSuccessor(CFG, - // getBasicBlock()) && dir == -1)) { - // system.newConstraint(dst, filterOperator, src); - // // System.err.println("PI " + dst + " " + src); - // } else { - // system.newConstraint(dst, inverseFilterOperator, src); - // } - // } - // } else if ((dir = nullConstantTest(cond, instruction.getVal())) != 0) { - // if ((target == com.ibm.domo.cfg.Util.getTrueSuccessor(CFG, - // getBasicBlock()) && dir == -1) - // || (target == com.ibm.domo.cfg.Util.getFalseSuccessor(CFG, - // getBasicBlock()) && dir == 1)) { - // PointerKey dst = getPointerKeyForLocal(node, instruction.getDef()); - // system.newConstraint(dst, assignOperator, src); - // } - // } else { - // PointerKey dst = getPointerKeyForLocal(node, instruction.getDef()); - // system.newConstraint(dst, assignOperator, src); - // } - // } else { - // PointerKey dst = getPointerKeyForLocal(node, instruction.getDef()); - // system.newConstraint(dst, assignOperator, src); - // } - // } - } - - public ISSABasicBlock getBasicBlock() { - return basicBlock; - } - - /** - * The calling loop must call this in each iteration! - */ - public void setBasicBlock(ISSABasicBlock block) { - basicBlock = block; - } - - // /** - // * Side effect: records invariant parameters as implicit points-to-sets. - // * - // * @return if non-null, then result[i] holds the set of instance keys - // which - // * may be passed as the ith parameter. (which must be invariant) - // */ - // protected InstanceKey[][] - // computeInvariantParameters(SSAAbstractInvokeInstruction call) { - // InstanceKey[][] constParams = null; - // for (int i = 0; i < call.getNumberOfUses(); i++) { - // // not sure how getUse(i) <= 0 .. dead code? - // // TODO: investigate - // if (call.getUse(i) > 0) { - // if (contentsAreInvariant(symbolTable, du, call.getUse(i))) { - // system.recordImplicitPointsToSet(getPointerKeyForLocal(node, - // call.getUse(i))); - // if (constParams == null) { - // constParams = new InstanceKey[call.getNumberOfUses()][]; - // } - // constParams[i] = getInvariantContents(symbolTable, du, node, - // call.getUse(i), SSAPropagationCallGraphBuilder.this); - // for (int j = 0; j < constParams[i].length; j++) { - // system.findOrCreateIndexForInstanceKey(constParams[i][j]); - // } - // } - // } - // } - // return constParams; - // } - - @Override - public void visitLoadMetadata(SSALoadMetadataInstruction instruction) { - Assertions.UNREACHABLE(); - // PointerKey def = getPointerKeyForLocal(node, instruction.getDef()); - // InstanceKey iKey = - // getInstanceKeyForClassObject(instruction.getLoadedClass()); - // - // if (!contentsAreInvariant(symbolTable, du, instruction.getDef())) { - // system.newConstraint(def, iKey); - // } else { - // system.findOrCreateIndexForInstanceKey(iKey); - // system.recordImplicitPointsToSet(def); - // } - } - } - - // private final class FieldExpression { - // LocalPointerKey x; - // - // IField f; - // - // public FieldExpression(IField f, LocalPointerKey x) { - // this.f = f; - // this.x = x; - // } - // - // /* - // * (non-Javadoc) - // * - // * @see java.lang.Object#equals(java.lang.Object) - // */ - // public boolean equals(Object obj) { - // if (obj instanceof FieldExpression) { - // FieldExpression other = (FieldExpression) obj; - // return x.equals(other.x) && f.equals(other.f); - // } else { - // return false; - // } - // } - // - // /* - // * (non-Javadoc) - // * - // * @see java.lang.Object#hashCode() - // */ - // public int hashCode() { - // return x.hashCode() + 4729 * f.hashCode(); - // } - // } - +/******************************************************************************* + * Copyright (c) 2007 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.demandpa.flowgraph; + +import java.util.Collection; +import java.util.Collections; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import com.ibm.wala.analysis.typeInference.TypeAbstraction; +import com.ibm.wala.analysis.typeInference.TypeInference; +import com.ibm.wala.cfg.ControlFlowGraph; +import com.ibm.wala.cfg.IBasicBlock; +import com.ibm.wala.classLoader.CallSiteReference; +import com.ibm.wala.classLoader.IClass; +import com.ibm.wala.classLoader.IField; +import com.ibm.wala.classLoader.ProgramCounter; +import com.ibm.wala.demandpa.util.MemoryAccess; +import com.ibm.wala.demandpa.util.MemoryAccessMap; +import com.ibm.wala.ipa.callgraph.CGNode; +import com.ibm.wala.ipa.callgraph.CallGraph; +import com.ibm.wala.ipa.callgraph.impl.ExplicitCallGraph; +import com.ibm.wala.ipa.callgraph.propagation.ConcreteTypeKey; +import com.ibm.wala.ipa.callgraph.propagation.FilteredPointerKey; +import com.ibm.wala.ipa.callgraph.propagation.HeapModel; +import com.ibm.wala.ipa.callgraph.propagation.InstanceKey; +import com.ibm.wala.ipa.callgraph.propagation.LocalPointerKey; +import com.ibm.wala.ipa.callgraph.propagation.PointerKey; +import com.ibm.wala.ipa.callgraph.propagation.PropagationCallGraphBuilder; +import com.ibm.wala.ipa.callgraph.propagation.SSAPropagationCallGraphBuilder; +import com.ibm.wala.ipa.callgraph.propagation.StaticFieldKey; +import com.ibm.wala.ipa.cha.IClassHierarchy; +import com.ibm.wala.ssa.DefUse; +import com.ibm.wala.ssa.IR; +import com.ibm.wala.ssa.ISSABasicBlock; +import com.ibm.wala.ssa.SSAAbstractInvokeInstruction; +import com.ibm.wala.ssa.SSAAbstractThrowInstruction; +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.SSALoadMetadataInstruction; +import com.ibm.wala.ssa.SSANewInstruction; +import com.ibm.wala.ssa.SSAPhiInstruction; +import com.ibm.wala.ssa.SSAPiInstruction; +import com.ibm.wala.ssa.SSAPutInstruction; +import com.ibm.wala.ssa.SSAReturnInstruction; +import com.ibm.wala.ssa.SSAThrowInstruction; +import com.ibm.wala.ssa.SymbolTable; +import com.ibm.wala.types.FieldReference; +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.UnimplementedError; +import com.ibm.wala.util.graph.impl.SlowSparseNumberedGraph; +import com.ibm.wala.util.intset.BitVectorIntSet; +import com.ibm.wala.util.intset.IntSet; +import com.ibm.wala.util.ref.ReferenceCleanser; + +/** + * The nodes in this graph are PointerKeys corresponding to local variables and static fields, InstanceKeys, and FieldRefs (see + * below). + * + * This graph is constructed on-demand during a traversal. + * + * The edges represent + *
          + *
        • flow from local -> local representing assignment (i.e. phi,pi) + *
        • flow from instancekey -> local for news + *
        • flow from formal -> actual parameter + *
        • flow from return value -> local + *
        • match edges + *
        • local -> local edges representing loads/stores (e.g. x = y.f will have a edge x->y, labelled with f) for a getstatic x = Y.f, + * we have an edge from x -> Y.f. + *
        + * + * N.B: Edges go OPPOSITE the flow of values. + * + * Edges carry labels if they arise from loads/stores, or calls + */ +public class SimpleDemandPointerFlowGraph extends SlowSparseNumberedGraph { + + private final static boolean DEBUG = false; + + /** + * Counter for wiping soft caches + */ + private static int wipeCount = 0; + + private final CallGraph cg; + + private final HeapModel heapModel; + + private final MemoryAccessMap fam; + + private final IClassHierarchy cha; + + /** + * node numbers of CGNodes we have already visited + */ + final BitVectorIntSet cgNodesVisited = new BitVectorIntSet(); + + /** + * Map: LocalPointerKey -> IField. if we have (x,f), that means x was def'fed by a getfield on f. + */ + final Map getFieldDefs = HashMapFactory.make(); + + final Collection arrayDefs = HashSetFactory.make(); + + /** + * Map: LocalPointerKey -> SSAInvokeInstruction. If we have (x, foo()), that means that x was def'fed by the return value from a + * call to foo() + */ + final Map callDefs = HashMapFactory.make(); + + /** + * Map: LocalPointerKey -> CGNode. If we have (x, foo), then x is a parameter of method foo. For now, we have to re-discover the + * parameter position. + */ + final Map params = HashMapFactory.make(); + + public SimpleDemandPointerFlowGraph(CallGraph cg, HeapModel heapModel, MemoryAccessMap fam, IClassHierarchy cha) { + super(); + if (cg == null) { + throw new IllegalArgumentException("null cg"); + } + this.cg = cg; + this.heapModel = heapModel; + this.fam = fam; + this.cha = cha; + } + + public void addSubgraphForNode(CGNode node) { + int n = cg.getNumber(node); + if (!cgNodesVisited.contains(n)) { + cgNodesVisited.add(n); + unconditionallyAddConstraintsFromNode(node); + addNodesForParameters(node); + } + } + + /** + * add nodes for parameters and return values + * + * @param node + */ + private void addNodesForParameters(CGNode node) { + // TODO Auto-generated method stub + IR ir = node.getIR(); + TypeInference ti = TypeInference.make(ir, false); + SymbolTable symbolTable = ir.getSymbolTable(); + for (int i = 0; i < symbolTable.getNumberOfParameters(); i++) { + int parameter = symbolTable.getParameter(i); + TypeAbstraction t = ti.getType(parameter); + if (t != null) { + PointerKey paramPk = heapModel.getPointerKeyForLocal(node, parameter); + addNode(paramPk); + params.put(paramPk, node); + } + } + addNode(heapModel.getPointerKeyForReturnValue(node)); + addNode(heapModel.getPointerKeyForExceptionalReturnValue(node)); + } + + /** + * @return Returns the heapModel. + */ + protected HeapModel getHeapModel() { + return heapModel; + } + + /* + * @see com.ibm.capa.util.graph.AbstractNumberedGraph#getPredNodeNumbers(java.lang.Object) + */ + @Override + public IntSet getPredNodeNumbers(Object node) throws UnimplementedError { + if (node instanceof StaticFieldKey) { + Assertions.UNREACHABLE(); + return null; + } else { + return super.getPredNodeNumbers(node); + } + } + + /* + * @see com.ibm.capa.util.graph.AbstractNumberedGraph#getSuccNodeNumbers(java.lang.Object) + */ + @Override + public IntSet getSuccNodeNumbers(Object node) throws IllegalArgumentException { + if (node instanceof com.ibm.wala.ipa.callgraph.propagation.StaticFieldKey) { + throw new IllegalArgumentException("node instanceof com.ibm.wala.ipa.callgraph.propagation.StaticFieldKey"); + } + return super.getSuccNodeNumbers(node); + } + + /* + * @see com.ibm.capa.util.graph.AbstractGraph#getPredNodeCount(java.lang.Object) + */ + @Override + public int getPredNodeCount(Object N) throws UnimplementedError { + if (N instanceof StaticFieldKey) { + Assertions.UNREACHABLE(); + return -1; + } else { + return super.getPredNodeCount(N); + } + } + + /* + * @see com.ibm.capa.util.graph.AbstractGraph#getPredNodes(java.lang.Object) + */ + @Override + public Iterator getPredNodes(Object N) throws IllegalArgumentException { + if (N instanceof com.ibm.wala.ipa.callgraph.propagation.StaticFieldKey) { + throw new IllegalArgumentException("N instanceof com.ibm.wala.ipa.callgraph.propagation.StaticFieldKey"); + } + return super.getPredNodes(N); + } + + /* + * @see com.ibm.capa.util.graph.AbstractGraph#getSuccNodeCount(java.lang.Object) + */ + @Override + public int getSuccNodeCount(Object N) throws UnimplementedError { + if (N instanceof StaticFieldKey) { + Assertions.UNREACHABLE(); + return -1; + } else { + return super.getSuccNodeCount(N); + } + } + + /* + * @see com.ibm.capa.util.graph.AbstractGraph#getSuccNodes(java.lang.Object) + */ + @Override + public Iterator getSuccNodes(Object N) { + if (N instanceof StaticFieldKey) { + addNodesThatWriteToStaticField(((StaticFieldKey) N).getField()); + } else { + IField f = getFieldDefs.get(N); + if (f != null) { + addMatchEdges((LocalPointerKey) N, f); + } else { + SSAInvokeInstruction callInstr = callDefs.get(N); + if (callInstr != null) { + addReturnEdges((LocalPointerKey) N, callInstr); + } else { + CGNode node = params.get(N); + if (node != null) { + addParamEdges((LocalPointerKey) N, node); + } else { + if (arrayDefs.contains(N)) { + addArrayMatchEdges((LocalPointerKey) N); + } + } + } + } + } + return super.getSuccNodes(N); + } + + private void addArrayMatchEdges(LocalPointerKey pk) { + Collection arrayWrites = fam.getArrayWrites(null); + for (MemoryAccess a : arrayWrites) { + addSubgraphForNode(a.getNode()); + } + for (MemoryAccess a : arrayWrites) { + IR ir = a.getNode().getIR(); + SSAArrayStoreInstruction s = (SSAArrayStoreInstruction) ir.getInstructions()[a.getInstructionIndex()]; + PointerKey r = heapModel.getPointerKeyForLocal(a.getNode(), s.getValue()); + assert containsNode(r); + assert containsNode(pk); + addMatchEdge(pk, r); + } + } + + private void addParamEdges(LocalPointerKey pk, CGNode node) { + // get parameter position: value number - 1? + int paramPos = pk.getValueNumber() - 1; + // iterate over callers + for (CGNode caller : cg) { + // TODO we don't need to add the graph if null is passed + // as the argument + addSubgraphForNode(caller); + IR ir = caller.getIR(); + for (Iterator iterator = ir.iterateCallSites(); iterator.hasNext();) { + CallSiteReference call = iterator.next(); + if (cg.getPossibleTargets(caller, call).contains(node)) { + SSAAbstractInvokeInstruction[] callInstrs = ir.getCalls(call); + for (int i = 0; i < callInstrs.length; i++) { + SSAAbstractInvokeInstruction callInstr = callInstrs[i]; + PointerKey actualPk = heapModel.getPointerKeyForLocal(caller, callInstr.getUse(paramPos)); + assert containsNode(actualPk); + assert containsNode(pk); + addEdge(pk, actualPk); + + } + } + } + } + } + + /** + * @param pk value being def'fed by a call instruction (either normal or exceptional) + */ + private void addReturnEdges(LocalPointerKey pk, SSAInvokeInstruction callInstr) { + boolean isExceptional = pk.getValueNumber() == callInstr.getException(); + + // get call targets + Collection possibleCallees = cg.getPossibleTargets(pk.getNode(), callInstr.getCallSite()); + // construct graph for each target + for (CGNode callee : possibleCallees) { + addSubgraphForNode(callee); + PointerKey retVal = isExceptional ? heapModel.getPointerKeyForExceptionalReturnValue(callee) : heapModel + .getPointerKeyForReturnValue(callee); + assert containsNode(retVal); + addEdge(pk, retVal); + } + } + + private void addMatchEdges(LocalPointerKey pk, IField f) { + Collection fieldWrites = fam.getFieldWrites(null, f); + addMatchHelper(pk, fieldWrites); + } + + private void addMatchHelper(LocalPointerKey pk, Collection writes) { + for (MemoryAccess a : writes) { + addSubgraphForNode(a.getNode()); + } + for (MemoryAccess a : writes) { + IR ir = a.getNode().getIR(); + SSAPutInstruction s = (SSAPutInstruction) ir.getInstructions()[a.getInstructionIndex()]; + PointerKey r = heapModel.getPointerKeyForLocal(a.getNode(), s.getVal()); + assert containsNode(r); + assert containsNode(pk); + addMatchEdge(pk, r); + } + } + + private void addMatchEdge(LocalPointerKey pk, PointerKey r) { + addEdge(pk, r); + } + + private void addNodesThatWriteToStaticField(IField field) { + Collection fieldWrites = fam.getStaticFieldWrites(field); + for (MemoryAccess a : fieldWrites) { + addSubgraphForNode(a.getNode()); + } + } + + /* + * (non-Javadoc) + * + * @see com.ibm.capa.util.graph.AbstractGraph#hasEdge(java.lang.Object, java.lang.Object) + */ + public boolean hasEdge(PointerKey src, PointerKey dst) { + // TODO Auto-generated method stub + return super.hasEdge(src, dst); + } + + protected void unconditionallyAddConstraintsFromNode(CGNode node) { + + if (DEBUG) { + System.err.println(("Visiting CGNode " + node)); + } + + if (SSAPropagationCallGraphBuilder.PERIODIC_WIPE_SOFT_CACHES) { + wipeCount++; + if (wipeCount >= SSAPropagationCallGraphBuilder.WIPE_SOFT_CACHE_INTERVAL) { + wipeCount = 0; + ReferenceCleanser.clearSoftCaches(); + } + } + + IR ir = node.getIR(); + debugPrintIR(ir); + + if (ir == null) { + return; + } + + DefUse du = node.getDU(); + addNodeInstructionConstraints(node, ir, du); + addNodePassthruExceptionConstraints(node, ir); + } + + /** + * Add constraints to represent the flow of exceptions to the exceptional return value for this node + */ + protected void addNodePassthruExceptionConstraints(CGNode node, IR ir) { + // add constraints relating to thrown exceptions that reach the exit block. + List peis = SSAPropagationCallGraphBuilder.getIncomingPEIs(ir, ir.getExitBlock()); + PointerKey exception = heapModel.getPointerKeyForExceptionalReturnValue(node); + IClass c = node.getClassHierarchy().lookupClass(TypeReference.JavaLangThrowable); + + addExceptionDefConstraints(ir, node, peis, exception, Collections.singleton(c)); + } + + /** + * Generate constraints which assign exception values into an exception pointer + * + * @param node governing node + * @param peis list of PEI instructions + * @param exceptionVar PointerKey representing a pointer to an exception value + * @param catchClasses the types "caught" by the exceptionVar + */ + private void addExceptionDefConstraints(IR ir, CGNode node, List peis, PointerKey exceptionVar, + Set catchClasses) { + for (ProgramCounter peiLoc : peis) { + SSAInstruction pei = ir.getPEI(peiLoc); + + if (pei instanceof SSAAbstractInvokeInstruction) { + SSAAbstractInvokeInstruction s = (SSAAbstractInvokeInstruction) pei; + PointerKey e = heapModel.getPointerKeyForLocal(node, s.getException()); + addNode(exceptionVar); + addNode(e); + addEdge(exceptionVar, e); + + } else if (pei instanceof SSAAbstractThrowInstruction) { + SSAAbstractThrowInstruction s = (SSAAbstractThrowInstruction) pei; + PointerKey e = heapModel.getPointerKeyForLocal(node, s.getException()); + addNode(exceptionVar); + addNode(e); + addEdge(exceptionVar, e); + } + + // Account for those exceptions for which we do not actually have a + // points-to set for + // the pei, but just instance keys + Collection types = pei.getExceptionTypes(); + if (types != null) { + for (TypeReference type : types) { + if (type != null) { + InstanceKey ik = heapModel.getInstanceKeyForPEI(node, peiLoc, type); + assert ik instanceof ConcreteTypeKey : "uh oh: need to implement getCaughtException constraints for instance " + ik; + ConcreteTypeKey ck = (ConcreteTypeKey) ik; + IClass klass = ck.getType(); + if (PropagationCallGraphBuilder.catches(catchClasses, klass, cha)) { + addNode(exceptionVar); + addNode(ik); + addEdge(exceptionVar, ik); + } + } + } + } + } + } + + /** + * Add pointer flow constraints based on instructions in a given node + */ + protected void addNodeInstructionConstraints(CGNode node, IR ir, DefUse du) { + StatementVisitor v = makeVisitor((ExplicitCallGraph.ExplicitNode) node, ir, du); + ControlFlowGraph cfg = ir.getControlFlowGraph(); + for (ISSABasicBlock b : cfg) { + addBlockInstructionConstraints(node, cfg, b, v); + } + } + + /** + * Add constraints for a particular basic block. + */ + protected void addBlockInstructionConstraints(CGNode node, ControlFlowGraph cfg, + ISSABasicBlock b, StatementVisitor v) { + v.setBasicBlock(b); + + // visit each instruction in the basic block. + for (Iterator it = b.iterator(); it.hasNext();) { + SSAInstruction s = it.next(); + if (s != null) { + s.visit(v); + } + } + + addPhiConstraints(node, cfg, b); + } + + private void addPhiConstraints(CGNode node, ControlFlowGraph cfg, ISSABasicBlock b) { + + // visit each phi instruction in each successor block + for (Iterator sbs = cfg.getSuccNodes(b); sbs.hasNext();) { + ISSABasicBlock sb = (ISSABasicBlock) sbs.next(); + if (sb.isExitBlock()) { + // an optimization based on invariant that exit blocks should have no + // phis. + continue; + } + int n = 0; + // set n to be whichPred(this, sb); + for (Iterator back = cfg.getPredNodes(sb); back.hasNext(); n++) { + if (back.next() == b) { + break; + } + } + assert n < cfg.getPredNodeCount(sb); + for (Iterator phis = sb.iteratePhis(); phis.hasNext();) { + SSAPhiInstruction phi = phis.next(); + if (phi == null) { + continue; + } + PointerKey def = heapModel.getPointerKeyForLocal(node, phi.getDef()); + if (phi.getUse(n) > 0) { + PointerKey use = heapModel.getPointerKeyForLocal(node, phi.getUse(n)); + addNode(def); + addNode(use); + addEdge(def, use); + } + // } + // } + } + } + } + + protected StatementVisitor makeVisitor(ExplicitCallGraph.ExplicitNode node, IR ir, DefUse du) { + return new StatementVisitor(node, ir, du); + } + + private void debugPrintIR(IR ir) { + if (DEBUG) { + if (ir == null) { + System.err.println("\n No statements\n"); + } else { + try { + System.err.println(ir.toString()); + } catch (Error e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } + } + } + + /** + * A visitor that generates graph nodes and edges for an IR. + * + * strategy: when visiting a statement, for each use of that statement, add a graph edge from def to use. + * + * TODO: special treatment for parameter passing, etc. + */ + protected class StatementVisitor extends SSAInstruction.Visitor { + + /** + * The node whose statements we are currently traversing + */ + protected final CGNode node; + + /** + * The governing IR + */ + protected final IR ir; + + /** + * The basic block currently being processed + */ + private ISSABasicBlock basicBlock; + + /** + * Governing symbol table + */ + protected final SymbolTable symbolTable; + + /** + * Def-use information + */ + protected final DefUse du; + + public StatementVisitor(CGNode node, IR ir, DefUse du) { + this.node = node; + this.ir = ir; + this.symbolTable = ir.getSymbolTable(); + assert symbolTable != null; + this.du = du; + } + + /* + * (non-Javadoc) + * + * @see com.ibm.domo.ssa.SSAInstruction.Visitor#visitArrayLoad(com.ibm.domo.ssa.SSAArrayLoadInstruction) + */ + @Override + public void visitArrayLoad(SSAArrayLoadInstruction instruction) { + // skip arrays of primitive type + if (instruction.typeIsPrimitive()) { + return; + } + PointerKey result = heapModel.getPointerKeyForLocal(node, instruction.getDef()); + arrayDefs.add(result); + // PointerKey arrayRef = getPointerKeyForLocal(node, + // instruction.getArrayRef()); + // if (hasNoInterestingUses(instruction.getDef(), du)) { + // system.recordImplicitPointsToSet(result); + // } else { + // if (contentsAreInvariant(symbolTable, du, instruction.getArrayRef())) { + // system.recordImplicitPointsToSet(arrayRef); + // InstanceKey[] ik = getInvariantContents(symbolTable, du, node, + // instruction.getArrayRef(), + // SSAPropagationCallGraphBuilder.this); + // for (int i = 0; i < ik.length; i++) { + // system.findOrCreateIndexForInstanceKey(ik[i]); + // PointerKey p = getPointerKeyForArrayContents(ik[i]); + // if (p == null) { + // getWarnings().add(ResolutionFailure.create(node, + // ik[i].getConcreteType())); + // } else { + // system.newConstraint(result, assignOperator, p); + // } + // } + // } else { + // if (Assertions.verifyAssertions) { + // Assertions._assert(!system.isUnified(result)); + // Assertions._assert(!system.isUnified(arrayRef)); + // } + // system.newSideEffect(new + // ArrayLoadOperator(system.findOrCreatePointsToSet(result)), arrayRef); + // } + // } + } + + /* + * (non-Javadoc) + * + * @see com.ibm.domo.ssa.SSAInstruction.Visitor#visitArrayStore(com.ibm.domo.ssa.SSAArrayStoreInstruction) + */ + @Override + public void visitArrayStore(SSAArrayStoreInstruction instruction) { + // Assertions.UNREACHABLE(); + // skip arrays of primitive type + if (instruction.typeIsPrimitive()) { + return; + } + // make node for used value + PointerKey value = heapModel.getPointerKeyForLocal(node, instruction.getValue()); + addNode(value); + // + // // (requires the creation of assign constraints as + // // the set points-to(a[]) grows.) + // PointerKey arrayRef = getPointerKeyForLocal(node, + // instruction.getArrayRef()); + // // if (!supportFullPointerFlowGraph && + // // contentsAreInvariant(instruction.getArrayRef())) { + // if (contentsAreInvariant(symbolTable, du, instruction.getArrayRef())) { + // system.recordImplicitPointsToSet(arrayRef); + // InstanceKey[] ik = getInvariantContents(symbolTable, du, node, + // instruction.getArrayRef(), + // SSAPropagationCallGraphBuilder.this); + // + // for (int i = 0; i < ik.length; i++) { + // system.findOrCreateIndexForInstanceKey(ik[i]); + // PointerKey p = getPointerKeyForArrayContents(ik[i]); + // IClass contents = ((ArrayClass) + // ik[i].getConcreteType()).getElementClass(); + // if (p == null) { + // getWarnings().add(ResolutionFailure.create(node, + // ik[i].getConcreteType())); + // } else { + // if (DEBUG_TRACK_INSTANCE) { + // if (system.findOrCreateIndexForInstanceKey(ik[i]) == + // DEBUG_INSTANCE_KEY) { + // Assertions.UNREACHABLE(); + // } + // } + // if (contentsAreInvariant(symbolTable, du, instruction.getValue())) { + // system.recordImplicitPointsToSet(value); + // InstanceKey[] vk = getInvariantContents(symbolTable, du, node, + // instruction.getValue(), + // SSAPropagationCallGraphBuilder.this); + // for (int j = 0; j < vk.length; j++) { + // system.findOrCreateIndexForInstanceKey(vk[j]); + // if (vk[j].getConcreteType() != null) { + // if (contents.isInterface()) { + // if (getClassHierarchy().implementsInterface(vk[j].getConcreteType(), + // contents.getReference())) { + // system.newConstraint(p, vk[j]); + // } + // } else { + // if (getClassHierarchy().isSubclassOf(vk[j].getConcreteType(), + // contents)) { + // system.newConstraint(p, vk[j]); + // } + // } + // } + // } + // } else { + // if (isRootType(contents)) { + // system.newConstraint(p, assignOperator, value); + // } else { + // system.newConstraint(p, filterOperator, value); + // } + // } + // } + // } + // } else { + // if (contentsAreInvariant(symbolTable, du, instruction.getValue())) { + // system.recordImplicitPointsToSet(value); + // InstanceKey[] ik = getInvariantContents(symbolTable, du, node, + // instruction.getValue(), + // SSAPropagationCallGraphBuilder.this); + // for (int i = 0; i < ik.length; i++) { + // system.findOrCreateIndexForInstanceKey(ik[i]); + // if (Assertions.verifyAssertions) { + // Assertions._assert(!system.isUnified(arrayRef)); + // } + // system.newSideEffect(new InstanceArrayStoreOperator(ik[i]), arrayRef); + // } + // } else { + // system.newSideEffect(new + // ArrayStoreOperator(system.findOrCreatePointsToSet(value)), arrayRef); + // } + // } + } + + /* + * (non-Javadoc) + * + * @see com.ibm.domo.ssa.SSAInstruction.Visitor#visitCheckCast(com.ibm.domo.ssa.SSACheckCastInstruction) + */ + @Override + public void visitCheckCast(SSACheckCastInstruction instruction) { + Set types = HashSetFactory.make(); + + for(TypeReference t : instruction.getDeclaredResultTypes()) { + IClass cls = cha.lookupClass(t); + if (cls == null) { + return; + } else { + types.add(cls); + } + } + + + PointerKey result = heapModel.getFilteredPointerKeyForLocal(node, + instruction.getResult(), + new FilteredPointerKey.MultipleClassesFilter(types.toArray(new IClass[ types.size() ])) ); + + PointerKey value = heapModel.getPointerKeyForLocal(node, instruction.getVal()); + // TODO actually use the cast type + addNode(result); + addNode(value); + addEdge(result, value); + // + // if (hasNoInterestingUses(instruction.getDef(), du)) { + // system.recordImplicitPointsToSet(result); + // } else { + // if (contentsAreInvariant(symbolTable, du, instruction.getVal())) { + // system.recordImplicitPointsToSet(value); + // InstanceKey[] ik = getInvariantContents(symbolTable, du, node, + // instruction.getVal(), SSAPropagationCallGraphBuilder.this); + // if (cls.isInterface()) { + // for (int i = 0; i < ik.length; i++) { + // system.findOrCreateIndexForInstanceKey(ik[i]); + // if (getClassHierarchy().implementsInterface(ik[i].getConcreteType(), + // cls.getReference())) { + // system.newConstraint(result, ik[i]); + // } + // } + // } else { + // for (int i = 0; i < ik.length; i++) { + // system.findOrCreateIndexForInstanceKey(ik[i]); + // if (getClassHierarchy().isSubclassOf(ik[i].getConcreteType(), cls)) { + // system.newConstraint(result, ik[i]); + // } + // } + // } + // } else { + // if (cls == null) { + // getWarnings().add(ResolutionFailure.create(node, + // instruction.getDeclaredResultType())); + // cls = getJavaLangObject(); + // } + // if (isRootType(cls)) { + // system.newConstraint(result, assignOperator, value); + // } else { + // system.newConstraint(result, filterOperator, value); + // } + // } + // } + } + + /* + * (non-Javadoc) + * + * @see com.ibm.domo.ssa.SSAInstruction.Visitor#visitReturn(com.ibm.domo.ssa.SSAReturnInstruction) + */ + @Override + public void visitReturn(SSAReturnInstruction instruction) { + // skip returns of primitive type + if (instruction.returnsPrimitiveType() || instruction.returnsVoid()) { + return; + } else { + // just make a node for the def'd value + PointerKey def = heapModel.getPointerKeyForLocal(node, instruction.getResult()); + addNode(def); + PointerKey returnValue = heapModel.getPointerKeyForReturnValue(node); + addNode(returnValue); + addEdge(returnValue, def); + } + // PointerKey returnValue = getPointerKeyForReturnValue(node); + // PointerKey result = getPointerKeyForLocal(node, + // instruction.getResult()); + // // if (!supportFullPointerFlowGraph && + // // contentsAreInvariant(instruction.getResult())) { + // if (contentsAreInvariant(symbolTable, du, instruction.getResult())) { + // system.recordImplicitPointsToSet(result); + // InstanceKey[] ik = getInvariantContents(symbolTable, du, node, + // instruction.getResult(), SSAPropagationCallGraphBuilder.this); + // for (int i = 0; i < ik.length; i++) { + // system.newConstraint(returnValue, ik[i]); + // } + // } else { + // system.newConstraint(returnValue, assignOperator, result); + // } + } + + /* + * (non-Javadoc) + * + * @see com.ibm.domo.ssa.SSAInstruction.Visitor#visitGet(com.ibm.domo.ssa.SSAGetInstruction) + */ + @Override + public void visitGet(SSAGetInstruction instruction) { + visitGetInternal(instruction.getDef(), instruction.isStatic(), instruction.getDeclaredField()); + } + + protected void visitGetInternal(int lval, boolean isStatic, FieldReference field) { + + // skip getfields of primitive type (optimisation) + if (field.getFieldType().isPrimitiveType()) { + return; + } + IField f = cg.getClassHierarchy().resolveField(field); + if (f == null) { + return; + } + PointerKey def = heapModel.getPointerKeyForLocal(node, lval); + assert def != null; + + if (isStatic) { + PointerKey fKey = heapModel.getPointerKeyForStaticField(f); + addNode(def); + addNode(fKey); + addEdge(def, fKey); + } else { + addNode(def); + getFieldDefs.put(def, f); + } + // system.newConstraint(def, assignOperator, fKey); + // IClass klass = getClassHierarchy().lookupClass(field.getType()); + // if (klass == null) { + // getWarnings().add(ResolutionFailure.create(node, field.getType())); + // } else { + // // side effect of getstatic: may call class initializer + // if (DEBUG) { + // Trace.guardedPrintln("getstatic call class init " + klass, + // DEBUG_METHOD_SUBSTRING); + // } + + // + // if (hasNoInterestingUses(lval, du)) { + // system.recordImplicitPointsToSet(def); + // } else { + // if (isStatic) { + // PointerKey fKey = getPointerKeyForStaticField(f); + // system.newConstraint(def, assignOperator, fKey); + // IClass klass = getClassHierarchy().lookupClass(field.getType()); + // if (klass == null) { + // getWarnings().add(ResolutionFailure.create(node, field.getType())); + // } else { + // // side effect of getstatic: may call class initializer + // if (DEBUG) { + // Trace.guardedPrintln("getstatic call class init " + klass, + // DEBUG_METHOD_SUBSTRING); + // } + // processClassInitializer(klass); + // } + // } else { + // PointerKey refKey = getPointerKeyForLocal(node, ref); + // // if (!supportFullPointerFlowGraph && + // // contentsAreInvariant(ref)) { + // if (contentsAreInvariant(symbolTable, du, ref)) { + // system.recordImplicitPointsToSet(refKey); + // InstanceKey[] ik = getInvariantContents(symbolTable, du, node, ref, + // SSAPropagationCallGraphBuilder.this); + // for (int i = 0; i < ik.length; i++) { + // system.findOrCreateIndexForInstanceKey(ik[i]); + // PointerKey p = getPointerKeyForInstanceField(ik[i], f); + // system.newConstraint(def, assignOperator, p); + // } + // } else { + // system.newSideEffect(new GetFieldOperator(f, + // system.findOrCreatePointsToSet(def)), refKey); + // } + // } + // } + } + + /* + * (non-Javadoc) + * + * @see com.ibm.domo.ssa.Instruction.Visitor#visitPut(com.ibm.domo.ssa.PutInstruction) + */ + @Override + public void visitPut(SSAPutInstruction instruction) { + visitPutInternal(instruction.getVal(), instruction.isStatic(), instruction.getDeclaredField()); + } + + public void visitPutInternal(int rval, boolean isStatic, FieldReference field) { + // skip putfields of primitive type (optimisation) + if (field.getFieldType().isPrimitiveType()) { + return; + } + IField f = cg.getClassHierarchy().resolveField(field); + if (f == null) { + return; + } + PointerKey use = heapModel.getPointerKeyForLocal(node, rval); + assert use != null; + + if (isStatic) { + PointerKey fKey = heapModel.getPointerKeyForStaticField(f); + addNode(use); + addNode(fKey); + addEdge(fKey, use); + } else { + addNode(use); + } + } + + /* + * @see com.ibm.domo.ssa.Instruction.Visitor#visitInvoke(com.ibm.domo.ssa.InvokeInstruction) + */ + @Override + public void visitInvoke(SSAInvokeInstruction instruction) { + + for (int i = 0; i < instruction.getNumberOfUses(); i++) { + // just make nodes for parameters; we'll get to them when traversing + // from the callee + PointerKey use = heapModel.getPointerKeyForLocal(node, instruction.getUse(i)); + addNode(use); + } + + // for any def'd values, keep track of the fact that they are def'd + // by a call + if (instruction.hasDef()) { + PointerKey def = heapModel.getPointerKeyForLocal(node, instruction.getDef()); + addNode(def); + callDefs.put(def, instruction); + } + PointerKey exc = heapModel.getPointerKeyForLocal(node, instruction.getException()); + addNode(exc); + callDefs.put(exc, instruction); + // TODO handle exceptions + // if (DEBUG && debug) { + // Trace.println("visitInvoke: " + instruction); + // } + // + // PointerKey uniqueCatch = null; + // if (hasUniqueCatchBlock(instruction, ir)) { + // uniqueCatch = getUniqueCatchKey(instruction, ir, node); + // } + // + // if (instruction.getCallSite().isStatic()) { + // CGNode n = getTargetForCall(node, instruction.getCallSite(), + // (InstanceKey) null); + // if (n == null) { + // getWarnings().add(ResolutionFailure.create(node, instruction)); + // } else { + // processResolvedCall(node, instruction, n, + // computeInvariantParameters(instruction), uniqueCatch); + // if (DEBUG) { + // Trace.guardedPrintln("visitInvoke class init " + n, + // DEBUG_METHOD_SUBSTRING); + // } + // + // // side effect of invoke: may call class initializer + // processClassInitializer(n.getMethod().getDeclaringClass()); + // } + // } else { + // // Add a side effect that will fire when we determine a value + // // for the receiver. This side effect will create a new node + // // and new constraints based on the new callee context. + // // NOTE: This will not be adequate for CPA-style context selectors, + // // where the callee context may depend on state other than the + // // receiver. TODO: rectify this when needed. + // PointerKey receiver = getPointerKeyForLocal(node, + // instruction.getReceiver()); + // // if (!supportFullPointerFlowGraph && + // // contentsAreInvariant(instruction.getReceiver())) { + // if (contentsAreInvariant(symbolTable, du, instruction.getReceiver())) { + // system.recordImplicitPointsToSet(receiver); + // InstanceKey[] ik = getInvariantContents(symbolTable, du, node, + // instruction.getReceiver(), + // SSAPropagationCallGraphBuilder.this); + // for (int i = 0; i < ik.length; i++) { + // system.findOrCreateIndexForInstanceKey(ik[i]); + // CGNode n = getTargetForCall(node, instruction.getCallSite(), ik[i]); + // if (n == null) { + // getWarnings().add(ResolutionFailure.create(node, instruction)); + // } else { + // processResolvedCall(node, instruction, n, + // computeInvariantParameters(instruction), uniqueCatch); + // // side effect of invoke: may call class initializer + // processClassInitializer(n.getMethod().getDeclaringClass()); + // } + // } + // } else { + // if (DEBUG && debug) { + // Trace.println("Add side effect, dispatch to " + instruction + ", + // receiver " + receiver); + // } + // DispatchOperator dispatchOperator = new DispatchOperator(instruction, + // node, computeInvariantParameters(instruction), + // uniqueCatch); + // system.newSideEffect(dispatchOperator, receiver); + // } + // } + } + + /* + * (non-Javadoc) + * + * @see com.ibm.domo.ssa.Instruction.Visitor#visitNew(com.ibm.domo.ssa.NewInstruction) + */ + @Override + public void visitNew(SSANewInstruction instruction) { + + InstanceKey iKey = heapModel.getInstanceKeyForAllocation(node, instruction.getNewSite()); + if (iKey == null) { + // something went wrong. I hope someone raised a warning. + return; + } + PointerKey def = heapModel.getPointerKeyForLocal(node, instruction.getDef()); + addNode(iKey); + addNode(def); + addEdge(def, iKey); + // IClass klass = iKey.getConcreteType(); + // + // if (DEBUG && debug) { + // Trace.println("visitNew: " + instruction + " " + iKey + " " + + // system.findOrCreateIndexForInstanceKey(iKey)); + // } + // + // if (klass == null) { + // getWarnings().add(ResolutionFailure.create(node, + // instruction.getConcreteType())); + // return; + // } + // + // if (!contentsAreInvariant(symbolTable, du, instruction.getDef())) { + // system.newConstraint(def, iKey); + // } else { + // system.findOrCreateIndexForInstanceKey(iKey); + // system.recordImplicitPointsToSet(def); + // } + // + // // side effect of new: may call class initializer + // if (DEBUG) { + // Trace.guardedPrintln("visitNew call clinit: " + klass, + // DEBUG_METHOD_SUBSTRING); + // } + // processClassInitializer(klass); + // + // // add instance keys and pointer keys for array contents + // int dim = 0; + // InstanceKey lastInstance = iKey; + // while (klass != null && klass.isArrayClass()) { + // klass = ((ArrayClass) klass).getElementClass(); + // // klass == null means it's a primitive + // if (klass != null && klass.isArrayClass()) { + // InstanceKey ik = getInstanceKeyForMultiNewArray(node, + // instruction.getNewSite(), dim); + // PointerKey pk = getPointerKeyForArrayContents(lastInstance); + // if (DEBUG_MULTINEWARRAY) { + // Trace.println("multinewarray constraint: "); + // Trace.println(" pk: " + pk); + // Trace.println(" ik: " + system.findOrCreateIndexForInstanceKey(ik) + " + // concrete type " + ik.getConcreteType() + // + " is " + ik); + // Trace.println(" klass:" + klass); + // } + // system.newConstraint(pk, ik); + // lastInstance = ik; + // dim++; + // } + // } + } + + /* + * (non-Javadoc) + * + * @see com.ibm.domo.ssa.Instruction.Visitor#visitThrow(com.ibm.domo.ssa.ThrowInstruction) + */ + @Override + public void visitThrow(SSAThrowInstruction instruction) { + // Assertions.UNREACHABLE(); + // don't do anything: we handle exceptional edges + // in a separate pass + } + + /* + * (non-Javadoc) + * + * @see com.ibm.domo.ssa.Instruction.Visitor#visitGetCaughtException(com.ibm.domo.ssa.GetCaughtExceptionInstruction) + */ + @Override + public void visitGetCaughtException(SSAGetCaughtExceptionInstruction instruction) { + List peis = SSAPropagationCallGraphBuilder.getIncomingPEIs(ir, getBasicBlock()); + PointerKey def = heapModel.getPointerKeyForLocal(node, instruction.getDef()); + + Set types = SSAPropagationCallGraphBuilder.getCaughtExceptionTypes(instruction, ir); + addExceptionDefConstraints(ir, node, peis, def, types); + } + + // private int booleanConstantTest(SSAConditionalBranchInstruction c, int v) + // { + // int result = 0; + // + // // right for OPR_eq + // if ((symbolTable.isZero(c.getUse(0)) && c.getUse(1) == v) || + // (symbolTable.isZero(c.getUse(1)) && c.getUse(0) == v)) { + // result = -1; + // } else if ((symbolTable.isOne(c.getUse(0)) && c.getUse(1) == v) || + // (symbolTable.isOne(c.getUse(1)) && c.getUse(0) == v)) { + // result = 1; + // } + // + // if (c.getOperator() == Constants.OPR_ne) { + // result = -result; + // } + // + // return result; + // } + // + // private int nullConstantTest(SSAConditionalBranchInstruction c, int v) { + // if ((symbolTable.isNullConstant(c.getUse(0)) && c.getUse(1) == v) + // || (symbolTable.isNullConstant(c.getUse(1)) && c.getUse(0) == v)) { + // if (c.getOperator() == Constants.OPR_eq) { + // return 1; + // } else { + // return -1; + // } + // } else { + // return 0; + // } + // } + + /* + * (non-Javadoc) + * + * @see com.ibm.domo.ssa.SSAInstruction.Visitor#visitPi(com.ibm.domo.ssa.SSAPiInstruction) + */ + @Override + public void visitPi(SSAPiInstruction instruction) { + Assertions.UNREACHABLE(); + // int dir; + // ControlFlowGraph CFG = ir.getControlFlowGraph(); + // PointerKey src = getPointerKeyForLocal(node, instruction.getVal()); + // if (hasNoInterestingUses(instruction.getDef(), du)) { + // PointerKey dst = getPointerKeyForLocal(node, instruction.getDef()); + // system.recordImplicitPointsToSet(dst); + // } else { + // if (com.ibm.domo.cfg.Util.endsWithConditionalBranch(CFG, + // getBasicBlock()) && CFG.getSuccNodeCount(getBasicBlock()) == 2) { + // SSAConditionalBranchInstruction cond = + // com.ibm.domo.cfg.Util.getConditionalBranch(CFG, getBasicBlock()); + // SSAInstruction cause = instruction.getCause(); + // BasicBlock target = (BasicBlock) + // CFG.getNode(instruction.getSuccessor()); + // if ((cause instanceof SSAInstanceofInstruction) && ((dir = + // booleanConstantTest(cond, cause.getDef())) != 0)) { + // TypeReference type = ((SSAInstanceofInstruction) + // cause).getCheckedType(); + // IClass cls = cha.lookupClass(type); + // if (cls == null) { + // getWarnings().add(ResolutionFailure.create(node, type)); + // PointerKey dst = getPointerKeyForLocal(node, instruction.getDef()); + // system.newConstraint(dst, assignOperator, src); + // } else { + // PointerKey dst = getFilteredPointerKeyForLocal(node, + // instruction.getDef(), cls); + // if ((target == com.ibm.domo.cfg.Util.getTrueSuccessor(CFG, + // getBasicBlock()) && dir == 1) + // || (target == com.ibm.domo.cfg.Util.getFalseSuccessor(CFG, + // getBasicBlock()) && dir == -1)) { + // system.newConstraint(dst, filterOperator, src); + // // System.err.println("PI " + dst + " " + src); + // } else { + // system.newConstraint(dst, inverseFilterOperator, src); + // } + // } + // } else if ((dir = nullConstantTest(cond, instruction.getVal())) != 0) { + // if ((target == com.ibm.domo.cfg.Util.getTrueSuccessor(CFG, + // getBasicBlock()) && dir == -1) + // || (target == com.ibm.domo.cfg.Util.getFalseSuccessor(CFG, + // getBasicBlock()) && dir == 1)) { + // PointerKey dst = getPointerKeyForLocal(node, instruction.getDef()); + // system.newConstraint(dst, assignOperator, src); + // } + // } else { + // PointerKey dst = getPointerKeyForLocal(node, instruction.getDef()); + // system.newConstraint(dst, assignOperator, src); + // } + // } else { + // PointerKey dst = getPointerKeyForLocal(node, instruction.getDef()); + // system.newConstraint(dst, assignOperator, src); + // } + // } + } + + public ISSABasicBlock getBasicBlock() { + return basicBlock; + } + + /** + * The calling loop must call this in each iteration! + */ + public void setBasicBlock(ISSABasicBlock block) { + basicBlock = block; + } + + // /** + // * Side effect: records invariant parameters as implicit points-to-sets. + // * + // * @return if non-null, then result[i] holds the set of instance keys + // which + // * may be passed as the ith parameter. (which must be invariant) + // */ + // protected InstanceKey[][] + // computeInvariantParameters(SSAAbstractInvokeInstruction call) { + // InstanceKey[][] constParams = null; + // for (int i = 0; i < call.getNumberOfUses(); i++) { + // // not sure how getUse(i) <= 0 .. dead code? + // // TODO: investigate + // if (call.getUse(i) > 0) { + // if (contentsAreInvariant(symbolTable, du, call.getUse(i))) { + // system.recordImplicitPointsToSet(getPointerKeyForLocal(node, + // call.getUse(i))); + // if (constParams == null) { + // constParams = new InstanceKey[call.getNumberOfUses()][]; + // } + // constParams[i] = getInvariantContents(symbolTable, du, node, + // call.getUse(i), SSAPropagationCallGraphBuilder.this); + // for (int j = 0; j < constParams[i].length; j++) { + // system.findOrCreateIndexForInstanceKey(constParams[i][j]); + // } + // } + // } + // } + // return constParams; + // } + + @Override + public void visitLoadMetadata(SSALoadMetadataInstruction instruction) { + Assertions.UNREACHABLE(); + // PointerKey def = getPointerKeyForLocal(node, instruction.getDef()); + // InstanceKey iKey = + // getInstanceKeyForClassObject(instruction.getLoadedClass()); + // + // if (!contentsAreInvariant(symbolTable, du, instruction.getDef())) { + // system.newConstraint(def, iKey); + // } else { + // system.findOrCreateIndexForInstanceKey(iKey); + // system.recordImplicitPointsToSet(def); + // } + } + } + + // private final class FieldExpression { + // LocalPointerKey x; + // + // IField f; + // + // public FieldExpression(IField f, LocalPointerKey x) { + // this.f = f; + // this.x = x; + // } + // + // /* + // * (non-Javadoc) + // * + // * @see java.lang.Object#equals(java.lang.Object) + // */ + // public boolean equals(Object obj) { + // if (obj instanceof FieldExpression) { + // FieldExpression other = (FieldExpression) obj; + // return x.equals(other.x) && f.equals(other.f); + // } else { + // return false; + // } + // } + // + // /* + // * (non-Javadoc) + // * + // * @see java.lang.Object#hashCode() + // */ + // public int hashCode() { + // return x.hashCode() + 4729 * f.hashCode(); + // } + // } + } \ No newline at end of file diff --git a/com.ibm.wala.core/src/com/ibm/wala/demandpa/util/ArrayContents.java b/com.ibm.wala.core/src/com/ibm/wala/demandpa/util/ArrayContents.java index 2ae018f8c..6c84d25e5 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/demandpa/util/ArrayContents.java +++ b/com.ibm.wala.core/src/com/ibm/wala/demandpa/util/ArrayContents.java @@ -1,123 +1,123 @@ -/******************************************************************************* - * 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. - * - * This file is a derivative of code released by the University of - * California under the terms listed below. - * - * Refinement Analysis Tools is Copyright (c) 2007 The Regents of the - * University of California (Regents). Provided that this notice and - * the following two paragraphs are included in any distribution of - * Refinement Analysis Tools or its derivative work, Regents agrees - * not to assert any of Regents' copyright rights in Refinement - * Analysis Tools against recipient for recipient's reproduction, - * preparation of derivative works, public display, public - * performance, distribution or sublicensing of Refinement Analysis - * Tools and derivative works, in source code and object code form. - * This agreement not to assert does not confer, by implication, - * estoppel, or otherwise any license or rights in any intellectual - * property of Regents, including, but not limited to, any patents - * of Regents or Regents' employees. - * - * IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, - * INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, - * INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE - * AND ITS DOCUMENTATION, EVEN IF REGENTS HAS BEEN ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE AND FURTHER DISCLAIMS ANY STATUTORY - * WARRANTY OF NON-INFRINGEMENT. THE SOFTWARE AND ACCOMPANYING - * DOCUMENTATION, IF ANY, PROVIDED HEREUNDER IS PROVIDED "AS - * IS". REGENTS HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, - * UPDATES, ENHANCEMENTS, OR MODIFICATIONS. - */ -package com.ibm.wala.demandpa.util; - -import com.ibm.wala.classLoader.IClass; -import com.ibm.wala.classLoader.IField; -import com.ibm.wala.ipa.cha.ClassHierarchy; -import com.ibm.wala.types.FieldReference; -import com.ibm.wala.types.TypeReference; -import com.ibm.wala.util.debug.Assertions; -import com.ibm.wala.util.debug.UnimplementedError; -import com.ibm.wala.util.strings.Atom; - -/** - * Pseudo-field modelling the contents of an array of reference type. Only for - * convenience; many of the methods don't actually work. Also, a singleton. - * - * @author manu - * - */ -public class ArrayContents implements IField { - - private static final ArrayContents theContents = new ArrayContents(); - - public static final ArrayContents v() { - return theContents; - } - - private ArrayContents() { - } - - public TypeReference getFieldTypeReference() throws UnimplementedError { - Assertions.UNREACHABLE(); - return null; - } - - public boolean isFinal() throws UnimplementedError { - Assertions.UNREACHABLE(); - return false; - } - - public boolean isPrivate() throws UnimplementedError { - Assertions.UNREACHABLE(); - return false; - } - - public boolean isProtected() throws UnimplementedError { - Assertions.UNREACHABLE(); - return false; - } - - public boolean isPublic() throws UnimplementedError { - Assertions.UNREACHABLE(); - return false; - } - - public boolean isStatic() throws UnimplementedError { - Assertions.UNREACHABLE(); - return false; - } - - public IClass getDeclaringClass() throws UnsupportedOperationException { - throw new UnsupportedOperationException(); - } - - public Atom getName() throws UnimplementedError { - Assertions.UNREACHABLE(); - return null; - } - - @Override - public String toString() { - return "arr"; - } - - public boolean isVolatile() { - return false; - } - - public ClassHierarchy getClassHierarchy() throws UnimplementedError { - Assertions.UNREACHABLE(); - return null; - } - - public FieldReference getReference() { - return null; - } +/******************************************************************************* + * 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. + * + * This file is a derivative of code released by the University of + * California under the terms listed below. + * + * Refinement Analysis Tools is Copyright (c) 2007 The Regents of the + * University of California (Regents). Provided that this notice and + * the following two paragraphs are included in any distribution of + * Refinement Analysis Tools or its derivative work, Regents agrees + * not to assert any of Regents' copyright rights in Refinement + * Analysis Tools against recipient for recipient's reproduction, + * preparation of derivative works, public display, public + * performance, distribution or sublicensing of Refinement Analysis + * Tools and derivative works, in source code and object code form. + * This agreement not to assert does not confer, by implication, + * estoppel, or otherwise any license or rights in any intellectual + * property of Regents, including, but not limited to, any patents + * of Regents or Regents' employees. + * + * IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, + * INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, + * INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE + * AND ITS DOCUMENTATION, EVEN IF REGENTS HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE AND FURTHER DISCLAIMS ANY STATUTORY + * WARRANTY OF NON-INFRINGEMENT. THE SOFTWARE AND ACCOMPANYING + * DOCUMENTATION, IF ANY, PROVIDED HEREUNDER IS PROVIDED "AS + * IS". REGENTS HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, + * UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + */ +package com.ibm.wala.demandpa.util; + +import com.ibm.wala.classLoader.IClass; +import com.ibm.wala.classLoader.IField; +import com.ibm.wala.ipa.cha.ClassHierarchy; +import com.ibm.wala.types.FieldReference; +import com.ibm.wala.types.TypeReference; +import com.ibm.wala.util.debug.Assertions; +import com.ibm.wala.util.debug.UnimplementedError; +import com.ibm.wala.util.strings.Atom; + +/** + * Pseudo-field modelling the contents of an array of reference type. Only for + * convenience; many of the methods don't actually work. Also, a singleton. + * + * @author manu + * + */ +public class ArrayContents implements IField { + + private static final ArrayContents theContents = new ArrayContents(); + + public static final ArrayContents v() { + return theContents; + } + + private ArrayContents() { + } + + public TypeReference getFieldTypeReference() throws UnimplementedError { + Assertions.UNREACHABLE(); + return null; + } + + public boolean isFinal() throws UnimplementedError { + Assertions.UNREACHABLE(); + return false; + } + + public boolean isPrivate() throws UnimplementedError { + Assertions.UNREACHABLE(); + return false; + } + + public boolean isProtected() throws UnimplementedError { + Assertions.UNREACHABLE(); + return false; + } + + public boolean isPublic() throws UnimplementedError { + Assertions.UNREACHABLE(); + return false; + } + + public boolean isStatic() throws UnimplementedError { + Assertions.UNREACHABLE(); + return false; + } + + public IClass getDeclaringClass() throws UnsupportedOperationException { + throw new UnsupportedOperationException(); + } + + public Atom getName() throws UnimplementedError { + Assertions.UNREACHABLE(); + return null; + } + + @Override + public String toString() { + return "arr"; + } + + public boolean isVolatile() { + return false; + } + + public ClassHierarchy getClassHierarchy() throws UnimplementedError { + Assertions.UNREACHABLE(); + return null; + } + + public FieldReference getReference() { + return null; + } } \ No newline at end of file diff --git a/com.ibm.wala.core/src/com/ibm/wala/demandpa/util/CallGraphMapUtil.java b/com.ibm.wala.core/src/com/ibm/wala/demandpa/util/CallGraphMapUtil.java index d564de4a0..28939fc46 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/demandpa/util/CallGraphMapUtil.java +++ b/com.ibm.wala.core/src/com/ibm/wala/demandpa/util/CallGraphMapUtil.java @@ -1,159 +1,159 @@ -/******************************************************************************* - * 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. - * - * This file is a derivative of code released by the University of - * California under the terms listed below. - * - * Refinement Analysis Tools is Copyright (c) 2007 The Regents of the - * University of California (Regents). Provided that this notice and - * the following two paragraphs are included in any distribution of - * Refinement Analysis Tools or its derivative work, Regents agrees - * not to assert any of Regents' copyright rights in Refinement - * Analysis Tools against recipient for recipient's reproduction, - * preparation of derivative works, public display, public - * performance, distribution or sublicensing of Refinement Analysis - * Tools and derivative works, in source code and object code form. - * This agreement not to assert does not confer, by implication, - * estoppel, or otherwise any license or rights in any intellectual - * property of Regents, including, but not limited to, any patents - * of Regents or Regents' employees. - * - * IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, - * INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, - * INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE - * AND ITS DOCUMENTATION, EVEN IF REGENTS HAS BEEN ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE AND FURTHER DISCLAIMS ANY STATUTORY - * WARRANTY OF NON-INFRINGEMENT. THE SOFTWARE AND ACCOMPANYING - * DOCUMENTATION, IF ANY, PROVIDED HEREUNDER IS PROVIDED "AS - * IS". REGENTS HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, - * UPDATES, ENHANCEMENTS, OR MODIFICATIONS. - */ -package com.ibm.wala.demandpa.util; - -import java.util.Set; - -import com.ibm.wala.analysis.reflection.InstanceKeyWithNode; -import com.ibm.wala.ipa.callgraph.CGNode; -import com.ibm.wala.ipa.callgraph.CallGraph; -import com.ibm.wala.ipa.callgraph.propagation.AbstractLocalPointerKey; -import com.ibm.wala.ipa.callgraph.propagation.AllocationSiteInNode; -import com.ibm.wala.ipa.callgraph.propagation.ConcreteTypeKey; -import com.ibm.wala.ipa.callgraph.propagation.HeapModel; -import com.ibm.wala.ipa.callgraph.propagation.InstanceKey; -import com.ibm.wala.ipa.callgraph.propagation.LocalPointerKey; -import com.ibm.wala.ipa.callgraph.propagation.MultiNewArrayInNode; -import com.ibm.wala.ipa.callgraph.propagation.NormalAllocationInNode; -import com.ibm.wala.ipa.callgraph.propagation.PointerKey; -import com.ibm.wala.ipa.callgraph.propagation.ReturnValueKey; -import com.ibm.wala.ipa.callgraph.propagation.cfa.ExceptionReturnValueKey; -import com.ibm.wala.types.MethodReference; -import com.ibm.wala.util.debug.Assertions; -import com.ibm.wala.util.debug.UnimplementedError; - -/** - * utility methods for mapping various program entities from one call graph to the corresponding entity in another one - * - * @author Manu Sridharan - * - */ -public class CallGraphMapUtil { - - /** - * map a call graph node from one call graph to the corresponding node in another. Note that the target call graph must be - * context-insensitive for the method, i.e., the only context for the method should be Everywhere.EVERYWHERE. - * - * @return the corresponding node, or null if the method is not in the target call graph - * @throws IllegalArgumentException if fromCG == null - */ - public static CGNode mapCGNode(CGNode orig, CallGraph fromCG, CallGraph toCG) throws IllegalArgumentException { - if (fromCG == null) { - throw new IllegalArgumentException("fromCG == null"); - } - if (orig == fromCG.getFakeRootNode()) { - return toCG.getFakeRootNode(); - } else { - MethodReference methodRef = orig.getMethod().getReference(); - if (methodRef.toString().equals("< Primordial, Ljava/lang/Object, clone()Ljava/lang/Object; >")) { - // NOTE: clone() is cloned one level, even by RTA, so we need to handle it - CGNode ret = toCG.getNode(orig.getMethod(), orig.getContext()); - if (ret == null) { - System.err.println(("WEIRD can't map node " + orig)); - } - return ret; - } else { - Set nodes = toCG.getNodes(methodRef); - int size = nodes.size(); - assert size <= 1; - return (size == 0) ? null : nodes.iterator().next(); - } - } - } - - public static InstanceKey mapInstKey(InstanceKey ik, CallGraph fromCG, CallGraph toCG, HeapModel heapModel) - throws UnimplementedError, NullPointerException { - InstanceKey ret = null; - if (ik instanceof InstanceKeyWithNode) { - CGNode oldCGNode = ((InstanceKeyWithNode) ik).getNode(); - CGNode newCGNode = mapCGNode(oldCGNode, fromCG, toCG); - if (newCGNode == null) { - return null; - } - if (ik instanceof AllocationSiteInNode) { - if (ik instanceof NormalAllocationInNode) { - ret = heapModel.getInstanceKeyForAllocation(newCGNode, ((AllocationSiteInNode) ik).getSite()); - } else if (ik instanceof MultiNewArrayInNode) { - MultiNewArrayInNode mnik = (MultiNewArrayInNode) ik; - - ret = heapModel.getInstanceKeyForMultiNewArray(newCGNode, mnik.getSite(), mnik.getDim()); - } else { - Assertions.UNREACHABLE(); - } - } else { - Assertions.UNREACHABLE(); - } - } else if (ik instanceof ConcreteTypeKey) { - return ik; - } else { - Assertions.UNREACHABLE(); - } - assert ret != null; - assert ret.getClass() == ik.getClass(); - return ret; - } - - public static PointerKey mapPointerKey(PointerKey pk, CallGraph fromCG, CallGraph toCG, HeapModel heapModel) - throws UnimplementedError { - PointerKey ret = null; - if (pk instanceof AbstractLocalPointerKey) { - CGNode oldCGNode = ((AbstractLocalPointerKey) pk).getNode(); - CGNode newCGNode = mapCGNode(oldCGNode, fromCG, toCG); - if (newCGNode == null) { - return null; - } - if (pk instanceof LocalPointerKey) { - ret = heapModel.getPointerKeyForLocal(newCGNode, ((LocalPointerKey) pk).getValueNumber()); - } else if (pk instanceof ReturnValueKey) { - // NOTE: must check for ExceptionReturnValueKey first, - // since its a subclass if ReturnValueKey - if (pk instanceof ExceptionReturnValueKey) { - ret = heapModel.getPointerKeyForExceptionalReturnValue(newCGNode); - } else { - ret = heapModel.getPointerKeyForReturnValue(newCGNode); - } - } else { - Assertions.UNREACHABLE(); - } - } else { - Assertions.UNREACHABLE(); - } - assert ret != null; - return ret; - } -} +/******************************************************************************* + * 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. + * + * This file is a derivative of code released by the University of + * California under the terms listed below. + * + * Refinement Analysis Tools is Copyright (c) 2007 The Regents of the + * University of California (Regents). Provided that this notice and + * the following two paragraphs are included in any distribution of + * Refinement Analysis Tools or its derivative work, Regents agrees + * not to assert any of Regents' copyright rights in Refinement + * Analysis Tools against recipient for recipient's reproduction, + * preparation of derivative works, public display, public + * performance, distribution or sublicensing of Refinement Analysis + * Tools and derivative works, in source code and object code form. + * This agreement not to assert does not confer, by implication, + * estoppel, or otherwise any license or rights in any intellectual + * property of Regents, including, but not limited to, any patents + * of Regents or Regents' employees. + * + * IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, + * INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, + * INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE + * AND ITS DOCUMENTATION, EVEN IF REGENTS HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE AND FURTHER DISCLAIMS ANY STATUTORY + * WARRANTY OF NON-INFRINGEMENT. THE SOFTWARE AND ACCOMPANYING + * DOCUMENTATION, IF ANY, PROVIDED HEREUNDER IS PROVIDED "AS + * IS". REGENTS HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, + * UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + */ +package com.ibm.wala.demandpa.util; + +import java.util.Set; + +import com.ibm.wala.analysis.reflection.InstanceKeyWithNode; +import com.ibm.wala.ipa.callgraph.CGNode; +import com.ibm.wala.ipa.callgraph.CallGraph; +import com.ibm.wala.ipa.callgraph.propagation.AbstractLocalPointerKey; +import com.ibm.wala.ipa.callgraph.propagation.AllocationSiteInNode; +import com.ibm.wala.ipa.callgraph.propagation.ConcreteTypeKey; +import com.ibm.wala.ipa.callgraph.propagation.HeapModel; +import com.ibm.wala.ipa.callgraph.propagation.InstanceKey; +import com.ibm.wala.ipa.callgraph.propagation.LocalPointerKey; +import com.ibm.wala.ipa.callgraph.propagation.MultiNewArrayInNode; +import com.ibm.wala.ipa.callgraph.propagation.NormalAllocationInNode; +import com.ibm.wala.ipa.callgraph.propagation.PointerKey; +import com.ibm.wala.ipa.callgraph.propagation.ReturnValueKey; +import com.ibm.wala.ipa.callgraph.propagation.cfa.ExceptionReturnValueKey; +import com.ibm.wala.types.MethodReference; +import com.ibm.wala.util.debug.Assertions; +import com.ibm.wala.util.debug.UnimplementedError; + +/** + * utility methods for mapping various program entities from one call graph to the corresponding entity in another one + * + * @author Manu Sridharan + * + */ +public class CallGraphMapUtil { + + /** + * map a call graph node from one call graph to the corresponding node in another. Note that the target call graph must be + * context-insensitive for the method, i.e., the only context for the method should be Everywhere.EVERYWHERE. + * + * @return the corresponding node, or null if the method is not in the target call graph + * @throws IllegalArgumentException if fromCG == null + */ + public static CGNode mapCGNode(CGNode orig, CallGraph fromCG, CallGraph toCG) throws IllegalArgumentException { + if (fromCG == null) { + throw new IllegalArgumentException("fromCG == null"); + } + if (orig == fromCG.getFakeRootNode()) { + return toCG.getFakeRootNode(); + } else { + MethodReference methodRef = orig.getMethod().getReference(); + if (methodRef.toString().equals("< Primordial, Ljava/lang/Object, clone()Ljava/lang/Object; >")) { + // NOTE: clone() is cloned one level, even by RTA, so we need to handle it + CGNode ret = toCG.getNode(orig.getMethod(), orig.getContext()); + if (ret == null) { + System.err.println(("WEIRD can't map node " + orig)); + } + return ret; + } else { + Set nodes = toCG.getNodes(methodRef); + int size = nodes.size(); + assert size <= 1; + return (size == 0) ? null : nodes.iterator().next(); + } + } + } + + public static InstanceKey mapInstKey(InstanceKey ik, CallGraph fromCG, CallGraph toCG, HeapModel heapModel) + throws UnimplementedError, NullPointerException { + InstanceKey ret = null; + if (ik instanceof InstanceKeyWithNode) { + CGNode oldCGNode = ((InstanceKeyWithNode) ik).getNode(); + CGNode newCGNode = mapCGNode(oldCGNode, fromCG, toCG); + if (newCGNode == null) { + return null; + } + if (ik instanceof AllocationSiteInNode) { + if (ik instanceof NormalAllocationInNode) { + ret = heapModel.getInstanceKeyForAllocation(newCGNode, ((AllocationSiteInNode) ik).getSite()); + } else if (ik instanceof MultiNewArrayInNode) { + MultiNewArrayInNode mnik = (MultiNewArrayInNode) ik; + + ret = heapModel.getInstanceKeyForMultiNewArray(newCGNode, mnik.getSite(), mnik.getDim()); + } else { + Assertions.UNREACHABLE(); + } + } else { + Assertions.UNREACHABLE(); + } + } else if (ik instanceof ConcreteTypeKey) { + return ik; + } else { + Assertions.UNREACHABLE(); + } + assert ret != null; + assert ret.getClass() == ik.getClass(); + return ret; + } + + public static PointerKey mapPointerKey(PointerKey pk, CallGraph fromCG, CallGraph toCG, HeapModel heapModel) + throws UnimplementedError { + PointerKey ret = null; + if (pk instanceof AbstractLocalPointerKey) { + CGNode oldCGNode = ((AbstractLocalPointerKey) pk).getNode(); + CGNode newCGNode = mapCGNode(oldCGNode, fromCG, toCG); + if (newCGNode == null) { + return null; + } + if (pk instanceof LocalPointerKey) { + ret = heapModel.getPointerKeyForLocal(newCGNode, ((LocalPointerKey) pk).getValueNumber()); + } else if (pk instanceof ReturnValueKey) { + // NOTE: must check for ExceptionReturnValueKey first, + // since its a subclass if ReturnValueKey + if (pk instanceof ExceptionReturnValueKey) { + ret = heapModel.getPointerKeyForExceptionalReturnValue(newCGNode); + } else { + ret = heapModel.getPointerKeyForReturnValue(newCGNode); + } + } else { + Assertions.UNREACHABLE(); + } + } else { + Assertions.UNREACHABLE(); + } + assert ret != null; + return ret; + } +} diff --git a/com.ibm.wala.core/src/com/ibm/wala/demandpa/util/MemoryAccess.java b/com.ibm.wala.core/src/com/ibm/wala/demandpa/util/MemoryAccess.java index 60cc308b2..306e9c8da 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/demandpa/util/MemoryAccess.java +++ b/com.ibm.wala.core/src/com/ibm/wala/demandpa/util/MemoryAccess.java @@ -1,87 +1,87 @@ -/******************************************************************************* - * Copyright (c) 2007 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.demandpa.util; - -import com.ibm.wala.ipa.callgraph.CGNode; - -/** - * * - * represents a single static occurrence of a memory access (i.e., an access to a field - * or to the contents of an array) in the code - * - * @author sfink - */ -public class MemoryAccess { - - final private CGNode node; - - /** - * index of the field access instruction in a shrikeBt or SSA instruction - * array - */ - final private int instructionIndex; - - public MemoryAccess(int index, CGNode node) { - super(); - instructionIndex = index; - this.node = node; - } - - /** - * @return Returns the instructionIndex. - */ - public int getInstructionIndex() { - return instructionIndex; - } - - @Override - public String toString() { - return "MemAccess: " + getNode() + ":" + getInstructionIndex(); - } - - /** - * @return Returns the node. - */ - public CGNode getNode() { - return node; - } - - @Override - public int hashCode() { - final int prime = 31; - int result = 1; - result = prime * result + instructionIndex; - result = prime * result + ((node == null) ? 0 : node.hashCode()); - return result; - } - - @Override - public boolean equals(Object obj) { - if (this == obj) - return true; - if (obj == null) - return false; - if (getClass() != obj.getClass()) - return false; - MemoryAccess other = (MemoryAccess) obj; - if (instructionIndex != other.instructionIndex) - return false; - if (node == null) { - if (other.node != null) - return false; - } else if (!node.equals(other.node)) - return false; - return true; - } - - - -} +/******************************************************************************* + * Copyright (c) 2007 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.demandpa.util; + +import com.ibm.wala.ipa.callgraph.CGNode; + +/** + * * + * represents a single static occurrence of a memory access (i.e., an access to a field + * or to the contents of an array) in the code + * + * @author sfink + */ +public class MemoryAccess { + + final private CGNode node; + + /** + * index of the field access instruction in a shrikeBt or SSA instruction + * array + */ + final private int instructionIndex; + + public MemoryAccess(int index, CGNode node) { + super(); + instructionIndex = index; + this.node = node; + } + + /** + * @return Returns the instructionIndex. + */ + public int getInstructionIndex() { + return instructionIndex; + } + + @Override + public String toString() { + return "MemAccess: " + getNode() + ":" + getInstructionIndex(); + } + + /** + * @return Returns the node. + */ + public CGNode getNode() { + return node; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + instructionIndex; + result = prime * result + ((node == null) ? 0 : node.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + MemoryAccess other = (MemoryAccess) obj; + if (instructionIndex != other.instructionIndex) + return false; + if (node == null) { + if (other.node != null) + return false; + } else if (!node.equals(other.node)) + return false; + return true; + } + + + +} diff --git a/com.ibm.wala.core/src/com/ibm/wala/demandpa/util/PointerParamValueNumIterator.java b/com.ibm.wala.core/src/com/ibm/wala/demandpa/util/PointerParamValueNumIterator.java index 1316304a3..43d74a3c1 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/demandpa/util/PointerParamValueNumIterator.java +++ b/com.ibm.wala.core/src/com/ibm/wala/demandpa/util/PointerParamValueNumIterator.java @@ -1,118 +1,118 @@ -/******************************************************************************* - * 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. - * - * This file is a derivative of code released by the University of - * California under the terms listed below. - * - * Refinement Analysis Tools is Copyright (c) 2007 The Regents of the - * University of California (Regents). Provided that this notice and - * the following two paragraphs are included in any distribution of - * Refinement Analysis Tools or its derivative work, Regents agrees - * not to assert any of Regents' copyright rights in Refinement - * Analysis Tools against recipient for recipient's reproduction, - * preparation of derivative works, public display, public - * performance, distribution or sublicensing of Refinement Analysis - * Tools and derivative works, in source code and object code form. - * This agreement not to assert does not confer, by implication, - * estoppel, or otherwise any license or rights in any intellectual - * property of Regents, including, but not limited to, any patents - * of Regents or Regents' employees. - * - * IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, - * INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, - * INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE - * AND ITS DOCUMENTATION, EVEN IF REGENTS HAS BEEN ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE AND FURTHER DISCLAIMS ANY STATUTORY - * WARRANTY OF NON-INFRINGEMENT. THE SOFTWARE AND ACCOMPANYING - * DOCUMENTATION, IF ANY, PROVIDED HEREUNDER IS PROVIDED "AS - * IS". REGENTS HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, - * UPDATES, ENHANCEMENTS, OR MODIFICATIONS. - */ -package com.ibm.wala.demandpa.util; - -import java.util.Iterator; -import java.util.NoSuchElementException; - -import com.ibm.wala.analysis.typeInference.TypeAbstraction; -import com.ibm.wala.analysis.typeInference.TypeInference; -import com.ibm.wala.ipa.callgraph.CGNode; -import com.ibm.wala.ssa.IR; -import com.ibm.wala.ssa.SymbolTable; - -/** - * Iterates over the value numbers of the pointer parameters of - * a method. - * @author Manu Sridharan - * - */ -public class PointerParamValueNumIterator implements Iterator { - - final TypeInference ti; - - final SymbolTable symbolTable; - - final int numParams; - - int paramInd; - - int nextParameter; - - public PointerParamValueNumIterator(CGNode node) throws IllegalArgumentException { - if (node == null) { - throw new IllegalArgumentException("node == null"); - } - IR ir = node.getIR(); - ti = TypeInference.make(ir, false); - symbolTable = ir.getSymbolTable(); - numParams = symbolTable.getNumberOfParameters(); - paramInd = 0; - setNextParameter(); - } - - private void setNextParameter() { - int i = paramInd; - for ( ; i < numParams; i++) { - int parameter = symbolTable.getParameter(i); - TypeAbstraction t = ti.getType(parameter); - if (t != null) { - nextParameter = parameter; - break; - } - } - paramInd = ++i; - } - - /* - * @see java.util.Iterator#hasNext() - */ - public boolean hasNext() { - return paramInd <= numParams; - } - - /* - * @see java.util.Iterator#next() - */ - public Integer next() { - if (!hasNext()) { - throw new NoSuchElementException(); - } - int ret = nextParameter; - setNextParameter(); - return ret; - } - - /* - * @see java.util.Iterator#remove() - */ - public void remove() throws UnsupportedOperationException { - throw new UnsupportedOperationException(); - } - +/******************************************************************************* + * 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. + * + * This file is a derivative of code released by the University of + * California under the terms listed below. + * + * Refinement Analysis Tools is Copyright (c) 2007 The Regents of the + * University of California (Regents). Provided that this notice and + * the following two paragraphs are included in any distribution of + * Refinement Analysis Tools or its derivative work, Regents agrees + * not to assert any of Regents' copyright rights in Refinement + * Analysis Tools against recipient for recipient's reproduction, + * preparation of derivative works, public display, public + * performance, distribution or sublicensing of Refinement Analysis + * Tools and derivative works, in source code and object code form. + * This agreement not to assert does not confer, by implication, + * estoppel, or otherwise any license or rights in any intellectual + * property of Regents, including, but not limited to, any patents + * of Regents or Regents' employees. + * + * IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, + * INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, + * INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE + * AND ITS DOCUMENTATION, EVEN IF REGENTS HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE AND FURTHER DISCLAIMS ANY STATUTORY + * WARRANTY OF NON-INFRINGEMENT. THE SOFTWARE AND ACCOMPANYING + * DOCUMENTATION, IF ANY, PROVIDED HEREUNDER IS PROVIDED "AS + * IS". REGENTS HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, + * UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + */ +package com.ibm.wala.demandpa.util; + +import java.util.Iterator; +import java.util.NoSuchElementException; + +import com.ibm.wala.analysis.typeInference.TypeAbstraction; +import com.ibm.wala.analysis.typeInference.TypeInference; +import com.ibm.wala.ipa.callgraph.CGNode; +import com.ibm.wala.ssa.IR; +import com.ibm.wala.ssa.SymbolTable; + +/** + * Iterates over the value numbers of the pointer parameters of + * a method. + * @author Manu Sridharan + * + */ +public class PointerParamValueNumIterator implements Iterator { + + final TypeInference ti; + + final SymbolTable symbolTable; + + final int numParams; + + int paramInd; + + int nextParameter; + + public PointerParamValueNumIterator(CGNode node) throws IllegalArgumentException { + if (node == null) { + throw new IllegalArgumentException("node == null"); + } + IR ir = node.getIR(); + ti = TypeInference.make(ir, false); + symbolTable = ir.getSymbolTable(); + numParams = symbolTable.getNumberOfParameters(); + paramInd = 0; + setNextParameter(); + } + + private void setNextParameter() { + int i = paramInd; + for ( ; i < numParams; i++) { + int parameter = symbolTable.getParameter(i); + TypeAbstraction t = ti.getType(parameter); + if (t != null) { + nextParameter = parameter; + break; + } + } + paramInd = ++i; + } + + /* + * @see java.util.Iterator#hasNext() + */ + public boolean hasNext() { + return paramInd <= numParams; + } + + /* + * @see java.util.Iterator#next() + */ + public Integer next() { + if (!hasNext()) { + throw new NoSuchElementException(); + } + int ret = nextParameter; + setNextParameter(); + return ret; + } + + /* + * @see java.util.Iterator#remove() + */ + public void remove() throws UnsupportedOperationException { + throw new UnsupportedOperationException(); + } + } \ No newline at end of file diff --git a/com.ibm.wala.core/src/com/ibm/wala/demandpa/util/SimpleMemoryAccessMap.java b/com.ibm.wala.core/src/com/ibm/wala/demandpa/util/SimpleMemoryAccessMap.java index 5cfac9e33..239240c2c 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/demandpa/util/SimpleMemoryAccessMap.java +++ b/com.ibm.wala.core/src/com/ibm/wala/demandpa/util/SimpleMemoryAccessMap.java @@ -1,456 +1,456 @@ -/******************************************************************************* - * Copyright (c) 2007 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.demandpa.util; - -import java.util.Collection; -import java.util.Collections; -import java.util.Iterator; -import java.util.Map; -import java.util.Set; - -import com.ibm.wala.classLoader.IField; -import com.ibm.wala.classLoader.ShrikeCTMethod; -import com.ibm.wala.ipa.callgraph.CGNode; -import com.ibm.wala.ipa.callgraph.CallGraph; -import com.ibm.wala.ipa.callgraph.propagation.HeapModel; -import com.ibm.wala.ipa.callgraph.propagation.PointerKey; -import com.ibm.wala.ipa.cha.IClassHierarchy; -import com.ibm.wala.shrikeBT.IArrayLoadInstruction; -import com.ibm.wala.shrikeBT.IArrayStoreInstruction; -import com.ibm.wala.shrikeBT.IGetInstruction; -import com.ibm.wala.shrikeBT.IInstruction; -import com.ibm.wala.shrikeBT.IPutInstruction; -import com.ibm.wala.shrikeBT.NewInstruction; -import com.ibm.wala.shrikeCT.InvalidClassFileException; -import com.ibm.wala.ssa.IR; -import com.ibm.wala.ssa.SSAArrayLoadInstruction; -import com.ibm.wala.ssa.SSAArrayReferenceInstruction; -import com.ibm.wala.ssa.SSAArrayStoreInstruction; -import com.ibm.wala.ssa.SSAGetInstruction; -import com.ibm.wala.ssa.SSAInstruction; -import com.ibm.wala.ssa.SSANewInstruction; -import com.ibm.wala.ssa.SSAPutInstruction; -import com.ibm.wala.types.ClassLoaderReference; -import com.ibm.wala.types.FieldReference; -import com.ibm.wala.types.TypeReference; -import com.ibm.wala.util.collections.CompoundIterator; -import com.ibm.wala.util.collections.HashMapFactory; -import com.ibm.wala.util.collections.HashSetFactory; -import com.ibm.wala.util.collections.Iterator2Iterable; -import com.ibm.wala.util.collections.MapUtil; -import com.ibm.wala.util.debug.Assertions; -import com.ibm.wala.util.shrike.ShrikeUtil; - -/** - * @author sfink - * - */ -public class SimpleMemoryAccessMap implements MemoryAccessMap { - - private static final boolean DEBUG = false; - - /** - * if true, always use IR from CGNode when reasoning about method statements; otherwise, try to use bytecodes when possible. Note - * that current code may not work if set to false. - */ - private static final boolean ALWAYS_BUILD_IR = true; - - /** - * Map: IField -> Set - */ - final private Map> readMap = HashMapFactory.make(); - - /** - * Map: IField -> Set - */ - final private Map> writeMap = HashMapFactory.make(); - - final private Set arrayReads = HashSetFactory.make(); - - final private Set arrayWrites = HashSetFactory.make(); - - private final IClassHierarchy cha; - - private final boolean includePrimOps; - - private final HeapModel heapModel; - - public SimpleMemoryAccessMap(CallGraph cg, HeapModel heapModel, boolean includePrimOps) { - if (cg == null) { - throw new IllegalArgumentException("null cg"); - } - this.cha = cg.getClassHierarchy(); - this.heapModel = heapModel; - this.includePrimOps = includePrimOps; - populate(cg); - } - - private void populate(CallGraph cg) { - for (Iterator it = cg.iterator(); it.hasNext();) { - CGNode n = it.next(); - populate(n); - } - } - - private void populate(CGNode n) { - // we analyze bytecodes to avoid the cost of IR construction, except - // for synthetic methods, where we must use the synthetic IR - if (ALWAYS_BUILD_IR || n.getMethod().isSynthetic()) { - if (DEBUG) { - System.err.println("synthetic method"); - } - IR ir = n.getIR(); - if (ir == null) { - return; - } - SSAInstruction[] statements = ir.getInstructions(); - SSAMemoryAccessVisitor v = new SSAMemoryAccessVisitor(n); - for (int i = 0; i < statements.length; i++) { - SSAInstruction s = statements[i]; - if (s != null) { - v.setInstructionIndex(i); - s.visit(v); - } - } - - } else { - if (DEBUG) { - System.err.println("Shrike method"); - } - ShrikeCTMethod sm = (ShrikeCTMethod) n.getMethod(); - MemoryAccessVisitor v = new MemoryAccessVisitor(n.getMethod().getReference().getDeclaringClass().getClassLoader(), n); - try { - IInstruction[] statements = sm.getInstructions(); - if (statements == null) { - // System.err.println("no statements for " + n.getMethod()); - return; - } - if (DEBUG) { - for (int i = 0; i < statements.length; i++) { - System.err.println(i + ": " + statements[i]); - } - } - for (int i = 0; i < statements.length; i++) { - IInstruction s = statements[i]; - if (s != null) { - v.setInstructionIndex(i); - s.visit(v); - } - } - } catch (InvalidClassFileException e) { - e.printStackTrace(); - Assertions.UNREACHABLE(); - } - } - - } - - private class SSAMemoryAccessVisitor extends SSAInstruction.Visitor { - - private final CGNode node; - - private int instructionIndex; - - public SSAMemoryAccessVisitor(CGNode n) { - this.node = n; - } - - public void setInstructionIndex(int i) { - this.instructionIndex = i; - } - - @Override - public void visitNew(SSANewInstruction instruction) { - TypeReference declaredType = instruction.getNewSite().getDeclaredType(); - // check for multidimensional array - if (declaredType.isArrayType() && declaredType.getArrayElementType().isArrayType()) { - arrayWrites.add(new MemoryAccess(instructionIndex, node)); - } - - } - - @Override - public void visitArrayLoad(SSAArrayLoadInstruction instruction) { - if (!includePrimOps && instruction.typeIsPrimitive()) { - return; - } - arrayReads.add(new MemoryAccess(instructionIndex, node)); - } - - @Override - public void visitArrayStore(SSAArrayStoreInstruction instruction) { - if (!includePrimOps && instruction.typeIsPrimitive()) { - return; - } - arrayWrites.add(new MemoryAccess(instructionIndex, node)); - } - - @Override - public void visitGet(SSAGetInstruction instruction) { - if (!includePrimOps && instruction.getDeclaredFieldType().isPrimitiveType()) { - return; - } - FieldReference fr = instruction.getDeclaredField(); - IField f = cha.resolveField(fr); - if (f == null) { - return; - } - Set s = MapUtil.findOrCreateSet(readMap, f); - MemoryAccess fa = new MemoryAccess(instructionIndex, node); - s.add(fa); - } - - @Override - public void visitPut(SSAPutInstruction instruction) { - if (!includePrimOps && instruction.getDeclaredFieldType().isPrimitiveType()) { - return; - } - FieldReference fr = instruction.getDeclaredField(); - IField f = cha.resolveField(fr); - if (f == null) { - return; - } - Set s = MapUtil.findOrCreateSet(writeMap, f); - MemoryAccess fa = new MemoryAccess(instructionIndex, node); - s.add(fa); - } - - } - - private class MemoryAccessVisitor extends IInstruction.Visitor { - int instructionIndex; - - final ClassLoaderReference loader; - - final CGNode node; - - public MemoryAccessVisitor(ClassLoaderReference loader, CGNode node) { - super(); - this.loader = loader; - this.node = node; - } - - protected int getInstructionIndex() { - return instructionIndex; - } - - protected void setInstructionIndex(int instructionIndex) { - this.instructionIndex = instructionIndex; - } - - @Override - public void visitNew(NewInstruction instruction) { - TypeReference tr = ShrikeUtil.makeTypeReference(loader, instruction.getType()); - // chekc for multi-dimensional array allocation - if (tr.isArrayType() && tr.getArrayElementType().isArrayType()) { - if (DEBUG) { - System.err.println("found multi-dim array write at " + instructionIndex); - } - arrayWrites.add(new MemoryAccess(instructionIndex, node)); - } - } - - /* - * (non-Javadoc) - * - * @see com.ibm.shrikeBT.Instruction.Visitor#visitArrayLoad(com.ibm.shrikeBT.ArrayLoadInstruction) - */ - @Override - public void visitArrayLoad(IArrayLoadInstruction instruction) { - if (!includePrimOps) { - TypeReference tr = ShrikeUtil.makeTypeReference(loader, instruction.getType()); - // ISSUE is this the right check? - if (tr.isPrimitiveType()) { - return; - } - - } - arrayReads.add(new MemoryAccess(instructionIndex, node)); - } - - /* - * (non-Javadoc) - * - * @see com.ibm.shrikeBT.Instruction.Visitor#visitArrayStore(com.ibm.shrikeBT.ArrayStoreInstruction) - */ - @Override - public void visitArrayStore(IArrayStoreInstruction instruction) { - if (!includePrimOps) { - TypeReference tr = ShrikeUtil.makeTypeReference(loader, instruction.getType()); - if (tr.isPrimitiveType()) { - return; - } - } - - if (DEBUG) { - System.err.println("found array write at " + instructionIndex); - } - arrayWrites.add(new MemoryAccess(instructionIndex, node)); - } - - /* - * (non-Javadoc) - * - * @see com.ibm.shrikeBT.Instruction.Visitor#visitGet(com.ibm.shrikeBT.GetInstruction) - */ - @Override - public void visitGet(IGetInstruction instruction) { - FieldReference fr = FieldReference.findOrCreate(loader, instruction.getClassType(), instruction.getFieldName(), instruction - .getFieldType()); - if (!includePrimOps && fr.getFieldType().isPrimitiveType()) { - return; - } - IField f = cha.resolveField(fr); - if (f == null) { - return; - } - Set s = MapUtil.findOrCreateSet(readMap, f); - MemoryAccess fa = new MemoryAccess(instructionIndex, node); - s.add(fa); - } - - /* - * (non-Javadoc) - * - * @see com.ibm.shrikeBT.Instruction.Visitor#visitPut(com.ibm.shrikeBT.PutInstruction) - */ - @Override - public void visitPut(IPutInstruction instruction) { - FieldReference fr = FieldReference.findOrCreate(loader, instruction.getClassType(), instruction.getFieldName(), instruction - .getFieldType()); - if (!includePrimOps && fr.getFieldType().isPrimitiveType()) { - return; - } - IField f = cha.resolveField(fr); - if (f == null) { - return; - } - Set s = MapUtil.findOrCreateSet(writeMap, f); - MemoryAccess fa = new MemoryAccess(instructionIndex, node); - s.add(fa); - } - - } - - /* - * @see com.ibm.wala.demandpa.util.MemoryAccessMap#getFieldReads(com.ibm.wala.classLoader.IField) - */ - public Collection getFieldReads(PointerKey pk, IField field) { - Collection result = readMap.get(field); - if (result == null) { - return Collections.emptySet(); - } else { - return result; - } - } - - /* - * @see com.ibm.wala.demandpa.util.MemoryAccessMap#getFieldWrites(com.ibm.wala.classLoader.IField) - */ - public Collection getFieldWrites(PointerKey pk, IField field) { - Collection result = writeMap.get(field); - if (result == null) { - return Collections.emptySet(); - } else { - return result; - } - } - - /* - * @see com.ibm.wala.demandpa.util.MemoryAccessMap#getArrayReads() - */ - public Collection getArrayReads(PointerKey pk) { - return arrayReads; - } - - /* - * @see com.ibm.wala.demandpa.util.MemoryAccessMap#getArrayWrites() - */ - public Collection getArrayWrites(PointerKey pk) { - return arrayWrites; - } - - @Override - public String toString() { - StringBuffer result = new StringBuffer(); - - Collection allFields = HashSetFactory.make(); - allFields.addAll(readMap.keySet()); - allFields.addAll(writeMap.keySet()); - - for (Iterator it = allFields.iterator(); it.hasNext();) { - IField f = it.next(); - result.append("FIELD ").append(f).append(":\n"); - Collection reads = getFieldReads(null, f); - if (!reads.isEmpty()) { - result.append(" reads:\n"); - for (Iterator it2 = reads.iterator(); it2.hasNext();) { - result.append(" ").append(it2.next()).append("\n"); - } - } - Collection writes = getFieldWrites(null, f); - if (!writes.isEmpty()) { - result.append(" writes:\n"); - for (Iterator it2 = writes.iterator(); it2.hasNext();) { - result.append(" ").append(it2.next()).append("\n"); - } - } - } - - // arrays - result.append("ARRAY CONTENTS:\n"); - if (!arrayReads.isEmpty()) { - result.append(" reads:\n"); - for (Iterator it2 = arrayReads.iterator(); it2.hasNext();) { - result.append(" ").append(it2.next()).append("\n"); - } - } - if (!arrayWrites.isEmpty()) { - result.append(" writes:\n"); - for (Iterator it2 = arrayWrites.iterator(); it2.hasNext();) { - result.append(" ").append(it2.next()).append("\n"); - } - } - return result.toString(); - } - - public Collection getStaticFieldReads(IField field) { - return getFieldReads(null, field); - } - - public Collection getStaticFieldWrites(IField field) { - return getFieldWrites(null, field); - } - - public HeapModel getHeapModel() { - // NOTE: this memory access map actually makes no use of the heap model - return heapModel; - } - - public void repOk() { - for (MemoryAccess m : Iterator2Iterable.make(new CompoundIterator(arrayReads.iterator(), arrayWrites.iterator()))) { - CGNode node = m.getNode(); - IR ir = node.getIR(); - assert ir != null : "null IR for " + node + " but we have a memory access"; - SSAInstruction[] instructions = ir.getInstructions(); - int instructionIndex = m.getInstructionIndex(); - assert instructionIndex >= 0 && instructionIndex < instructions.length : "instruction index " + instructionIndex - + " out of range for " + node + ", which has " + instructions.length + " instructions"; - SSAInstruction s = instructions[m.getInstructionIndex()]; - if (s == null) { - // this is possible due to dead bytecodes - continue; - } - assert s instanceof SSAArrayReferenceInstruction || s instanceof SSANewInstruction : "bad type " + s.getClass() - + " for array access instruction"; - } - } +/******************************************************************************* + * Copyright (c) 2007 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.demandpa.util; + +import java.util.Collection; +import java.util.Collections; +import java.util.Iterator; +import java.util.Map; +import java.util.Set; + +import com.ibm.wala.classLoader.IField; +import com.ibm.wala.classLoader.ShrikeCTMethod; +import com.ibm.wala.ipa.callgraph.CGNode; +import com.ibm.wala.ipa.callgraph.CallGraph; +import com.ibm.wala.ipa.callgraph.propagation.HeapModel; +import com.ibm.wala.ipa.callgraph.propagation.PointerKey; +import com.ibm.wala.ipa.cha.IClassHierarchy; +import com.ibm.wala.shrikeBT.IArrayLoadInstruction; +import com.ibm.wala.shrikeBT.IArrayStoreInstruction; +import com.ibm.wala.shrikeBT.IGetInstruction; +import com.ibm.wala.shrikeBT.IInstruction; +import com.ibm.wala.shrikeBT.IPutInstruction; +import com.ibm.wala.shrikeBT.NewInstruction; +import com.ibm.wala.shrikeCT.InvalidClassFileException; +import com.ibm.wala.ssa.IR; +import com.ibm.wala.ssa.SSAArrayLoadInstruction; +import com.ibm.wala.ssa.SSAArrayReferenceInstruction; +import com.ibm.wala.ssa.SSAArrayStoreInstruction; +import com.ibm.wala.ssa.SSAGetInstruction; +import com.ibm.wala.ssa.SSAInstruction; +import com.ibm.wala.ssa.SSANewInstruction; +import com.ibm.wala.ssa.SSAPutInstruction; +import com.ibm.wala.types.ClassLoaderReference; +import com.ibm.wala.types.FieldReference; +import com.ibm.wala.types.TypeReference; +import com.ibm.wala.util.collections.CompoundIterator; +import com.ibm.wala.util.collections.HashMapFactory; +import com.ibm.wala.util.collections.HashSetFactory; +import com.ibm.wala.util.collections.Iterator2Iterable; +import com.ibm.wala.util.collections.MapUtil; +import com.ibm.wala.util.debug.Assertions; +import com.ibm.wala.util.shrike.ShrikeUtil; + +/** + * @author sfink + * + */ +public class SimpleMemoryAccessMap implements MemoryAccessMap { + + private static final boolean DEBUG = false; + + /** + * if true, always use IR from CGNode when reasoning about method statements; otherwise, try to use bytecodes when possible. Note + * that current code may not work if set to false. + */ + private static final boolean ALWAYS_BUILD_IR = true; + + /** + * Map: IField -> Set + */ + final private Map> readMap = HashMapFactory.make(); + + /** + * Map: IField -> Set + */ + final private Map> writeMap = HashMapFactory.make(); + + final private Set arrayReads = HashSetFactory.make(); + + final private Set arrayWrites = HashSetFactory.make(); + + private final IClassHierarchy cha; + + private final boolean includePrimOps; + + private final HeapModel heapModel; + + public SimpleMemoryAccessMap(CallGraph cg, HeapModel heapModel, boolean includePrimOps) { + if (cg == null) { + throw new IllegalArgumentException("null cg"); + } + this.cha = cg.getClassHierarchy(); + this.heapModel = heapModel; + this.includePrimOps = includePrimOps; + populate(cg); + } + + private void populate(CallGraph cg) { + for (Iterator it = cg.iterator(); it.hasNext();) { + CGNode n = it.next(); + populate(n); + } + } + + private void populate(CGNode n) { + // we analyze bytecodes to avoid the cost of IR construction, except + // for synthetic methods, where we must use the synthetic IR + if (ALWAYS_BUILD_IR || n.getMethod().isSynthetic()) { + if (DEBUG) { + System.err.println("synthetic method"); + } + IR ir = n.getIR(); + if (ir == null) { + return; + } + SSAInstruction[] statements = ir.getInstructions(); + SSAMemoryAccessVisitor v = new SSAMemoryAccessVisitor(n); + for (int i = 0; i < statements.length; i++) { + SSAInstruction s = statements[i]; + if (s != null) { + v.setInstructionIndex(i); + s.visit(v); + } + } + + } else { + if (DEBUG) { + System.err.println("Shrike method"); + } + ShrikeCTMethod sm = (ShrikeCTMethod) n.getMethod(); + MemoryAccessVisitor v = new MemoryAccessVisitor(n.getMethod().getReference().getDeclaringClass().getClassLoader(), n); + try { + IInstruction[] statements = sm.getInstructions(); + if (statements == null) { + // System.err.println("no statements for " + n.getMethod()); + return; + } + if (DEBUG) { + for (int i = 0; i < statements.length; i++) { + System.err.println(i + ": " + statements[i]); + } + } + for (int i = 0; i < statements.length; i++) { + IInstruction s = statements[i]; + if (s != null) { + v.setInstructionIndex(i); + s.visit(v); + } + } + } catch (InvalidClassFileException e) { + e.printStackTrace(); + Assertions.UNREACHABLE(); + } + } + + } + + private class SSAMemoryAccessVisitor extends SSAInstruction.Visitor { + + private final CGNode node; + + private int instructionIndex; + + public SSAMemoryAccessVisitor(CGNode n) { + this.node = n; + } + + public void setInstructionIndex(int i) { + this.instructionIndex = i; + } + + @Override + public void visitNew(SSANewInstruction instruction) { + TypeReference declaredType = instruction.getNewSite().getDeclaredType(); + // check for multidimensional array + if (declaredType.isArrayType() && declaredType.getArrayElementType().isArrayType()) { + arrayWrites.add(new MemoryAccess(instructionIndex, node)); + } + + } + + @Override + public void visitArrayLoad(SSAArrayLoadInstruction instruction) { + if (!includePrimOps && instruction.typeIsPrimitive()) { + return; + } + arrayReads.add(new MemoryAccess(instructionIndex, node)); + } + + @Override + public void visitArrayStore(SSAArrayStoreInstruction instruction) { + if (!includePrimOps && instruction.typeIsPrimitive()) { + return; + } + arrayWrites.add(new MemoryAccess(instructionIndex, node)); + } + + @Override + public void visitGet(SSAGetInstruction instruction) { + if (!includePrimOps && instruction.getDeclaredFieldType().isPrimitiveType()) { + return; + } + FieldReference fr = instruction.getDeclaredField(); + IField f = cha.resolveField(fr); + if (f == null) { + return; + } + Set s = MapUtil.findOrCreateSet(readMap, f); + MemoryAccess fa = new MemoryAccess(instructionIndex, node); + s.add(fa); + } + + @Override + public void visitPut(SSAPutInstruction instruction) { + if (!includePrimOps && instruction.getDeclaredFieldType().isPrimitiveType()) { + return; + } + FieldReference fr = instruction.getDeclaredField(); + IField f = cha.resolveField(fr); + if (f == null) { + return; + } + Set s = MapUtil.findOrCreateSet(writeMap, f); + MemoryAccess fa = new MemoryAccess(instructionIndex, node); + s.add(fa); + } + + } + + private class MemoryAccessVisitor extends IInstruction.Visitor { + int instructionIndex; + + final ClassLoaderReference loader; + + final CGNode node; + + public MemoryAccessVisitor(ClassLoaderReference loader, CGNode node) { + super(); + this.loader = loader; + this.node = node; + } + + protected int getInstructionIndex() { + return instructionIndex; + } + + protected void setInstructionIndex(int instructionIndex) { + this.instructionIndex = instructionIndex; + } + + @Override + public void visitNew(NewInstruction instruction) { + TypeReference tr = ShrikeUtil.makeTypeReference(loader, instruction.getType()); + // chekc for multi-dimensional array allocation + if (tr.isArrayType() && tr.getArrayElementType().isArrayType()) { + if (DEBUG) { + System.err.println("found multi-dim array write at " + instructionIndex); + } + arrayWrites.add(new MemoryAccess(instructionIndex, node)); + } + } + + /* + * (non-Javadoc) + * + * @see com.ibm.shrikeBT.Instruction.Visitor#visitArrayLoad(com.ibm.shrikeBT.ArrayLoadInstruction) + */ + @Override + public void visitArrayLoad(IArrayLoadInstruction instruction) { + if (!includePrimOps) { + TypeReference tr = ShrikeUtil.makeTypeReference(loader, instruction.getType()); + // ISSUE is this the right check? + if (tr.isPrimitiveType()) { + return; + } + + } + arrayReads.add(new MemoryAccess(instructionIndex, node)); + } + + /* + * (non-Javadoc) + * + * @see com.ibm.shrikeBT.Instruction.Visitor#visitArrayStore(com.ibm.shrikeBT.ArrayStoreInstruction) + */ + @Override + public void visitArrayStore(IArrayStoreInstruction instruction) { + if (!includePrimOps) { + TypeReference tr = ShrikeUtil.makeTypeReference(loader, instruction.getType()); + if (tr.isPrimitiveType()) { + return; + } + } + + if (DEBUG) { + System.err.println("found array write at " + instructionIndex); + } + arrayWrites.add(new MemoryAccess(instructionIndex, node)); + } + + /* + * (non-Javadoc) + * + * @see com.ibm.shrikeBT.Instruction.Visitor#visitGet(com.ibm.shrikeBT.GetInstruction) + */ + @Override + public void visitGet(IGetInstruction instruction) { + FieldReference fr = FieldReference.findOrCreate(loader, instruction.getClassType(), instruction.getFieldName(), instruction + .getFieldType()); + if (!includePrimOps && fr.getFieldType().isPrimitiveType()) { + return; + } + IField f = cha.resolveField(fr); + if (f == null) { + return; + } + Set s = MapUtil.findOrCreateSet(readMap, f); + MemoryAccess fa = new MemoryAccess(instructionIndex, node); + s.add(fa); + } + + /* + * (non-Javadoc) + * + * @see com.ibm.shrikeBT.Instruction.Visitor#visitPut(com.ibm.shrikeBT.PutInstruction) + */ + @Override + public void visitPut(IPutInstruction instruction) { + FieldReference fr = FieldReference.findOrCreate(loader, instruction.getClassType(), instruction.getFieldName(), instruction + .getFieldType()); + if (!includePrimOps && fr.getFieldType().isPrimitiveType()) { + return; + } + IField f = cha.resolveField(fr); + if (f == null) { + return; + } + Set s = MapUtil.findOrCreateSet(writeMap, f); + MemoryAccess fa = new MemoryAccess(instructionIndex, node); + s.add(fa); + } + + } + + /* + * @see com.ibm.wala.demandpa.util.MemoryAccessMap#getFieldReads(com.ibm.wala.classLoader.IField) + */ + public Collection getFieldReads(PointerKey pk, IField field) { + Collection result = readMap.get(field); + if (result == null) { + return Collections.emptySet(); + } else { + return result; + } + } + + /* + * @see com.ibm.wala.demandpa.util.MemoryAccessMap#getFieldWrites(com.ibm.wala.classLoader.IField) + */ + public Collection getFieldWrites(PointerKey pk, IField field) { + Collection result = writeMap.get(field); + if (result == null) { + return Collections.emptySet(); + } else { + return result; + } + } + + /* + * @see com.ibm.wala.demandpa.util.MemoryAccessMap#getArrayReads() + */ + public Collection getArrayReads(PointerKey pk) { + return arrayReads; + } + + /* + * @see com.ibm.wala.demandpa.util.MemoryAccessMap#getArrayWrites() + */ + public Collection getArrayWrites(PointerKey pk) { + return arrayWrites; + } + + @Override + public String toString() { + StringBuffer result = new StringBuffer(); + + Collection allFields = HashSetFactory.make(); + allFields.addAll(readMap.keySet()); + allFields.addAll(writeMap.keySet()); + + for (Iterator it = allFields.iterator(); it.hasNext();) { + IField f = it.next(); + result.append("FIELD ").append(f).append(":\n"); + Collection reads = getFieldReads(null, f); + if (!reads.isEmpty()) { + result.append(" reads:\n"); + for (Iterator it2 = reads.iterator(); it2.hasNext();) { + result.append(" ").append(it2.next()).append("\n"); + } + } + Collection writes = getFieldWrites(null, f); + if (!writes.isEmpty()) { + result.append(" writes:\n"); + for (Iterator it2 = writes.iterator(); it2.hasNext();) { + result.append(" ").append(it2.next()).append("\n"); + } + } + } + + // arrays + result.append("ARRAY CONTENTS:\n"); + if (!arrayReads.isEmpty()) { + result.append(" reads:\n"); + for (Iterator it2 = arrayReads.iterator(); it2.hasNext();) { + result.append(" ").append(it2.next()).append("\n"); + } + } + if (!arrayWrites.isEmpty()) { + result.append(" writes:\n"); + for (Iterator it2 = arrayWrites.iterator(); it2.hasNext();) { + result.append(" ").append(it2.next()).append("\n"); + } + } + return result.toString(); + } + + public Collection getStaticFieldReads(IField field) { + return getFieldReads(null, field); + } + + public Collection getStaticFieldWrites(IField field) { + return getFieldWrites(null, field); + } + + public HeapModel getHeapModel() { + // NOTE: this memory access map actually makes no use of the heap model + return heapModel; + } + + public void repOk() { + for (MemoryAccess m : Iterator2Iterable.make(new CompoundIterator(arrayReads.iterator(), arrayWrites.iterator()))) { + CGNode node = m.getNode(); + IR ir = node.getIR(); + assert ir != null : "null IR for " + node + " but we have a memory access"; + SSAInstruction[] instructions = ir.getInstructions(); + int instructionIndex = m.getInstructionIndex(); + assert instructionIndex >= 0 && instructionIndex < instructions.length : "instruction index " + instructionIndex + + " out of range for " + node + ", which has " + instructions.length + " instructions"; + SSAInstruction s = instructions[m.getInstructionIndex()]; + if (s == null) { + // this is possible due to dead bytecodes + continue; + } + assert s instanceof SSAArrayReferenceInstruction || s instanceof SSANewInstruction : "bad type " + s.getClass() + + " for array access instruction"; + } + } } \ No newline at end of file diff --git a/com.ibm.wala.core/src/com/ibm/wala/escape/FILiveObjectAnalysis.java b/com.ibm.wala.core/src/com/ibm/wala/escape/FILiveObjectAnalysis.java index f96ee71c3..64e008714 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/escape/FILiveObjectAnalysis.java +++ b/com.ibm.wala.core/src/com/ibm/wala/escape/FILiveObjectAnalysis.java @@ -1,203 +1,203 @@ -/******************************************************************************* - * 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.escape; - -import java.util.Collections; -import java.util.Iterator; -import java.util.Map; -import java.util.Set; - -import com.ibm.wala.analysis.pointers.HeapGraph; -import com.ibm.wala.classLoader.NewSiteReference; -import com.ibm.wala.ipa.callgraph.CGNode; -import com.ibm.wala.ipa.callgraph.CallGraph; -import com.ibm.wala.ipa.callgraph.propagation.AbstractLocalPointerKey; -import com.ibm.wala.ipa.callgraph.propagation.InstanceKey; -import com.ibm.wala.ipa.callgraph.propagation.LocalPointerKey; -import com.ibm.wala.ipa.callgraph.propagation.PropagationCallGraphBuilder.TypedPointerKey; -import com.ibm.wala.ipa.callgraph.propagation.StaticFieldKey; -import com.ibm.wala.ssa.DefUse; -import com.ibm.wala.ssa.IR; -import com.ibm.wala.util.WalaException; -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.graph.impl.GraphInverter; -import com.ibm.wala.util.graph.traverse.DFS; -import com.ibm.wala.util.intset.IntIterator; -import com.ibm.wala.util.intset.IntSet; - -/** - * A simple liveness analysis based on flow-insensitive pointer analysis - */ -public class FILiveObjectAnalysis implements ILiveObjectAnalysis { - - /** - * governing call graph - */ - private final CallGraph callGraph; - - /** - * Graph view of pointer analysis results - */ - private final HeapGraph heapGraph; - - /** - * Cached map from InstanceKey -> Set - */ - final private Map> liveNodes = HashMapFactory.make(); - - /** - * Set of instanceKeys which are live everywhere - */ - final private Set liveEverywhere = HashSetFactory.make(); - - /** - * A hack for now .. since right now the intraprocedural analysis is expensive - */ - private final boolean expensiveIntraproceduralAnalysis; - - /** - * - */ - public FILiveObjectAnalysis(CallGraph callGraph, HeapGraph heapGraph, boolean expensiveIntraproceduralAnalysis) { - super(); - this.callGraph = callGraph; - this.heapGraph = heapGraph; - this.expensiveIntraproceduralAnalysis = expensiveIntraproceduralAnalysis; - } - - public boolean mayBeLive(CGNode allocMethod, int allocPC, CGNode m, int instructionIndex) throws IllegalArgumentException, - WalaException { - if (allocMethod == null) { - throw new IllegalArgumentException("allocMethod == null"); - } - NewSiteReference site = TrivialMethodEscape.findAlloc(allocMethod, allocPC); - InstanceKey ik = heapGraph.getHeapModel().getInstanceKeyForAllocation(allocMethod, site); - return mayBeLive(ik, m, instructionIndex); - } - - /** - * @param instructionIndex index of an SSA instruction - */ - public boolean mayBeLive(InstanceKey ik, CGNode m, int instructionIndex) { - if (liveEverywhere.contains(ik)) { - return true; - } else { - Set live = liveNodes.get(ik); - if (live != null) { - if (live.contains(m)) { - if (instructionIndex == -1) { - return true; - } else { - if (mayBeLiveInSomeCaller(ik, m)) { - // a hack. if it's live in some caller of m, assume it's live - // throughout m. this may be imprecise. - return true; - } else { - if (expensiveIntraproceduralAnalysis) { - return mayBeLiveIntraprocedural(ik, m, instructionIndex); - } else { - // be conservative - return true; - } - } - } - } else { - return false; - } - } else { - live = computeLiveNodes(ik); - liveNodes.put(ik, live); - return mayBeLive(ik, m, instructionIndex); - } - } - } - - private boolean mayBeLiveInSomeCaller(InstanceKey ik, CGNode m) { - for (Iterator it = callGraph.getPredNodes(m); it.hasNext();) { - CGNode n = (CGNode) it.next(); - if (mayBeLive(ik, n, -1)) { - return true; - } - } - return false; - } - - /** - * precondition: !mayBeLiveInSomeCaller(ik, m) - * - * @param instructionIndex index of an SSA instruction - */ - private boolean mayBeLiveIntraprocedural(InstanceKey ik, CGNode m, int instructionIndex) { - - IR ir = m.getIR(); - DefUse du = m.getDU(); - - for (Iterator it = DFS.iterateDiscoverTime(GraphInverter.invert(heapGraph), ik); it.hasNext();) { - Object p = it.next(); - if (p instanceof LocalPointerKey) { - LocalPointerKey lpk = (LocalPointerKey) p; - if (lpk.getNode().equals(m)) { - if (LocalLiveRangeAnalysis.isLive(lpk.getValueNumber(), instructionIndex, ir, du)) { - return true; - } - } - } - } - return false; - } - - /** - * Compute the set of nodes in which ik may be live. If it's live everywhere, return an EMPTY_SET, but also record this fact in - * the "liveEverywhere" set as a side effect - */ - private Set computeLiveNodes(InstanceKey ik) { - Set localRootNodes = HashSetFactory.make(); - for (Iterator it = DFS.iterateDiscoverTime(GraphInverter.invert(heapGraph), ik); it.hasNext();) { - Object node = it.next(); - if (node instanceof StaticFieldKey) { - liveEverywhere.add(ik); - return Collections.emptySet(); - } else { - if (node instanceof AbstractLocalPointerKey) { - AbstractLocalPointerKey local = (AbstractLocalPointerKey) node; - localRootNodes.add(local.getNode()); - } else if (node instanceof TypedPointerKey) { - TypedPointerKey t = (TypedPointerKey) node; - node = t.getBase(); - if (node instanceof AbstractLocalPointerKey) { - AbstractLocalPointerKey local = (AbstractLocalPointerKey) node; - localRootNodes.add(local.getNode()); - } else { - Assertions.UNREACHABLE("unexpected base of TypedPointerKey: " + node.getClass() + " " + node); - } - } - } - } - return DFS.getReachableNodes(callGraph, localRootNodes); - } - - public boolean mayBeLive(InstanceKey ik, CGNode m, IntSet instructionIndices) { - if (instructionIndices == null) { - throw new IllegalArgumentException("instructionIndices is null"); - } - // TODO this sucks - for (IntIterator it = instructionIndices.intIterator(); it.hasNext();) { - int i = it.next(); - if (mayBeLive(ik, m, i)) { - return true; - } - } - return false; - } - -} +/******************************************************************************* + * 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.escape; + +import java.util.Collections; +import java.util.Iterator; +import java.util.Map; +import java.util.Set; + +import com.ibm.wala.analysis.pointers.HeapGraph; +import com.ibm.wala.classLoader.NewSiteReference; +import com.ibm.wala.ipa.callgraph.CGNode; +import com.ibm.wala.ipa.callgraph.CallGraph; +import com.ibm.wala.ipa.callgraph.propagation.AbstractLocalPointerKey; +import com.ibm.wala.ipa.callgraph.propagation.InstanceKey; +import com.ibm.wala.ipa.callgraph.propagation.LocalPointerKey; +import com.ibm.wala.ipa.callgraph.propagation.PropagationCallGraphBuilder.TypedPointerKey; +import com.ibm.wala.ipa.callgraph.propagation.StaticFieldKey; +import com.ibm.wala.ssa.DefUse; +import com.ibm.wala.ssa.IR; +import com.ibm.wala.util.WalaException; +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.graph.impl.GraphInverter; +import com.ibm.wala.util.graph.traverse.DFS; +import com.ibm.wala.util.intset.IntIterator; +import com.ibm.wala.util.intset.IntSet; + +/** + * A simple liveness analysis based on flow-insensitive pointer analysis + */ +public class FILiveObjectAnalysis implements ILiveObjectAnalysis { + + /** + * governing call graph + */ + private final CallGraph callGraph; + + /** + * Graph view of pointer analysis results + */ + private final HeapGraph heapGraph; + + /** + * Cached map from InstanceKey -> Set + */ + final private Map> liveNodes = HashMapFactory.make(); + + /** + * Set of instanceKeys which are live everywhere + */ + final private Set liveEverywhere = HashSetFactory.make(); + + /** + * A hack for now .. since right now the intraprocedural analysis is expensive + */ + private final boolean expensiveIntraproceduralAnalysis; + + /** + * + */ + public FILiveObjectAnalysis(CallGraph callGraph, HeapGraph heapGraph, boolean expensiveIntraproceduralAnalysis) { + super(); + this.callGraph = callGraph; + this.heapGraph = heapGraph; + this.expensiveIntraproceduralAnalysis = expensiveIntraproceduralAnalysis; + } + + public boolean mayBeLive(CGNode allocMethod, int allocPC, CGNode m, int instructionIndex) throws IllegalArgumentException, + WalaException { + if (allocMethod == null) { + throw new IllegalArgumentException("allocMethod == null"); + } + NewSiteReference site = TrivialMethodEscape.findAlloc(allocMethod, allocPC); + InstanceKey ik = heapGraph.getHeapModel().getInstanceKeyForAllocation(allocMethod, site); + return mayBeLive(ik, m, instructionIndex); + } + + /** + * @param instructionIndex index of an SSA instruction + */ + public boolean mayBeLive(InstanceKey ik, CGNode m, int instructionIndex) { + if (liveEverywhere.contains(ik)) { + return true; + } else { + Set live = liveNodes.get(ik); + if (live != null) { + if (live.contains(m)) { + if (instructionIndex == -1) { + return true; + } else { + if (mayBeLiveInSomeCaller(ik, m)) { + // a hack. if it's live in some caller of m, assume it's live + // throughout m. this may be imprecise. + return true; + } else { + if (expensiveIntraproceduralAnalysis) { + return mayBeLiveIntraprocedural(ik, m, instructionIndex); + } else { + // be conservative + return true; + } + } + } + } else { + return false; + } + } else { + live = computeLiveNodes(ik); + liveNodes.put(ik, live); + return mayBeLive(ik, m, instructionIndex); + } + } + } + + private boolean mayBeLiveInSomeCaller(InstanceKey ik, CGNode m) { + for (Iterator it = callGraph.getPredNodes(m); it.hasNext();) { + CGNode n = (CGNode) it.next(); + if (mayBeLive(ik, n, -1)) { + return true; + } + } + return false; + } + + /** + * precondition: !mayBeLiveInSomeCaller(ik, m) + * + * @param instructionIndex index of an SSA instruction + */ + private boolean mayBeLiveIntraprocedural(InstanceKey ik, CGNode m, int instructionIndex) { + + IR ir = m.getIR(); + DefUse du = m.getDU(); + + for (Iterator it = DFS.iterateDiscoverTime(GraphInverter.invert(heapGraph), ik); it.hasNext();) { + Object p = it.next(); + if (p instanceof LocalPointerKey) { + LocalPointerKey lpk = (LocalPointerKey) p; + if (lpk.getNode().equals(m)) { + if (LocalLiveRangeAnalysis.isLive(lpk.getValueNumber(), instructionIndex, ir, du)) { + return true; + } + } + } + } + return false; + } + + /** + * Compute the set of nodes in which ik may be live. If it's live everywhere, return an EMPTY_SET, but also record this fact in + * the "liveEverywhere" set as a side effect + */ + private Set computeLiveNodes(InstanceKey ik) { + Set localRootNodes = HashSetFactory.make(); + for (Iterator it = DFS.iterateDiscoverTime(GraphInverter.invert(heapGraph), ik); it.hasNext();) { + Object node = it.next(); + if (node instanceof StaticFieldKey) { + liveEverywhere.add(ik); + return Collections.emptySet(); + } else { + if (node instanceof AbstractLocalPointerKey) { + AbstractLocalPointerKey local = (AbstractLocalPointerKey) node; + localRootNodes.add(local.getNode()); + } else if (node instanceof TypedPointerKey) { + TypedPointerKey t = (TypedPointerKey) node; + node = t.getBase(); + if (node instanceof AbstractLocalPointerKey) { + AbstractLocalPointerKey local = (AbstractLocalPointerKey) node; + localRootNodes.add(local.getNode()); + } else { + Assertions.UNREACHABLE("unexpected base of TypedPointerKey: " + node.getClass() + " " + node); + } + } + } + } + return DFS.getReachableNodes(callGraph, localRootNodes); + } + + public boolean mayBeLive(InstanceKey ik, CGNode m, IntSet instructionIndices) { + if (instructionIndices == null) { + throw new IllegalArgumentException("instructionIndices is null"); + } + // TODO this sucks + for (IntIterator it = instructionIndices.intIterator(); it.hasNext();) { + int i = it.next(); + if (mayBeLive(ik, m, i)) { + return true; + } + } + return false; + } + +} diff --git a/com.ibm.wala.core/src/com/ibm/wala/escape/ILiveObjectAnalysis.java b/com.ibm.wala.core/src/com/ibm/wala/escape/ILiveObjectAnalysis.java index c406903f8..965059a26 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/escape/ILiveObjectAnalysis.java +++ b/com.ibm.wala.core/src/com/ibm/wala/escape/ILiveObjectAnalysis.java @@ -1,53 +1,53 @@ -/******************************************************************************* - * Copyright (c) 2002 - 2006 IBM Corporation. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * IBM Corporation - initial API and implementation - *******************************************************************************/ -package com.ibm.wala.escape; - -import com.ibm.wala.ipa.callgraph.CGNode; -import com.ibm.wala.ipa.callgraph.propagation.InstanceKey; -import com.ibm.wala.util.WalaException; -import com.ibm.wala.util.intset.IntSet; - -/** - * Basic interface for liveness analysis of heap-allocated objects - */ -public interface ILiveObjectAnalysis { - - /** - * @param allocMethod a method which holds an allocation site - * @param allocPC bytecode index of allocation site - * @param m method in question - * @param instructionIndex index of an instruction in SSA IR. in m. if -1, it is interpreted as a wildcard meaning "any statement" - * @throws WalaException - * @returns true if an object allocated at the allocation site <allocMethod,allocPC> may be live immediately after the - * statement - */ - public boolean mayBeLive(CGNode allocMethod, int allocPC, CGNode m, int instructionIndex) throws WalaException; - - /** - * @param ik an instance key - * @param m method in question - * @param instructionIndex index of an instruction in SSA IR. in m. if -1, it is interpreted as a wildcard meaning "any statement" - * @throws WalaException - * @returns true if an object allocated at the allocation site <allocMethod,allocPC> may be live immediately after the - * statement - */ - public boolean mayBeLive(InstanceKey ik, CGNode m, int instructionIndex) throws WalaException; - - /** - * @param ik an instance key - * @param m method in question - * @param instructionIndices indices of instructions in SSA IR. - * @returns true if an object allocated at the allocation site <allocMethod,allocPC> may be live immediately after the - * statement for any instructionIndex in the set - */ - public boolean mayBeLive(InstanceKey ik, CGNode m, IntSet instructionIndices); - -} +/******************************************************************************* + * 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.escape; + +import com.ibm.wala.ipa.callgraph.CGNode; +import com.ibm.wala.ipa.callgraph.propagation.InstanceKey; +import com.ibm.wala.util.WalaException; +import com.ibm.wala.util.intset.IntSet; + +/** + * Basic interface for liveness analysis of heap-allocated objects + */ +public interface ILiveObjectAnalysis { + + /** + * @param allocMethod a method which holds an allocation site + * @param allocPC bytecode index of allocation site + * @param m method in question + * @param instructionIndex index of an instruction in SSA IR. in m. if -1, it is interpreted as a wildcard meaning "any statement" + * @throws WalaException + * @returns true if an object allocated at the allocation site <allocMethod,allocPC> may be live immediately after the + * statement + */ + public boolean mayBeLive(CGNode allocMethod, int allocPC, CGNode m, int instructionIndex) throws WalaException; + + /** + * @param ik an instance key + * @param m method in question + * @param instructionIndex index of an instruction in SSA IR. in m. if -1, it is interpreted as a wildcard meaning "any statement" + * @throws WalaException + * @returns true if an object allocated at the allocation site <allocMethod,allocPC> may be live immediately after the + * statement + */ + public boolean mayBeLive(InstanceKey ik, CGNode m, int instructionIndex) throws WalaException; + + /** + * @param ik an instance key + * @param m method in question + * @param instructionIndices indices of instructions in SSA IR. + * @returns true if an object allocated at the allocation site <allocMethod,allocPC> may be live immediately after the + * statement for any instructionIndex in the set + */ + public boolean mayBeLive(InstanceKey ik, CGNode m, IntSet instructionIndices); + +} diff --git a/com.ibm.wala.core/src/com/ibm/wala/escape/IMethodEscapeAnalysis.java b/com.ibm.wala.core/src/com/ibm/wala/escape/IMethodEscapeAnalysis.java index c403eb8ae..ce907c03a 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/escape/IMethodEscapeAnalysis.java +++ b/com.ibm.wala.core/src/com/ibm/wala/escape/IMethodEscapeAnalysis.java @@ -1,30 +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.escape; - -import com.ibm.wala.types.MethodReference; -import com.ibm.wala.util.WalaException; - -/** - * Basic interface from which to execute and get the results of escape analysis - */ -public interface IMethodEscapeAnalysis { - - /** - * @param allocMethod a method which holds an allocation site - * @param allocPC bytecode index of allocation site - * @param m method in question - * @returns true if an object allocated at the allocation site <allocMethod,allocPC> may escape from an activation of method m, - * false otherwise - */ - public boolean mayEscape(MethodReference allocMethod, int allocPC, MethodReference m) throws WalaException; - -} +/******************************************************************************* + * 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.escape; + +import com.ibm.wala.types.MethodReference; +import com.ibm.wala.util.WalaException; + +/** + * Basic interface from which to execute and get the results of escape analysis + */ +public interface IMethodEscapeAnalysis { + + /** + * @param allocMethod a method which holds an allocation site + * @param allocPC bytecode index of allocation site + * @param m method in question + * @returns true if an object allocated at the allocation site <allocMethod,allocPC> may escape from an activation of method m, + * false otherwise + */ + public boolean mayEscape(MethodReference allocMethod, int allocPC, MethodReference m) throws WalaException; + +} diff --git a/com.ibm.wala.core/src/com/ibm/wala/escape/INodeEscapeAnalysis.java b/com.ibm.wala.core/src/com/ibm/wala/escape/INodeEscapeAnalysis.java index 33652875f..96b52cc99 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/escape/INodeEscapeAnalysis.java +++ b/com.ibm.wala.core/src/com/ibm/wala/escape/INodeEscapeAnalysis.java @@ -1,31 +1,31 @@ -/******************************************************************************* - * 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.escape; - -import com.ibm.wala.ipa.callgraph.CGNode; -import com.ibm.wala.util.WalaException; - -/** - * Basic interface from which to execute and get the results of escape analysis - */ -public interface INodeEscapeAnalysis extends IMethodEscapeAnalysis { - - /** - * @param allocNode a CGNode which holds an allocation site - * @param allocPC bytecode index of allocation site - * @param node method in question - * @throws WalaException - * @returns true if an object allocated at the allocation site <allocMethod,allocPC> may escape from an activation of node m, - * false otherwise - */ - public boolean mayEscape(CGNode allocNode, int allocPC, CGNode node) throws WalaException; - -} +/******************************************************************************* + * 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.escape; + +import com.ibm.wala.ipa.callgraph.CGNode; +import com.ibm.wala.util.WalaException; + +/** + * Basic interface from which to execute and get the results of escape analysis + */ +public interface INodeEscapeAnalysis extends IMethodEscapeAnalysis { + + /** + * @param allocNode a CGNode which holds an allocation site + * @param allocPC bytecode index of allocation site + * @param node method in question + * @throws WalaException + * @returns true if an object allocated at the allocation site <allocMethod,allocPC> may escape from an activation of node m, + * false otherwise + */ + public boolean mayEscape(CGNode allocNode, int allocPC, CGNode node) throws WalaException; + +} diff --git a/com.ibm.wala.core/src/com/ibm/wala/escape/LocalLiveRangeAnalysis.java b/com.ibm.wala.core/src/com/ibm/wala/escape/LocalLiveRangeAnalysis.java index 625c5b28e..cbe434910 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/escape/LocalLiveRangeAnalysis.java +++ b/com.ibm.wala.core/src/com/ibm/wala/escape/LocalLiveRangeAnalysis.java @@ -1,156 +1,156 @@ -/******************************************************************************* - * 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.escape; - -import java.util.Collection; -import java.util.Collections; -import java.util.Iterator; - -import com.ibm.wala.ssa.DefUse; -import com.ibm.wala.ssa.IR; -import com.ibm.wala.ssa.ISSABasicBlock; -import com.ibm.wala.ssa.SSACFG; -import com.ibm.wala.ssa.SSACFG.BasicBlock; -import com.ibm.wala.ssa.SSAInstruction; -import com.ibm.wala.ssa.SSAReturnInstruction; -import com.ibm.wala.util.collections.Filter; -import com.ibm.wala.util.collections.HashSetFactory; -import com.ibm.wala.util.collections.Iterator2Collection; -import com.ibm.wala.util.debug.Assertions; -import com.ibm.wala.util.graph.traverse.DFS; - -/** - * Intraprocedural SSA-based live range analysis. This is horribly inefficient. - * - */ -public class LocalLiveRangeAnalysis { - - /** - * Is the variable with value number v live immediately after a particular instruction index? - * - * Algorithm: returns true if there is a path from pc to some use of v that does not traverse the def of v - * - * @param instructionIndex index of an instruction in the IR - * @throws IllegalArgumentException if du is null - */ - public static boolean isLive(int v, int instructionIndex, IR ir, DefUse du) { - if (du == null) { - throw new IllegalArgumentException("du is null"); - } - if (du.getNumberOfUses(v) == 0) { - return false; - } - if (instructionIndex < 0) { - Assertions.UNREACHABLE(); - } - ISSABasicBlock queryBlock = findBlock(ir, instructionIndex); - SSAInstruction def = du.getDef(v); - final SSACFG.BasicBlock defBlock = def == null ? null : findBlock(ir, def); - final Collection uses = findBlocks(ir, du.getUses(v)); - - // a filter which accepts everything but the block which defs v - Filter notDef = new Filter() { - public boolean accepts(Object o) { - return (defBlock == null || !defBlock.equals(o)); - } - }; - - if (defBlock != null && defBlock.equals(queryBlock)) { - // for now, conservatively say it's live. fix this later if necessary. - return true; - } else { - Collection reached = DFS.getReachableNodes(ir.getControlFlowGraph(), Collections.singleton(queryBlock), notDef); - uses.retainAll(reached); - if (uses.isEmpty()) { - return false; - } else if (uses.size() == 1 && uses.iterator().next().equals(queryBlock)) { - if (instructionIndex == queryBlock.getLastInstructionIndex()) { - // the query is for the last instruction. There can be no more uses - // following the block, so: - // not quite true for return instructions. - if (ir.getInstructions()[instructionIndex] instanceof SSAReturnInstruction) { - return true; - } else { - return false; - } - } else { - // todo: be more aggressive. - // there may be more uses after the query, so conservatively assume it - // may be live - return true; - } - } else { - return true; - } - } - } - - /** - * @param statements Iterator - */ - private static Collection findBlocks(IR ir, Iterator statements) { - Collection s = Iterator2Collection.toSet(statements); - Collection result = HashSetFactory.make(); - outer: for (Iterator it = ir.getControlFlowGraph().iterator(); it.hasNext();) { - SSACFG.BasicBlock b = (SSACFG.BasicBlock) it.next(); - for (Iterator it2 = b.iterator(); it2.hasNext();) { - SSAInstruction x = (SSAInstruction) it2.next(); - if (s.contains(x)) { - result.add(b); - continue outer; - } - } - } - if (result.isEmpty()) { - Assertions.UNREACHABLE(); - } - return result; - } - - /** - * This is horribly inefficient. - * - * @return the basic block which contains the instruction - */ - private static SSACFG.BasicBlock findBlock(IR ir, SSAInstruction s) { - if (s == null) { - Assertions.UNREACHABLE(); - } - for (Iterator it = ir.getControlFlowGraph().iterator(); it.hasNext();) { - SSACFG.BasicBlock b = (SSACFG.BasicBlock) it.next(); - for (Iterator it2 = b.iterator(); it2.hasNext();) { - SSAInstruction x = (SSAInstruction) it2.next(); - if (s.equals(x)) { - return b; - } - } - } - Assertions.UNREACHABLE("no block for " + s + " in IR " + ir); - return null; - } - - /** - * This is horribly inefficient. - * - * @return the basic block which contains the ith instruction - */ - private static ISSABasicBlock findBlock(IR ir, int i) { - for (Iterator it = ir.getControlFlowGraph().iterator(); it.hasNext();) { - SSACFG.BasicBlock b = (SSACFG.BasicBlock) it.next(); - if (i >= b.getFirstInstructionIndex() && i <= b.getLastInstructionIndex()) { - return b; - } - } - Assertions.UNREACHABLE("no block for " + i + " in IR " + ir); - return null; - } - -} +/******************************************************************************* + * 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.escape; + +import java.util.Collection; +import java.util.Collections; +import java.util.Iterator; + +import com.ibm.wala.ssa.DefUse; +import com.ibm.wala.ssa.IR; +import com.ibm.wala.ssa.ISSABasicBlock; +import com.ibm.wala.ssa.SSACFG; +import com.ibm.wala.ssa.SSACFG.BasicBlock; +import com.ibm.wala.ssa.SSAInstruction; +import com.ibm.wala.ssa.SSAReturnInstruction; +import com.ibm.wala.util.collections.Filter; +import com.ibm.wala.util.collections.HashSetFactory; +import com.ibm.wala.util.collections.Iterator2Collection; +import com.ibm.wala.util.debug.Assertions; +import com.ibm.wala.util.graph.traverse.DFS; + +/** + * Intraprocedural SSA-based live range analysis. This is horribly inefficient. + * + */ +public class LocalLiveRangeAnalysis { + + /** + * Is the variable with value number v live immediately after a particular instruction index? + * + * Algorithm: returns true if there is a path from pc to some use of v that does not traverse the def of v + * + * @param instructionIndex index of an instruction in the IR + * @throws IllegalArgumentException if du is null + */ + public static boolean isLive(int v, int instructionIndex, IR ir, DefUse du) { + if (du == null) { + throw new IllegalArgumentException("du is null"); + } + if (du.getNumberOfUses(v) == 0) { + return false; + } + if (instructionIndex < 0) { + Assertions.UNREACHABLE(); + } + ISSABasicBlock queryBlock = findBlock(ir, instructionIndex); + SSAInstruction def = du.getDef(v); + final SSACFG.BasicBlock defBlock = def == null ? null : findBlock(ir, def); + final Collection uses = findBlocks(ir, du.getUses(v)); + + // a filter which accepts everything but the block which defs v + Filter notDef = new Filter() { + public boolean accepts(Object o) { + return (defBlock == null || !defBlock.equals(o)); + } + }; + + if (defBlock != null && defBlock.equals(queryBlock)) { + // for now, conservatively say it's live. fix this later if necessary. + return true; + } else { + Collection reached = DFS.getReachableNodes(ir.getControlFlowGraph(), Collections.singleton(queryBlock), notDef); + uses.retainAll(reached); + if (uses.isEmpty()) { + return false; + } else if (uses.size() == 1 && uses.iterator().next().equals(queryBlock)) { + if (instructionIndex == queryBlock.getLastInstructionIndex()) { + // the query is for the last instruction. There can be no more uses + // following the block, so: + // not quite true for return instructions. + if (ir.getInstructions()[instructionIndex] instanceof SSAReturnInstruction) { + return true; + } else { + return false; + } + } else { + // todo: be more aggressive. + // there may be more uses after the query, so conservatively assume it + // may be live + return true; + } + } else { + return true; + } + } + } + + /** + * @param statements Iterator + */ + private static Collection findBlocks(IR ir, Iterator statements) { + Collection s = Iterator2Collection.toSet(statements); + Collection result = HashSetFactory.make(); + outer: for (Iterator it = ir.getControlFlowGraph().iterator(); it.hasNext();) { + SSACFG.BasicBlock b = (SSACFG.BasicBlock) it.next(); + for (Iterator it2 = b.iterator(); it2.hasNext();) { + SSAInstruction x = (SSAInstruction) it2.next(); + if (s.contains(x)) { + result.add(b); + continue outer; + } + } + } + if (result.isEmpty()) { + Assertions.UNREACHABLE(); + } + return result; + } + + /** + * This is horribly inefficient. + * + * @return the basic block which contains the instruction + */ + private static SSACFG.BasicBlock findBlock(IR ir, SSAInstruction s) { + if (s == null) { + Assertions.UNREACHABLE(); + } + for (Iterator it = ir.getControlFlowGraph().iterator(); it.hasNext();) { + SSACFG.BasicBlock b = (SSACFG.BasicBlock) it.next(); + for (Iterator it2 = b.iterator(); it2.hasNext();) { + SSAInstruction x = (SSAInstruction) it2.next(); + if (s.equals(x)) { + return b; + } + } + } + Assertions.UNREACHABLE("no block for " + s + " in IR " + ir); + return null; + } + + /** + * This is horribly inefficient. + * + * @return the basic block which contains the ith instruction + */ + private static ISSABasicBlock findBlock(IR ir, int i) { + for (Iterator it = ir.getControlFlowGraph().iterator(); it.hasNext();) { + SSACFG.BasicBlock b = (SSACFG.BasicBlock) it.next(); + if (i >= b.getFirstInstructionIndex() && i <= b.getLastInstructionIndex()) { + return b; + } + } + Assertions.UNREACHABLE("no block for " + i + " in IR " + ir); + return null; + } + +} diff --git a/com.ibm.wala.core/src/com/ibm/wala/escape/TrivialMethodEscape.java b/com.ibm.wala.core/src/com/ibm/wala/escape/TrivialMethodEscape.java index 7e96cfe8c..65b6a9484 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/escape/TrivialMethodEscape.java +++ b/com.ibm.wala.core/src/com/ibm/wala/escape/TrivialMethodEscape.java @@ -1,146 +1,146 @@ -/******************************************************************************* - * 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.escape; - -import java.util.Collections; -import java.util.Iterator; -import java.util.Set; - -import com.ibm.wala.analysis.pointers.HeapGraph; -import com.ibm.wala.classLoader.NewSiteReference; -import com.ibm.wala.ipa.callgraph.CGNode; -import com.ibm.wala.ipa.callgraph.CallGraph; -import com.ibm.wala.ipa.callgraph.propagation.AbstractLocalPointerKey; -import com.ibm.wala.ipa.callgraph.propagation.InstanceKey; -import com.ibm.wala.ipa.callgraph.propagation.PointerKey; -import com.ibm.wala.ipa.callgraph.propagation.ReturnValueKey; -import com.ibm.wala.types.MethodReference; -import com.ibm.wala.util.WalaException; -import com.ibm.wala.util.collections.HashSetFactory; - -/** - * Trivial method-level escape analysis. - * - * An instance does not escape from method m if the following hold: - *
          - *
        1. the instance is only ever pointed to by locals (it is never stored in the heap) - *
        2. the method m does NOT return (either normally or exceptionally) a pointer to the instance - *
        - */ -public class TrivialMethodEscape implements IMethodEscapeAnalysis, INodeEscapeAnalysis { - - /** - * Heap graph representation of pointer analysis - */ - private final HeapGraph hg; - - /** - * Governing call graph - */ - private final CallGraph cg; - - /** - * @param hg Heap graph representation of pointer analysis - * @param cg governing call graph - */ - public TrivialMethodEscape(CallGraph cg, HeapGraph hg) { - this.hg = hg; - this.cg = cg; - } - - public boolean mayEscape(MethodReference allocMethod, int allocPC, MethodReference m) throws WalaException { - - if (allocMethod == null) { - throw new IllegalArgumentException("null allocMethod"); - } - // nodes:= set of call graph nodes representing method m - Set nodes = cg.getNodes(m); - if (nodes.size() == 0) { - throw new WalaException("could not find call graph node for method " + m); - } - - // allocN := set of call graph nodes representing method allocMethod - Set allocN = cg.getNodes(allocMethod); - if (allocN.size() == 0) { - throw new WalaException("could not find call graph node for allocation method " + allocMethod); - } - return mayEscape(allocN, allocPC, nodes); - } - - public boolean mayEscape(CGNode allocNode, int allocPC, CGNode node) throws WalaException { - return mayEscape(Collections.singleton(allocNode), allocPC, Collections.singleton(node)); - } - - /** - * @param allocN Set representing the allocation site. - * @param allocPC - * @param nodes Set, the nodes of interest - * @return true iff some instance allocated at a site N \in <allocN, allocPC> might escape from some activation of a node m \in - * { nodes } - * @throws WalaException - */ - private boolean mayEscape(Set allocN, int allocPC, Set nodes) throws WalaException { - Set instances = HashSetFactory.make(); - // instances := set of instance key allocated at <allocMethod, allocPC> - for (Iterator it = allocN.iterator(); it.hasNext();) { - CGNode n = (CGNode) it.next(); - NewSiteReference site = findAlloc(n, allocPC); - InstanceKey ik = hg.getHeapModel().getInstanceKeyForAllocation(n, site); - if (ik == null) { - throw new WalaException("could not get instance key at site " + site + " in " + n); - } - instances.add(ik); - } - - for (Iterator it = instances.iterator(); it.hasNext();) { - InstanceKey ik = it.next(); - for (Iterator it2 = hg.getPredNodes(ik); it2.hasNext();) { - PointerKey p = (PointerKey) it2.next(); - if (!(p instanceof AbstractLocalPointerKey)) { - // a pointer from the heap. give up. - return true; - } else { - if (p instanceof ReturnValueKey) { - ReturnValueKey rk = (ReturnValueKey) p; - if (nodes.contains(rk.getNode())) { - // some node representing method m returns the instance to its - // caller - return true; - } - } - } - } - } - - // if we get here, it may not escape - return false; - } - - /** - * @param n a call graph node - * @param allocPC a bytecode index corresponding to an allocation - * @return the NewSiteReference for the allocation - * @throws WalaException - */ - static NewSiteReference findAlloc(CGNode n, int allocPC) throws WalaException { - if (n == null) { - throw new IllegalArgumentException("null n"); - } - for (Iterator it = n.iterateNewSites(); it.hasNext();) { - NewSiteReference site = (NewSiteReference) it.next(); - if (site.getProgramCounter() == allocPC) { - return site; - } - } - throw new WalaException("Failed to find an allocation at pc " + allocPC + " in node " + n); - } - -} +/******************************************************************************* + * 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.escape; + +import java.util.Collections; +import java.util.Iterator; +import java.util.Set; + +import com.ibm.wala.analysis.pointers.HeapGraph; +import com.ibm.wala.classLoader.NewSiteReference; +import com.ibm.wala.ipa.callgraph.CGNode; +import com.ibm.wala.ipa.callgraph.CallGraph; +import com.ibm.wala.ipa.callgraph.propagation.AbstractLocalPointerKey; +import com.ibm.wala.ipa.callgraph.propagation.InstanceKey; +import com.ibm.wala.ipa.callgraph.propagation.PointerKey; +import com.ibm.wala.ipa.callgraph.propagation.ReturnValueKey; +import com.ibm.wala.types.MethodReference; +import com.ibm.wala.util.WalaException; +import com.ibm.wala.util.collections.HashSetFactory; + +/** + * Trivial method-level escape analysis. + * + * An instance does not escape from method m if the following hold: + *
          + *
        1. the instance is only ever pointed to by locals (it is never stored in the heap) + *
        2. the method m does NOT return (either normally or exceptionally) a pointer to the instance + *
        + */ +public class TrivialMethodEscape implements IMethodEscapeAnalysis, INodeEscapeAnalysis { + + /** + * Heap graph representation of pointer analysis + */ + private final HeapGraph hg; + + /** + * Governing call graph + */ + private final CallGraph cg; + + /** + * @param hg Heap graph representation of pointer analysis + * @param cg governing call graph + */ + public TrivialMethodEscape(CallGraph cg, HeapGraph hg) { + this.hg = hg; + this.cg = cg; + } + + public boolean mayEscape(MethodReference allocMethod, int allocPC, MethodReference m) throws WalaException { + + if (allocMethod == null) { + throw new IllegalArgumentException("null allocMethod"); + } + // nodes:= set of call graph nodes representing method m + Set nodes = cg.getNodes(m); + if (nodes.size() == 0) { + throw new WalaException("could not find call graph node for method " + m); + } + + // allocN := set of call graph nodes representing method allocMethod + Set allocN = cg.getNodes(allocMethod); + if (allocN.size() == 0) { + throw new WalaException("could not find call graph node for allocation method " + allocMethod); + } + return mayEscape(allocN, allocPC, nodes); + } + + public boolean mayEscape(CGNode allocNode, int allocPC, CGNode node) throws WalaException { + return mayEscape(Collections.singleton(allocNode), allocPC, Collections.singleton(node)); + } + + /** + * @param allocN Set representing the allocation site. + * @param allocPC + * @param nodes Set, the nodes of interest + * @return true iff some instance allocated at a site N \in <allocN, allocPC> might escape from some activation of a node m \in + * { nodes } + * @throws WalaException + */ + private boolean mayEscape(Set allocN, int allocPC, Set nodes) throws WalaException { + Set instances = HashSetFactory.make(); + // instances := set of instance key allocated at <allocMethod, allocPC> + for (Iterator it = allocN.iterator(); it.hasNext();) { + CGNode n = (CGNode) it.next(); + NewSiteReference site = findAlloc(n, allocPC); + InstanceKey ik = hg.getHeapModel().getInstanceKeyForAllocation(n, site); + if (ik == null) { + throw new WalaException("could not get instance key at site " + site + " in " + n); + } + instances.add(ik); + } + + for (Iterator it = instances.iterator(); it.hasNext();) { + InstanceKey ik = it.next(); + for (Iterator it2 = hg.getPredNodes(ik); it2.hasNext();) { + PointerKey p = (PointerKey) it2.next(); + if (!(p instanceof AbstractLocalPointerKey)) { + // a pointer from the heap. give up. + return true; + } else { + if (p instanceof ReturnValueKey) { + ReturnValueKey rk = (ReturnValueKey) p; + if (nodes.contains(rk.getNode())) { + // some node representing method m returns the instance to its + // caller + return true; + } + } + } + } + } + + // if we get here, it may not escape + return false; + } + + /** + * @param n a call graph node + * @param allocPC a bytecode index corresponding to an allocation + * @return the NewSiteReference for the allocation + * @throws WalaException + */ + static NewSiteReference findAlloc(CGNode n, int allocPC) throws WalaException { + if (n == null) { + throw new IllegalArgumentException("null n"); + } + for (Iterator it = n.iterateNewSites(); it.hasNext();) { + NewSiteReference site = (NewSiteReference) it.next(); + if (site.getProgramCounter() == allocPC) { + return site; + } + } + throw new WalaException("Failed to find an allocation at pc " + allocPC + " in node " + n); + } + +} diff --git a/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/AnalysisCache.java b/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/AnalysisCache.java index 809142d16..ae4632692 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/AnalysisCache.java +++ b/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/AnalysisCache.java @@ -1,76 +1,76 @@ -/******************************************************************************* - * Copyright (c) 2007 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.ipa.callgraph; - -import com.ibm.wala.classLoader.IMethod; -import com.ibm.wala.ipa.callgraph.impl.Everywhere; -import com.ibm.wala.ssa.DefUse; -import com.ibm.wala.ssa.DefaultIRFactory; -import com.ibm.wala.ssa.IR; -import com.ibm.wala.ssa.IRFactory; -import com.ibm.wala.ssa.SSACache; -import com.ibm.wala.ssa.SSAOptions; -import com.ibm.wala.util.ref.ReferenceCleanser; - -/** - * A place to hold onto caches of various analysis artifacts. - * - * Someday this should maybe go away? - */ -public class AnalysisCache { - private final IRFactory irFactory; - - private final SSACache ssaCache; - - public AnalysisCache(IRFactory irFactory) { - super(); - this.irFactory = irFactory; - this.ssaCache = new SSACache(irFactory); - ReferenceCleanser.registerCache(this); - } - - public AnalysisCache() { - this(new DefaultIRFactory()); - } - - public void invalidate(IMethod method, Context C) { - ssaCache.invalidate(method, C); - } - - public SSACache getSSACache() { - return ssaCache; - } - - public IRFactory getIRFactory() { - return irFactory; - } - - /** - * Find or create an IR for the method using the {@link Everywhere} context and default {@link SSAOptions} - */ - public IR getIR(IMethod method) { - if (method == null) { - throw new IllegalArgumentException("method is null"); - } - return ssaCache.findOrCreateIR(method, Everywhere.EVERYWHERE, new AnalysisOptions().getSSAOptions()); - } - - - /** - * Find or create a DefUse for the IR using the {@link Everywhere} context - */ - public DefUse getDefUse(IR ir) { - if (ir == null) { - throw new IllegalArgumentException("ir is null"); - } - return ssaCache.findOrCreateDU(ir, Everywhere.EVERYWHERE); - } -} +/******************************************************************************* + * Copyright (c) 2007 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.ipa.callgraph; + +import com.ibm.wala.classLoader.IMethod; +import com.ibm.wala.ipa.callgraph.impl.Everywhere; +import com.ibm.wala.ssa.DefUse; +import com.ibm.wala.ssa.DefaultIRFactory; +import com.ibm.wala.ssa.IR; +import com.ibm.wala.ssa.IRFactory; +import com.ibm.wala.ssa.SSACache; +import com.ibm.wala.ssa.SSAOptions; +import com.ibm.wala.util.ref.ReferenceCleanser; + +/** + * A place to hold onto caches of various analysis artifacts. + * + * Someday this should maybe go away? + */ +public class AnalysisCache { + private final IRFactory irFactory; + + private final SSACache ssaCache; + + public AnalysisCache(IRFactory irFactory) { + super(); + this.irFactory = irFactory; + this.ssaCache = new SSACache(irFactory); + ReferenceCleanser.registerCache(this); + } + + public AnalysisCache() { + this(new DefaultIRFactory()); + } + + public void invalidate(IMethod method, Context C) { + ssaCache.invalidate(method, C); + } + + public SSACache getSSACache() { + return ssaCache; + } + + public IRFactory getIRFactory() { + return irFactory; + } + + /** + * Find or create an IR for the method using the {@link Everywhere} context and default {@link SSAOptions} + */ + public IR getIR(IMethod method) { + if (method == null) { + throw new IllegalArgumentException("method is null"); + } + return ssaCache.findOrCreateIR(method, Everywhere.EVERYWHERE, new AnalysisOptions().getSSAOptions()); + } + + + /** + * Find or create a DefUse for the IR using the {@link Everywhere} context + */ + public DefUse getDefUse(IR ir) { + if (ir == null) { + throw new IllegalArgumentException("ir is null"); + } + return ssaCache.findOrCreateDU(ir, Everywhere.EVERYWHERE); + } +} diff --git a/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/AnalysisOptions.java b/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/AnalysisOptions.java index 7bfe60b76..c6228f373 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/AnalysisOptions.java +++ b/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/AnalysisOptions.java @@ -1,405 +1,405 @@ -/******************************************************************************* - * 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.ipa.callgraph; - -import com.ibm.wala.analysis.reflection.ReflectionContextInterpreter; -import com.ibm.wala.analysis.reflection.ReflectionContextSelector; -import com.ibm.wala.ipa.callgraph.impl.ExplicitCallGraph; -import com.ibm.wala.ipa.callgraph.propagation.ReflectionHandler; -import com.ibm.wala.ssa.SSAOptions; - -/** - * Basic interface for options that control call graph generation. - * - * TODO: This class should be refactored into an abstract base class and language-specific subclasses. - */ -public class AnalysisOptions { - - /** - * An object that represents the analysis scope - */ - private AnalysisScope analysisScope; - - /** - * An object that identifies the entrypoints for the call graph - */ - private Iterable entrypoints; - - - /** - * Policy that determines types allocated at new statements. - */ - private ClassTargetSelector classTargetSelector; - - /** - * Policy that determines methods called at call sites. - */ - private MethodTargetSelector methodTargetSelector; - - /** - * A tuning parameter; how may new equations must be added before doing a new topological sort? - */ - private int minEquationsForTopSort = 100; - - /** - * A tuning parameter; by what percentage must the number of equations grow before we perform a topological sort? - */ - private double topologicalGrowthFactor = 0.5; - - /** - * A tuning parameter: how many evaluations are allowed to take place between topological re-orderings. The idea is that many - * evaluations may be a sign of a bad ordering, even when few new equations are being added. - */ - private int maxEvalBetweenTopo = 1000000000; - - /** - * options for handling reflection during call graph construction - */ - public static enum ReflectionOptions { - FULL("full", Integer.MAX_VALUE, false, false), NO_FLOW_TO_CASTS("no_flow_to_casts", 0, false, false), NO_METHOD_INVOKE( - "no_method_invoke", Integer.MAX_VALUE, true, false), NO_FLOW_TO_CASTS_NO_METHOD_INVOKE("no_flow_to_casts_no_method_invoke", - 0, true, false), ONE_FLOW_TO_CASTS_NO_METHOD_INVOKE("one_flow_to_casts_no_method_invoke", 1, true, false), NO_STRING_CONSTANTS( - "no_string_constants", Integer.MAX_VALUE, false, true), NONE("none", 0, true, true); - - private final String name; - - /** - * how many times should flows from newInstance() calls to casts be analyzed? - */ - private final int numFlowToCastIterations; - - /** - * should calls to Method.invoke() be ignored? - */ - private final boolean ignoreMethodInvoke; - - /** - * should calls to reflective methods with String constant arguments be ignored? - */ - private final boolean ignoreStringConstants; - - private ReflectionOptions(String name, int numFlowToCastIterations, boolean ignoreMethodInvoke, boolean ignoreInterpretCalls) { - this.name = name; - this.numFlowToCastIterations = numFlowToCastIterations; - this.ignoreMethodInvoke = ignoreMethodInvoke; - this.ignoreStringConstants = ignoreInterpretCalls; - } - - public String getName() { - return name; - } - - public int getNumFlowToCastIterations() { - return numFlowToCastIterations; - } - - public boolean isIgnoreMethodInvoke() { - return ignoreMethodInvoke; - } - - public boolean isIgnoreStringConstants() { - return ignoreStringConstants; - } - - } - - /** - * Should call graph construction attempt to handle reflection via detection of flows to casts, analysis of string constant - * parameters to reflective methods, etc.? - * - * @see ReflectionHandler - * @see ReflectionContextInterpreter - * @see ReflectionContextSelector - */ - private ReflectionOptions reflectionOptions = ReflectionOptions.FULL; - - /** - * Should call graph construction handle possible invocations of static initializer methods? - */ - private boolean handleStaticInit = true; - - /** - * Options governing SSA construction - */ - private SSAOptions ssaOptions = new SSAOptions(); - - /** - * Use distinct instance keys for distinct string constants? - * - * TODO: Probably, this option should moved somewhere into the creation of instance keys. However, those factories are created - * within the various builders right now, and this is the most convenient place for an engine user to set an option which the - * creation of instance keys later picks up. - */ - private boolean useConstantSpecificKeys = false; - - /** - * Should analysis of lexical scoping consider call stacks? - * - * TODO: this option does not apply to all languages. We could have a separation into core engine options and language-specific - * options. - * - * (be careful with multithreaded languages, as threading can break the stack discipline this option may assume) - */ - private boolean useStacksForLexicalScoping = false; - - /** - * Should global variables be considered lexically-scoped from the root node? - * - * TODO: this option does not apply to all languages. We could have a separation into core engine options and language-specific - * options. - * - * (be careful with multithreaded languages, as threading can break the stack discipline this option may assume) - */ - private boolean useLexicalScopingForGlobals = false; - - /** - * Should analysis try to understand the results of string constants flowing to a + operator? Note that this option does not apply - * to Java bytecode analysis, since the + operators have been compiled away for that. It is used for the Java CAst front end. - */ - private boolean traceStringConstants = false; - - /** - * This numerical value indicates the maximum number of nodes that any {@link CallGraph} build with this {@link AnalysisOptions} - * object is allowed to have. During {@link CallGraph} construction, once maxNumberOfNodes {@link CGNode} objects - * have been added to the {@link CallGraph}, no more {@link CGNode} objects will be added. By default, - * maxNumberOfNodes is set to -1, which indicates that no restrictions are in place. See also - * {@link ExplicitCallGraph}. - */ - private long maxNumberOfNodes = -1; - - // SJF: I'm not sure these factories and caches belong here. - // TODO: figure out how to clean this up. - - public AnalysisOptions() { - } - - public AnalysisOptions(AnalysisScope scope, Iterable e) { - this.analysisScope = scope; - this.entrypoints = e; - } - - public AnalysisScope getAnalysisScope() { - return analysisScope; - } - - public void setAnalysisScope(AnalysisScope analysisScope) { - this.analysisScope = analysisScope; - } - - /** - * TODO: this really should go away. The entrypoints don't belong here. - */ - public Iterable getEntrypoints() { - return entrypoints; - } - - public void setEntrypoints(Iterable entrypoints) { - this.entrypoints = entrypoints; - } - - public long getMaxNumberOfNodes() { - return maxNumberOfNodes; - } - - public void setMaxNumberOfNodes(long maxNumberOfNodes) { - this.maxNumberOfNodes = maxNumberOfNodes; - } - - - /** - * @return Policy that determines methods called at call sites. - */ - public MethodTargetSelector getMethodTargetSelector() { - return methodTargetSelector; - } - - /** - * @return Policy that determines types allocated at new statements. - */ - public ClassTargetSelector getClassTargetSelector() { - return classTargetSelector; - } - - /** - * install a method target selector - * - * @param x an object which controls the policy for selecting the target at a call site - */ - public void setSelector(MethodTargetSelector x) { - methodTargetSelector = x; - } - - /** - * install a class target selector - * - * @param x an object which controls the policy for selecting the allocated object at a new site - */ - public void setSelector(ClassTargetSelector x) { - classTargetSelector = x; - } - - /** - * @return the mininum number of equations that the pointer analysis system must contain before the solver will try to - * topologically sore - */ - public int getMinEquationsForTopSort() { - return minEquationsForTopSort; - } - - /** - * @param i the mininum number of equations that the pointer analysis system must contain before the solver will try to - * topologically sore - */ - public void setMinEquationsForTopSort(int i) { - minEquationsForTopSort = i; - } - - /** - * @return the maximum number of evaluations that the pointer analysis solver will perform before topologically resorting the - * system - */ - public int getMaxEvalBetweenTopo() { - return maxEvalBetweenTopo; - } - - /** - * @return a fraction x s.t. the solver will resort the system when it grows by a factor of x - */ - public double getTopologicalGrowthFactor() { - return topologicalGrowthFactor; - } - - /** - * @param i the maximum number of evaluations that the pointer analysis solver will perform before topologically resorting the - * system - */ - public void setMaxEvalBetweenTopo(int i) { - maxEvalBetweenTopo = i; - } - - /** - * @param d a fraction x s.t. the solver will resort the system when it grows by a factor of x - */ - public void setTopologicalGrowthFactor(double d) { - topologicalGrowthFactor = d; - } - - - /** - * @return options governing SSA construction - */ - public SSAOptions getSSAOptions() { - return ssaOptions; - } - - /** - * @param ssaOptions options governing SSA construction - */ - public void setSSAOptions(SSAOptions ssaOptions) { - this.ssaOptions = ssaOptions; - } - - /** - * Use distinct instance keys for distinct string constants? - */ - public boolean getUseConstantSpecificKeys() { - return useConstantSpecificKeys; - } - - /** - * Use distinct instance keys for distinct string constants? - */ - public void setUseConstantSpecificKeys(boolean useConstantSpecificKeys) { - this.useConstantSpecificKeys = useConstantSpecificKeys; - } - - /** - * Should analysis of lexical scoping consider call stacks? - */ - public boolean getUseStacksForLexicalScoping() { - return useStacksForLexicalScoping; - } - - /** - * Should analysis of lexical scoping consider call stacks? - */ - public void setUseStacksForLexicalScoping(boolean v) { - useStacksForLexicalScoping = v; - } - - /** - * Should global variables be considered lexically-scoped from the root node? - */ - public boolean getUseLexicalScopingForGlobals() { - return useLexicalScopingForGlobals; - } - - /** - * Should global variables be considered lexically-scoped from the root node? - */ - public void setUseLexicalScopingForGlobals(boolean v) { - useLexicalScopingForGlobals = v; - } - - /** - * Should analysis try to understand the results of string constants flowing to a + operator? Note that this option does not apply - * to Java bytecode analysis, since the + operators have been compiled away for that. It is used for the Java CAst front end. - */ - public void setTraceStringConstants(boolean v) { - traceStringConstants = v; - } - - /** - * Should analysis try to understand the results of string constants flowing to a + operator? Note that this option does not apply - * to Java bytecode analysis, since the + operators have been compiled away for that. It is used for the Java CAst front end. - */ - public boolean getTraceStringConstants() { - return traceStringConstants; - } - - /** - * Should call graph construction attempt to handle reflection via detection of flows to casts, analysis of string constant - * parameters to reflective methods, etc.? - * - * @see ReflectionHandler - * @see ReflectionContextInterpreter - * @see ReflectionContextSelector - */ - public ReflectionOptions getReflectionOptions() { - return reflectionOptions; - } - - /** - * Should call graph construction attempt to handle reflection via detection of flows to casts, analysis of string constant - * parameters to reflective methods, etc.? - * - * @see ReflectionHandler - * @see ReflectionContextInterpreter - * @see ReflectionContextSelector - */ - public void setReflectionOptions(ReflectionOptions reflectionOptions) { - this.reflectionOptions = reflectionOptions; - } - - /** - * Should call graph construction handle possible invocations of static initializer methods? - */ - public boolean getHandleStaticInit() { - return handleStaticInit; - } - - /** - * Should call graph construction handle possible invocations of static initializer methods? - */ - public void setHandleStaticInit(boolean handleStaticInit) { - this.handleStaticInit = handleStaticInit; - } -} +/******************************************************************************* + * 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.ipa.callgraph; + +import com.ibm.wala.analysis.reflection.ReflectionContextInterpreter; +import com.ibm.wala.analysis.reflection.ReflectionContextSelector; +import com.ibm.wala.ipa.callgraph.impl.ExplicitCallGraph; +import com.ibm.wala.ipa.callgraph.propagation.ReflectionHandler; +import com.ibm.wala.ssa.SSAOptions; + +/** + * Basic interface for options that control call graph generation. + * + * TODO: This class should be refactored into an abstract base class and language-specific subclasses. + */ +public class AnalysisOptions { + + /** + * An object that represents the analysis scope + */ + private AnalysisScope analysisScope; + + /** + * An object that identifies the entrypoints for the call graph + */ + private Iterable entrypoints; + + + /** + * Policy that determines types allocated at new statements. + */ + private ClassTargetSelector classTargetSelector; + + /** + * Policy that determines methods called at call sites. + */ + private MethodTargetSelector methodTargetSelector; + + /** + * A tuning parameter; how may new equations must be added before doing a new topological sort? + */ + private int minEquationsForTopSort = 100; + + /** + * A tuning parameter; by what percentage must the number of equations grow before we perform a topological sort? + */ + private double topologicalGrowthFactor = 0.5; + + /** + * A tuning parameter: how many evaluations are allowed to take place between topological re-orderings. The idea is that many + * evaluations may be a sign of a bad ordering, even when few new equations are being added. + */ + private int maxEvalBetweenTopo = 1000000000; + + /** + * options for handling reflection during call graph construction + */ + public static enum ReflectionOptions { + FULL("full", Integer.MAX_VALUE, false, false), NO_FLOW_TO_CASTS("no_flow_to_casts", 0, false, false), NO_METHOD_INVOKE( + "no_method_invoke", Integer.MAX_VALUE, true, false), NO_FLOW_TO_CASTS_NO_METHOD_INVOKE("no_flow_to_casts_no_method_invoke", + 0, true, false), ONE_FLOW_TO_CASTS_NO_METHOD_INVOKE("one_flow_to_casts_no_method_invoke", 1, true, false), NO_STRING_CONSTANTS( + "no_string_constants", Integer.MAX_VALUE, false, true), NONE("none", 0, true, true); + + private final String name; + + /** + * how many times should flows from newInstance() calls to casts be analyzed? + */ + private final int numFlowToCastIterations; + + /** + * should calls to Method.invoke() be ignored? + */ + private final boolean ignoreMethodInvoke; + + /** + * should calls to reflective methods with String constant arguments be ignored? + */ + private final boolean ignoreStringConstants; + + private ReflectionOptions(String name, int numFlowToCastIterations, boolean ignoreMethodInvoke, boolean ignoreInterpretCalls) { + this.name = name; + this.numFlowToCastIterations = numFlowToCastIterations; + this.ignoreMethodInvoke = ignoreMethodInvoke; + this.ignoreStringConstants = ignoreInterpretCalls; + } + + public String getName() { + return name; + } + + public int getNumFlowToCastIterations() { + return numFlowToCastIterations; + } + + public boolean isIgnoreMethodInvoke() { + return ignoreMethodInvoke; + } + + public boolean isIgnoreStringConstants() { + return ignoreStringConstants; + } + + } + + /** + * Should call graph construction attempt to handle reflection via detection of flows to casts, analysis of string constant + * parameters to reflective methods, etc.? + * + * @see ReflectionHandler + * @see ReflectionContextInterpreter + * @see ReflectionContextSelector + */ + private ReflectionOptions reflectionOptions = ReflectionOptions.FULL; + + /** + * Should call graph construction handle possible invocations of static initializer methods? + */ + private boolean handleStaticInit = true; + + /** + * Options governing SSA construction + */ + private SSAOptions ssaOptions = new SSAOptions(); + + /** + * Use distinct instance keys for distinct string constants? + * + * TODO: Probably, this option should moved somewhere into the creation of instance keys. However, those factories are created + * within the various builders right now, and this is the most convenient place for an engine user to set an option which the + * creation of instance keys later picks up. + */ + private boolean useConstantSpecificKeys = false; + + /** + * Should analysis of lexical scoping consider call stacks? + * + * TODO: this option does not apply to all languages. We could have a separation into core engine options and language-specific + * options. + * + * (be careful with multithreaded languages, as threading can break the stack discipline this option may assume) + */ + private boolean useStacksForLexicalScoping = false; + + /** + * Should global variables be considered lexically-scoped from the root node? + * + * TODO: this option does not apply to all languages. We could have a separation into core engine options and language-specific + * options. + * + * (be careful with multithreaded languages, as threading can break the stack discipline this option may assume) + */ + private boolean useLexicalScopingForGlobals = false; + + /** + * Should analysis try to understand the results of string constants flowing to a + operator? Note that this option does not apply + * to Java bytecode analysis, since the + operators have been compiled away for that. It is used for the Java CAst front end. + */ + private boolean traceStringConstants = false; + + /** + * This numerical value indicates the maximum number of nodes that any {@link CallGraph} build with this {@link AnalysisOptions} + * object is allowed to have. During {@link CallGraph} construction, once maxNumberOfNodes {@link CGNode} objects + * have been added to the {@link CallGraph}, no more {@link CGNode} objects will be added. By default, + * maxNumberOfNodes is set to -1, which indicates that no restrictions are in place. See also + * {@link ExplicitCallGraph}. + */ + private long maxNumberOfNodes = -1; + + // SJF: I'm not sure these factories and caches belong here. + // TODO: figure out how to clean this up. + + public AnalysisOptions() { + } + + public AnalysisOptions(AnalysisScope scope, Iterable e) { + this.analysisScope = scope; + this.entrypoints = e; + } + + public AnalysisScope getAnalysisScope() { + return analysisScope; + } + + public void setAnalysisScope(AnalysisScope analysisScope) { + this.analysisScope = analysisScope; + } + + /** + * TODO: this really should go away. The entrypoints don't belong here. + */ + public Iterable getEntrypoints() { + return entrypoints; + } + + public void setEntrypoints(Iterable entrypoints) { + this.entrypoints = entrypoints; + } + + public long getMaxNumberOfNodes() { + return maxNumberOfNodes; + } + + public void setMaxNumberOfNodes(long maxNumberOfNodes) { + this.maxNumberOfNodes = maxNumberOfNodes; + } + + + /** + * @return Policy that determines methods called at call sites. + */ + public MethodTargetSelector getMethodTargetSelector() { + return methodTargetSelector; + } + + /** + * @return Policy that determines types allocated at new statements. + */ + public ClassTargetSelector getClassTargetSelector() { + return classTargetSelector; + } + + /** + * install a method target selector + * + * @param x an object which controls the policy for selecting the target at a call site + */ + public void setSelector(MethodTargetSelector x) { + methodTargetSelector = x; + } + + /** + * install a class target selector + * + * @param x an object which controls the policy for selecting the allocated object at a new site + */ + public void setSelector(ClassTargetSelector x) { + classTargetSelector = x; + } + + /** + * @return the mininum number of equations that the pointer analysis system must contain before the solver will try to + * topologically sore + */ + public int getMinEquationsForTopSort() { + return minEquationsForTopSort; + } + + /** + * @param i the mininum number of equations that the pointer analysis system must contain before the solver will try to + * topologically sore + */ + public void setMinEquationsForTopSort(int i) { + minEquationsForTopSort = i; + } + + /** + * @return the maximum number of evaluations that the pointer analysis solver will perform before topologically resorting the + * system + */ + public int getMaxEvalBetweenTopo() { + return maxEvalBetweenTopo; + } + + /** + * @return a fraction x s.t. the solver will resort the system when it grows by a factor of x + */ + public double getTopologicalGrowthFactor() { + return topologicalGrowthFactor; + } + + /** + * @param i the maximum number of evaluations that the pointer analysis solver will perform before topologically resorting the + * system + */ + public void setMaxEvalBetweenTopo(int i) { + maxEvalBetweenTopo = i; + } + + /** + * @param d a fraction x s.t. the solver will resort the system when it grows by a factor of x + */ + public void setTopologicalGrowthFactor(double d) { + topologicalGrowthFactor = d; + } + + + /** + * @return options governing SSA construction + */ + public SSAOptions getSSAOptions() { + return ssaOptions; + } + + /** + * @param ssaOptions options governing SSA construction + */ + public void setSSAOptions(SSAOptions ssaOptions) { + this.ssaOptions = ssaOptions; + } + + /** + * Use distinct instance keys for distinct string constants? + */ + public boolean getUseConstantSpecificKeys() { + return useConstantSpecificKeys; + } + + /** + * Use distinct instance keys for distinct string constants? + */ + public void setUseConstantSpecificKeys(boolean useConstantSpecificKeys) { + this.useConstantSpecificKeys = useConstantSpecificKeys; + } + + /** + * Should analysis of lexical scoping consider call stacks? + */ + public boolean getUseStacksForLexicalScoping() { + return useStacksForLexicalScoping; + } + + /** + * Should analysis of lexical scoping consider call stacks? + */ + public void setUseStacksForLexicalScoping(boolean v) { + useStacksForLexicalScoping = v; + } + + /** + * Should global variables be considered lexically-scoped from the root node? + */ + public boolean getUseLexicalScopingForGlobals() { + return useLexicalScopingForGlobals; + } + + /** + * Should global variables be considered lexically-scoped from the root node? + */ + public void setUseLexicalScopingForGlobals(boolean v) { + useLexicalScopingForGlobals = v; + } + + /** + * Should analysis try to understand the results of string constants flowing to a + operator? Note that this option does not apply + * to Java bytecode analysis, since the + operators have been compiled away for that. It is used for the Java CAst front end. + */ + public void setTraceStringConstants(boolean v) { + traceStringConstants = v; + } + + /** + * Should analysis try to understand the results of string constants flowing to a + operator? Note that this option does not apply + * to Java bytecode analysis, since the + operators have been compiled away for that. It is used for the Java CAst front end. + */ + public boolean getTraceStringConstants() { + return traceStringConstants; + } + + /** + * Should call graph construction attempt to handle reflection via detection of flows to casts, analysis of string constant + * parameters to reflective methods, etc.? + * + * @see ReflectionHandler + * @see ReflectionContextInterpreter + * @see ReflectionContextSelector + */ + public ReflectionOptions getReflectionOptions() { + return reflectionOptions; + } + + /** + * Should call graph construction attempt to handle reflection via detection of flows to casts, analysis of string constant + * parameters to reflective methods, etc.? + * + * @see ReflectionHandler + * @see ReflectionContextInterpreter + * @see ReflectionContextSelector + */ + public void setReflectionOptions(ReflectionOptions reflectionOptions) { + this.reflectionOptions = reflectionOptions; + } + + /** + * Should call graph construction handle possible invocations of static initializer methods? + */ + public boolean getHandleStaticInit() { + return handleStaticInit; + } + + /** + * Should call graph construction handle possible invocations of static initializer methods? + */ + public void setHandleStaticInit(boolean handleStaticInit) { + this.handleStaticInit = handleStaticInit; + } +} diff --git a/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/AnalysisScope.java b/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/AnalysisScope.java index 639102f27..c0e090594 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/AnalysisScope.java +++ b/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/AnalysisScope.java @@ -1,491 +1,491 @@ -/******************************************************************************* - * 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.ipa.callgraph; - -import java.io.File; -import java.io.NotSerializableException; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.HashMap; -import java.util.Iterator; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.jar.Attributes; -import java.util.jar.JarFile; -import java.util.jar.Manifest; - -import com.ibm.wala.classLoader.ArrayClassLoader; -import com.ibm.wala.classLoader.BinaryDirectoryTreeModule; -import com.ibm.wala.classLoader.ClassFileModule; -import com.ibm.wala.classLoader.IClassLoader; -import com.ibm.wala.classLoader.JarFileModule; -import com.ibm.wala.classLoader.Language; -import com.ibm.wala.classLoader.Module; -import com.ibm.wala.classLoader.SourceDirectoryTreeModule; -import com.ibm.wala.classLoader.SourceFileModule; -import com.ibm.wala.ipa.callgraph.impl.SetOfClasses; -import com.ibm.wala.shrikeCT.InvalidClassFileException; -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.PlatformUtil; -import com.ibm.wala.util.collections.HashMapFactory; -import com.ibm.wala.util.collections.HashSetFactory; -import com.ibm.wala.util.collections.MapUtil; -import com.ibm.wala.util.debug.Assertions; -import com.ibm.wala.util.strings.Atom; -import com.ibm.wala.util.strings.ImmutableByteArray; - -/** - * Base class that represents a set of files to analyze. - * - * The analysis scope is partitioned by class loader. There are three pre-defined class loader scopes: - *
          - *
        • Primordial (for rt.jar, the core classes) - *
        • Extension (for extension libraries in $JRE/lib/ext) - *
        • Application (for the classes of the application) - *
        - * - * Each class loader will load a set of classes described by a {@link Module}. - */ -public class AnalysisScope { - - private final static int DEBUG_LEVEL = 0; - - public static final Atom PRIMORDIAL = Atom.findOrCreateUnicodeAtom("Primordial"); - - public static final Atom EXTENSION = Atom.findOrCreateUnicodeAtom("Extension"); - - public static final Atom APPLICATION = Atom.findOrCreateUnicodeAtom("Application"); - - public static final Atom SYNTHETIC = Atom.findOrCreateUnicodeAtom("Synthetic"); - - /** - * Create an analysis scope initialized for analysis of Java - */ - public static AnalysisScope createJavaAnalysisScope() { - AnalysisScope scope = new AnalysisScope(Collections.singleton(Language.JAVA)); - scope.initForJava(); - return scope; - } - - /** - * Initialize a scope for java analysis - */ - protected void initForJava() { - initCoreForJava(); - initSynthetic(loadersByName.get(APPLICATION)); - } - - /** - * Initialize the standard 3 class loaders for java analysis - */ - protected void initCoreForJava() { - ClassLoaderReference primordial = new ClassLoaderReference(PRIMORDIAL, ClassLoaderReference.Java, null); - ClassLoaderReference extension = new ClassLoaderReference(EXTENSION, ClassLoaderReference.Java, primordial); - ClassLoaderReference application = new ClassLoaderReference(APPLICATION, ClassLoaderReference.Java, extension); - - loadersByName.put(PRIMORDIAL, primordial); - loadersByName.put(EXTENSION, extension); - loadersByName.put(APPLICATION, application); - } - - /** - * Create the class loader for synthetic classes. - */ - protected void initSynthetic(ClassLoaderReference parent) { - ClassLoaderReference synthetic = new ClassLoaderReference(SYNTHETIC, ClassLoaderReference.Java, parent); - setLoaderImpl(synthetic, "com.ibm.wala.ipa.summaries.BypassSyntheticClassLoader"); - loadersByName.put(SYNTHETIC, synthetic); - } - - /** - * A set of classes to exclude from the analysis entirely. - */ - private SetOfClasses exclusions; - - final protected LinkedHashMap loadersByName = new LinkedHashMap(); - - /** - * Special class loader for array instances - */ - private final ArrayClassLoader arrayClassLoader = new ArrayClassLoader(); - - final private Map> moduleMap = HashMapFactory.make(3); - - private final Map languages; - - protected AnalysisScope(Collection languages) { - super(); - this.languages = new HashMap(); - for (Language l : languages) { - this.languages.put(l.getName(), l); - } - } - - public Language getLanguage(Atom name) { - return languages.get(name); - } - - public boolean isApplicationLoader(IClassLoader loader) { - return loader.getReference().equals(getLoader(APPLICATION)); - } - - /** - * Return the information regarding the primordial loader. - */ - public ClassLoaderReference getPrimordialLoader() { - return getLoader(PRIMORDIAL); - } - - /** - * Return the information regarding the extension loader. - */ - public ClassLoaderReference getExtensionLoader() { - return getLoader(EXTENSION); - } - - /** - * Return the information regarding the application loader. - */ - public ClassLoaderReference getApplicationLoader() { - return getLoader(APPLICATION); - } - - /** - * Return the information regarding the application loader. - */ - public ClassLoaderReference getSyntheticLoader() { - return getLoader(SYNTHETIC); - } - - /** - * @return the set of languages to be processed during this analysis session. - */ - public Collection getLanguages() { - return languages.values(); - } - - /** - * @return the set of "base languages," each of which defines a family of compatible languages, and therefore induces a distinct - * ClassHierarchy - */ - public Set getBaseLanguages() { - Set result = HashSetFactory.make(); - for (Language language : getLanguages()) { - if (language.getBaseLanguage() == null) { - result.add(language); - } - } - return result; - } - - /** - * Add a class file to the scope for a loader - */ - public void addSourceFileToScope(ClassLoaderReference loader, File file, String fileName) throws IllegalArgumentException { - List s = MapUtil.findOrCreateList(moduleMap, loader); - s.add(new SourceFileModule(file, fileName)); - } - - /** - * Add a class file to the scope for a loader - * @throws InvalidClassFileException - */ - public void addClassFileToScope(ClassLoaderReference loader, File file) throws IllegalArgumentException, InvalidClassFileException { - List s = MapUtil.findOrCreateList(moduleMap, loader); - s.add(new ClassFileModule(file)); - } - - /** - * Add a jar file to the scope for a loader - */ - public void addToScope(ClassLoaderReference loader, JarFile file) { - List s = MapUtil.findOrCreateList(moduleMap, loader); - if (DEBUG_LEVEL > 0) { - System.err.println(("AnalysisScope: add JarFileModule " + file.getName())); - } - s.add(new JarFileModule(file)); - } - - /** - * Add a module to the scope for a loader - */ - public void addToScope(ClassLoaderReference loader, Module m) { - if (m == null) { - throw new IllegalArgumentException("null m"); - } - List s = MapUtil.findOrCreateList(moduleMap, loader); - if (DEBUG_LEVEL > 0) { - System.err.println(("AnalysisScope: add module " + m)); - } - s.add(m); - } - - /** - * Add all modules from another scope - */ - public void addToScope(AnalysisScope other) { - if (other == null) { - throw new IllegalArgumentException("null other"); - } - for (ClassLoaderReference loader : other.getLoaders()) { - for (Module m : other.getModules(loader)) { - addToScope(loader, m); - } - } - } - - /** - * Add a module file to the scope for a loader. The classes in the added jar file will override classes added to the scope so far. - */ - public void addToScopeHead(ClassLoaderReference loader, Module m) { - if (m == null) { - throw new IllegalArgumentException("null m"); - } - List s = MapUtil.findOrCreateList(moduleMap, loader); - if (DEBUG_LEVEL > 0) { - System.err.println(("AnalysisScope: add overriding module " + m)); - } - s.add(0, m); - } - - /** - * @return the ClassLoaderReference specified by name. - * @throws IllegalArgumentException if name is null - */ - public ClassLoaderReference getLoader(Atom name) throws IllegalArgumentException { - if (name == null) { - throw new IllegalArgumentException("name is null"); - } - if (name.length() == 0) { - throw new IllegalArgumentException("empty atom is not a legal class loader name"); - } - /* - * if (Assertions.verifyAssertions) { if (name.getVal(0) > 'Z') { Assertions._assert(name.getVal(0) <= 'Z', - * "Classloader name improperly capitalised? (" + name + ")"); } } - */ - return loadersByName.get(name); - } - - protected ClassLoaderReference classLoaderName2Ref(String clName) { - return getLoader(Atom.findOrCreateUnicodeAtom(clName)); - } - - private final HashMap loaderImplByRef = HashMapFactory.make(); - - public String getLoaderImpl(ClassLoaderReference ref) { - return loaderImplByRef.get(ref); - } - - public void setLoaderImpl(ClassLoaderReference ref, String implClass) { - if (ref == null) { - throw new IllegalArgumentException("null ref"); - } - if (implClass == null) { - throw new IllegalArgumentException("null implClass"); - } - loaderImplByRef.put(ref, implClass); - } - - public Collection getLoaders() { - return Collections.unmodifiableCollection(loadersByName.values()); - } - - public int getNumberOfLoaders() { - return loadersByName.values().size(); - } - - public SetOfClasses getExclusions() { - return exclusions; - } - - public void setExclusions(SetOfClasses classes) { - exclusions = classes; - } - - @Override - public String toString() { - StringBuffer result = new StringBuffer(); - for (ClassLoaderReference loader : loadersByName.values()) { - result.append(loader.getName()); - result.append("\n"); - for (Module m : getModules(loader)) { - result.append(" "); - result.append(m); - result.append("\n"); - } - } - result.append(getExclusionString()); - result.append("\n"); - return result.toString(); - } - - /** - * @return a String that describes exclusions from the analysis scope. - */ - protected Object getExclusionString() { - return "Exclusions: " + exclusions; - } - - /** - * Utility function. Useful when parsing input. - */ - public MethodReference findMethod(Atom loader, String klass, Atom name, ImmutableByteArray desc) { - if (desc == null) { - throw new IllegalArgumentException("null desc"); - } - ClassLoaderReference clr = getLoader(loader); - Descriptor ddesc = Descriptor.findOrCreate(languages.get(clr.getLanguage()), desc); - TypeReference type = TypeReference.findOrCreate(clr, TypeName.string2TypeName(klass)); - return MethodReference.findOrCreate(type, name, ddesc); - } - - public List getModules(ClassLoaderReference loader) { - List result = moduleMap.get(loader); - List empty = Collections.emptyList(); - return result == null ? empty : result; - } - - /** - * @return Returns the arrayClassLoader. - */ - public ArrayClassLoader getArrayClassLoader() { - return arrayClassLoader; - } - - /** - * @return the rt.jar (1.4) or core.jar (1.5) file, or null if not found. - */ - private JarFile getRtJar() { - for (Iterator MS = getModules(getPrimordialLoader()).iterator(); MS.hasNext();) { - Module M = (Module) MS.next(); - if (M instanceof JarFileModule) { - JarFile JF = ((JarFileModule) M).getJarFile(); - if (JF.getName().endsWith(File.separator + "rt.jar")) { - return JF; - } - if (JF.getName().endsWith(File.separator + "core.jar")) { - return JF; - } - // hack for Mac - if (PlatformUtil.onMacOSX() && JF.getName().endsWith(File.separator + "classes.jar")) { - return JF; - } - } - } - return null; - } - - public String getJavaLibraryVersion() throws IllegalStateException { - JarFile rtJar = getRtJar(); - if (rtJar == null) { - throw new IllegalStateException("cannot find runtime libraries"); - } - try { - Manifest man = rtJar.getManifest(); - assert man != null : "runtime library has no manifest!"; - String result = man.getMainAttributes().getValue("Specification-Version"); - if (result == null) { - Attributes att = man.getMainAttributes(); - System.err.println("main attributes:" + att); - Assertions.UNREACHABLE("Manifest for " + rtJar.getName() + " has no value for Specification-Version"); - } - return result; - } catch (java.io.IOException e) { - Assertions.UNREACHABLE("error getting rt.jar manifest!"); - return null; - } - } - - public boolean isJava17Libraries() throws IllegalStateException { - return getJavaLibraryVersion().startsWith("1.7"); - } - - public boolean isJava16Libraries() throws IllegalStateException { - return getJavaLibraryVersion().startsWith("1.6"); - } - - public boolean isJava15Libraries() throws IllegalStateException { - return getJavaLibraryVersion().startsWith("1.5"); - } - - public boolean isJava14Libraries() throws IllegalStateException { - return getJavaLibraryVersion().startsWith("1.4"); - } - - /** - * Creates a "serializable" version of the analysis scope. - * - * @return a "serializable" version of the analysis scope. - * @throws NotSerializableException - */ - public ShallowAnalysisScope toShallowAnalysisScope() throws NotSerializableException { - - if (getArrayClassLoader().getNumberOfClasses() != 0) { - throw new NotSerializableException("Scope was already used for building array classes"); - } - // Note: 'arrayClassLoader' object will be built from scratch in remote process - - // represent modules map as a set of strings (corresponding to analysis scope file lines. - List moduleLines = new ArrayList(); - for (Map.Entry> e : moduleMap.entrySet()) { - ClassLoaderReference lrReference = e.getKey(); - String moduleLdr = lrReference.getName().toString(); - String moduleLang = lrReference.getLanguage().toString(); - assert Language.JAVA.getName().equals(lrReference.getLanguage()) : "Java language only is currently supported"; - - for (Module m : e.getValue()) { - String moduleType; - String modulePath; - if (m instanceof JarFileModule) { - moduleType = "jarFile"; - modulePath = ((JarFileModule) m).getAbsolutePath(); - } else if (m instanceof BinaryDirectoryTreeModule) { - moduleType = "binaryDir"; - modulePath = ((BinaryDirectoryTreeModule) m).getPath(); - } else if (m instanceof SourceDirectoryTreeModule) { - moduleType = "sourceDir"; - modulePath = ((SourceDirectoryTreeModule) m).getPath(); - } else if (m instanceof SourceFileModule) { - moduleType = "sourceFile"; - modulePath = ((SourceFileModule) m).getAbsolutePath(); - } else { - Assertions.UNREACHABLE("Module type isn't supported - " + m); - continue; - } - modulePath.replace("\\", "/"); - String moduleDescrLine = String.format("%s,%s,%s,%s", moduleLdr, moduleLang, moduleType, modulePath); - moduleLines.add(moduleDescrLine); - } - } - - // represent loaderImplByRef map as set of strings - List ldrImplLines = new ArrayList(); - for (Map.Entry e : loaderImplByRef.entrySet()) { - ClassLoaderReference lrReference = e.getKey(); - String ldrName = lrReference.getName().toString(); - String ldrLang = lrReference.getLanguage().toString(); - assert Language.JAVA.getName().equals(lrReference.getLanguage()) : "Java language only is currently supported"; - String ldrImplName = e.getValue(); - String ldrImplDescrLine = String.format("%s,%s,%s,%s", ldrName, ldrLang, "loaderImpl", ldrImplName); - ldrImplLines.add(ldrImplDescrLine); - } - - ShallowAnalysisScope shallowScope = new ShallowAnalysisScope(getExclusions(), moduleLines, ldrImplLines); - return shallowScope; - } -} +/******************************************************************************* + * 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.ipa.callgraph; + +import java.io.File; +import java.io.NotSerializableException; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.Iterator; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.jar.Attributes; +import java.util.jar.JarFile; +import java.util.jar.Manifest; + +import com.ibm.wala.classLoader.ArrayClassLoader; +import com.ibm.wala.classLoader.BinaryDirectoryTreeModule; +import com.ibm.wala.classLoader.ClassFileModule; +import com.ibm.wala.classLoader.IClassLoader; +import com.ibm.wala.classLoader.JarFileModule; +import com.ibm.wala.classLoader.Language; +import com.ibm.wala.classLoader.Module; +import com.ibm.wala.classLoader.SourceDirectoryTreeModule; +import com.ibm.wala.classLoader.SourceFileModule; +import com.ibm.wala.ipa.callgraph.impl.SetOfClasses; +import com.ibm.wala.shrikeCT.InvalidClassFileException; +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.PlatformUtil; +import com.ibm.wala.util.collections.HashMapFactory; +import com.ibm.wala.util.collections.HashSetFactory; +import com.ibm.wala.util.collections.MapUtil; +import com.ibm.wala.util.debug.Assertions; +import com.ibm.wala.util.strings.Atom; +import com.ibm.wala.util.strings.ImmutableByteArray; + +/** + * Base class that represents a set of files to analyze. + * + * The analysis scope is partitioned by class loader. There are three pre-defined class loader scopes: + *
          + *
        • Primordial (for rt.jar, the core classes) + *
        • Extension (for extension libraries in $JRE/lib/ext) + *
        • Application (for the classes of the application) + *
        + * + * Each class loader will load a set of classes described by a {@link Module}. + */ +public class AnalysisScope { + + private final static int DEBUG_LEVEL = 0; + + public static final Atom PRIMORDIAL = Atom.findOrCreateUnicodeAtom("Primordial"); + + public static final Atom EXTENSION = Atom.findOrCreateUnicodeAtom("Extension"); + + public static final Atom APPLICATION = Atom.findOrCreateUnicodeAtom("Application"); + + public static final Atom SYNTHETIC = Atom.findOrCreateUnicodeAtom("Synthetic"); + + /** + * Create an analysis scope initialized for analysis of Java + */ + public static AnalysisScope createJavaAnalysisScope() { + AnalysisScope scope = new AnalysisScope(Collections.singleton(Language.JAVA)); + scope.initForJava(); + return scope; + } + + /** + * Initialize a scope for java analysis + */ + protected void initForJava() { + initCoreForJava(); + initSynthetic(loadersByName.get(APPLICATION)); + } + + /** + * Initialize the standard 3 class loaders for java analysis + */ + protected void initCoreForJava() { + ClassLoaderReference primordial = new ClassLoaderReference(PRIMORDIAL, ClassLoaderReference.Java, null); + ClassLoaderReference extension = new ClassLoaderReference(EXTENSION, ClassLoaderReference.Java, primordial); + ClassLoaderReference application = new ClassLoaderReference(APPLICATION, ClassLoaderReference.Java, extension); + + loadersByName.put(PRIMORDIAL, primordial); + loadersByName.put(EXTENSION, extension); + loadersByName.put(APPLICATION, application); + } + + /** + * Create the class loader for synthetic classes. + */ + protected void initSynthetic(ClassLoaderReference parent) { + ClassLoaderReference synthetic = new ClassLoaderReference(SYNTHETIC, ClassLoaderReference.Java, parent); + setLoaderImpl(synthetic, "com.ibm.wala.ipa.summaries.BypassSyntheticClassLoader"); + loadersByName.put(SYNTHETIC, synthetic); + } + + /** + * A set of classes to exclude from the analysis entirely. + */ + private SetOfClasses exclusions; + + final protected LinkedHashMap loadersByName = new LinkedHashMap(); + + /** + * Special class loader for array instances + */ + private final ArrayClassLoader arrayClassLoader = new ArrayClassLoader(); + + final private Map> moduleMap = HashMapFactory.make(3); + + private final Map languages; + + protected AnalysisScope(Collection languages) { + super(); + this.languages = new HashMap(); + for (Language l : languages) { + this.languages.put(l.getName(), l); + } + } + + public Language getLanguage(Atom name) { + return languages.get(name); + } + + public boolean isApplicationLoader(IClassLoader loader) { + return loader.getReference().equals(getLoader(APPLICATION)); + } + + /** + * Return the information regarding the primordial loader. + */ + public ClassLoaderReference getPrimordialLoader() { + return getLoader(PRIMORDIAL); + } + + /** + * Return the information regarding the extension loader. + */ + public ClassLoaderReference getExtensionLoader() { + return getLoader(EXTENSION); + } + + /** + * Return the information regarding the application loader. + */ + public ClassLoaderReference getApplicationLoader() { + return getLoader(APPLICATION); + } + + /** + * Return the information regarding the application loader. + */ + public ClassLoaderReference getSyntheticLoader() { + return getLoader(SYNTHETIC); + } + + /** + * @return the set of languages to be processed during this analysis session. + */ + public Collection getLanguages() { + return languages.values(); + } + + /** + * @return the set of "base languages," each of which defines a family of compatible languages, and therefore induces a distinct + * ClassHierarchy + */ + public Set getBaseLanguages() { + Set result = HashSetFactory.make(); + for (Language language : getLanguages()) { + if (language.getBaseLanguage() == null) { + result.add(language); + } + } + return result; + } + + /** + * Add a class file to the scope for a loader + */ + public void addSourceFileToScope(ClassLoaderReference loader, File file, String fileName) throws IllegalArgumentException { + List s = MapUtil.findOrCreateList(moduleMap, loader); + s.add(new SourceFileModule(file, fileName)); + } + + /** + * Add a class file to the scope for a loader + * @throws InvalidClassFileException + */ + public void addClassFileToScope(ClassLoaderReference loader, File file) throws IllegalArgumentException, InvalidClassFileException { + List s = MapUtil.findOrCreateList(moduleMap, loader); + s.add(new ClassFileModule(file)); + } + + /** + * Add a jar file to the scope for a loader + */ + public void addToScope(ClassLoaderReference loader, JarFile file) { + List s = MapUtil.findOrCreateList(moduleMap, loader); + if (DEBUG_LEVEL > 0) { + System.err.println(("AnalysisScope: add JarFileModule " + file.getName())); + } + s.add(new JarFileModule(file)); + } + + /** + * Add a module to the scope for a loader + */ + public void addToScope(ClassLoaderReference loader, Module m) { + if (m == null) { + throw new IllegalArgumentException("null m"); + } + List s = MapUtil.findOrCreateList(moduleMap, loader); + if (DEBUG_LEVEL > 0) { + System.err.println(("AnalysisScope: add module " + m)); + } + s.add(m); + } + + /** + * Add all modules from another scope + */ + public void addToScope(AnalysisScope other) { + if (other == null) { + throw new IllegalArgumentException("null other"); + } + for (ClassLoaderReference loader : other.getLoaders()) { + for (Module m : other.getModules(loader)) { + addToScope(loader, m); + } + } + } + + /** + * Add a module file to the scope for a loader. The classes in the added jar file will override classes added to the scope so far. + */ + public void addToScopeHead(ClassLoaderReference loader, Module m) { + if (m == null) { + throw new IllegalArgumentException("null m"); + } + List s = MapUtil.findOrCreateList(moduleMap, loader); + if (DEBUG_LEVEL > 0) { + System.err.println(("AnalysisScope: add overriding module " + m)); + } + s.add(0, m); + } + + /** + * @return the ClassLoaderReference specified by name. + * @throws IllegalArgumentException if name is null + */ + public ClassLoaderReference getLoader(Atom name) throws IllegalArgumentException { + if (name == null) { + throw new IllegalArgumentException("name is null"); + } + if (name.length() == 0) { + throw new IllegalArgumentException("empty atom is not a legal class loader name"); + } + /* + * if (Assertions.verifyAssertions) { if (name.getVal(0) > 'Z') { Assertions._assert(name.getVal(0) <= 'Z', + * "Classloader name improperly capitalised? (" + name + ")"); } } + */ + return loadersByName.get(name); + } + + protected ClassLoaderReference classLoaderName2Ref(String clName) { + return getLoader(Atom.findOrCreateUnicodeAtom(clName)); + } + + private final HashMap loaderImplByRef = HashMapFactory.make(); + + public String getLoaderImpl(ClassLoaderReference ref) { + return loaderImplByRef.get(ref); + } + + public void setLoaderImpl(ClassLoaderReference ref, String implClass) { + if (ref == null) { + throw new IllegalArgumentException("null ref"); + } + if (implClass == null) { + throw new IllegalArgumentException("null implClass"); + } + loaderImplByRef.put(ref, implClass); + } + + public Collection getLoaders() { + return Collections.unmodifiableCollection(loadersByName.values()); + } + + public int getNumberOfLoaders() { + return loadersByName.values().size(); + } + + public SetOfClasses getExclusions() { + return exclusions; + } + + public void setExclusions(SetOfClasses classes) { + exclusions = classes; + } + + @Override + public String toString() { + StringBuffer result = new StringBuffer(); + for (ClassLoaderReference loader : loadersByName.values()) { + result.append(loader.getName()); + result.append("\n"); + for (Module m : getModules(loader)) { + result.append(" "); + result.append(m); + result.append("\n"); + } + } + result.append(getExclusionString()); + result.append("\n"); + return result.toString(); + } + + /** + * @return a String that describes exclusions from the analysis scope. + */ + protected Object getExclusionString() { + return "Exclusions: " + exclusions; + } + + /** + * Utility function. Useful when parsing input. + */ + public MethodReference findMethod(Atom loader, String klass, Atom name, ImmutableByteArray desc) { + if (desc == null) { + throw new IllegalArgumentException("null desc"); + } + ClassLoaderReference clr = getLoader(loader); + Descriptor ddesc = Descriptor.findOrCreate(languages.get(clr.getLanguage()), desc); + TypeReference type = TypeReference.findOrCreate(clr, TypeName.string2TypeName(klass)); + return MethodReference.findOrCreate(type, name, ddesc); + } + + public List getModules(ClassLoaderReference loader) { + List result = moduleMap.get(loader); + List empty = Collections.emptyList(); + return result == null ? empty : result; + } + + /** + * @return Returns the arrayClassLoader. + */ + public ArrayClassLoader getArrayClassLoader() { + return arrayClassLoader; + } + + /** + * @return the rt.jar (1.4) or core.jar (1.5) file, or null if not found. + */ + private JarFile getRtJar() { + for (Iterator MS = getModules(getPrimordialLoader()).iterator(); MS.hasNext();) { + Module M = (Module) MS.next(); + if (M instanceof JarFileModule) { + JarFile JF = ((JarFileModule) M).getJarFile(); + if (JF.getName().endsWith(File.separator + "rt.jar")) { + return JF; + } + if (JF.getName().endsWith(File.separator + "core.jar")) { + return JF; + } + // hack for Mac + if (PlatformUtil.onMacOSX() && JF.getName().endsWith(File.separator + "classes.jar")) { + return JF; + } + } + } + return null; + } + + public String getJavaLibraryVersion() throws IllegalStateException { + JarFile rtJar = getRtJar(); + if (rtJar == null) { + throw new IllegalStateException("cannot find runtime libraries"); + } + try { + Manifest man = rtJar.getManifest(); + assert man != null : "runtime library has no manifest!"; + String result = man.getMainAttributes().getValue("Specification-Version"); + if (result == null) { + Attributes att = man.getMainAttributes(); + System.err.println("main attributes:" + att); + Assertions.UNREACHABLE("Manifest for " + rtJar.getName() + " has no value for Specification-Version"); + } + return result; + } catch (java.io.IOException e) { + Assertions.UNREACHABLE("error getting rt.jar manifest!"); + return null; + } + } + + public boolean isJava17Libraries() throws IllegalStateException { + return getJavaLibraryVersion().startsWith("1.7"); + } + + public boolean isJava16Libraries() throws IllegalStateException { + return getJavaLibraryVersion().startsWith("1.6"); + } + + public boolean isJava15Libraries() throws IllegalStateException { + return getJavaLibraryVersion().startsWith("1.5"); + } + + public boolean isJava14Libraries() throws IllegalStateException { + return getJavaLibraryVersion().startsWith("1.4"); + } + + /** + * Creates a "serializable" version of the analysis scope. + * + * @return a "serializable" version of the analysis scope. + * @throws NotSerializableException + */ + public ShallowAnalysisScope toShallowAnalysisScope() throws NotSerializableException { + + if (getArrayClassLoader().getNumberOfClasses() != 0) { + throw new NotSerializableException("Scope was already used for building array classes"); + } + // Note: 'arrayClassLoader' object will be built from scratch in remote process + + // represent modules map as a set of strings (corresponding to analysis scope file lines. + List moduleLines = new ArrayList(); + for (Map.Entry> e : moduleMap.entrySet()) { + ClassLoaderReference lrReference = e.getKey(); + String moduleLdr = lrReference.getName().toString(); + String moduleLang = lrReference.getLanguage().toString(); + assert Language.JAVA.getName().equals(lrReference.getLanguage()) : "Java language only is currently supported"; + + for (Module m : e.getValue()) { + String moduleType; + String modulePath; + if (m instanceof JarFileModule) { + moduleType = "jarFile"; + modulePath = ((JarFileModule) m).getAbsolutePath(); + } else if (m instanceof BinaryDirectoryTreeModule) { + moduleType = "binaryDir"; + modulePath = ((BinaryDirectoryTreeModule) m).getPath(); + } else if (m instanceof SourceDirectoryTreeModule) { + moduleType = "sourceDir"; + modulePath = ((SourceDirectoryTreeModule) m).getPath(); + } else if (m instanceof SourceFileModule) { + moduleType = "sourceFile"; + modulePath = ((SourceFileModule) m).getAbsolutePath(); + } else { + Assertions.UNREACHABLE("Module type isn't supported - " + m); + continue; + } + modulePath.replace("\\", "/"); + String moduleDescrLine = String.format("%s,%s,%s,%s", moduleLdr, moduleLang, moduleType, modulePath); + moduleLines.add(moduleDescrLine); + } + } + + // represent loaderImplByRef map as set of strings + List ldrImplLines = new ArrayList(); + for (Map.Entry e : loaderImplByRef.entrySet()) { + ClassLoaderReference lrReference = e.getKey(); + String ldrName = lrReference.getName().toString(); + String ldrLang = lrReference.getLanguage().toString(); + assert Language.JAVA.getName().equals(lrReference.getLanguage()) : "Java language only is currently supported"; + String ldrImplName = e.getValue(); + String ldrImplDescrLine = String.format("%s,%s,%s,%s", ldrName, ldrLang, "loaderImpl", ldrImplName); + ldrImplLines.add(ldrImplDescrLine); + } + + ShallowAnalysisScope shallowScope = new ShallowAnalysisScope(getExclusions(), moduleLines, ldrImplLines); + return shallowScope; + } +} diff --git a/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/CGNode.java b/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/CGNode.java index 0295053a4..106a7a4b2 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/CGNode.java +++ b/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/CGNode.java @@ -1,73 +1,73 @@ -/******************************************************************************* - * Copyright (c) 2002 - 2006 IBM Corporation. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * IBM Corporation - initial API and implementation - *******************************************************************************/ -package com.ibm.wala.ipa.callgraph; - -import java.util.Iterator; - -import com.ibm.wala.classLoader.CallSiteReference; -import com.ibm.wala.classLoader.IMethod; -import com.ibm.wala.classLoader.NewSiteReference; -import com.ibm.wala.ipa.cha.IClassHierarchyDweller; -import com.ibm.wala.ssa.DefUse; -import com.ibm.wala.ssa.IR; -import com.ibm.wala.util.graph.INodeWithNumber; - -/** - * Basic interface for a node in a call graph. - */ -public interface CGNode extends INodeWithNumber, ContextItem, IClassHierarchyDweller { - /** - * Return the {@link IMethod method} this CGNode represents. - * This value will never be null. - * - * @return the target IMethod for this CGNode. - */ - public IMethod getMethod(); - - /** - * Return the {@link Context context} this CGNode represents. - * This value will never be null. - * - * @return the Context for this CGNode. - */ - public Context getContext(); - - /** - * This is for use only by call graph builders ... not by the general - * public. Clients should not use this. - * - * Record that a particular call site might resolve to a call to a - * particular target node. Returns true if this is a new target - */ - @Deprecated - public boolean addTarget(CallSiteReference site, CGNode target); - - /** - * @return the "default" IR for this node used by the governing call graph - */ - public IR getIR(); - - /** - * @return DefUse for the "default" IR for this node used by the governing call graph - */ - public DefUse getDU(); - - /** - * @return an Iterator of the types that may be allocated by a given - * method in a given context. - */ - public Iterator iterateNewSites(); - /** - * @return an Iterator of the call statements that may execute - * in a given method for a given context - */ - public Iterator iterateCallSites(); -} +/******************************************************************************* + * 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.ipa.callgraph; + +import java.util.Iterator; + +import com.ibm.wala.classLoader.CallSiteReference; +import com.ibm.wala.classLoader.IMethod; +import com.ibm.wala.classLoader.NewSiteReference; +import com.ibm.wala.ipa.cha.IClassHierarchyDweller; +import com.ibm.wala.ssa.DefUse; +import com.ibm.wala.ssa.IR; +import com.ibm.wala.util.graph.INodeWithNumber; + +/** + * Basic interface for a node in a call graph. + */ +public interface CGNode extends INodeWithNumber, ContextItem, IClassHierarchyDweller { + /** + * Return the {@link IMethod method} this CGNode represents. + * This value will never be null. + * + * @return the target IMethod for this CGNode. + */ + public IMethod getMethod(); + + /** + * Return the {@link Context context} this CGNode represents. + * This value will never be null. + * + * @return the Context for this CGNode. + */ + public Context getContext(); + + /** + * This is for use only by call graph builders ... not by the general + * public. Clients should not use this. + * + * Record that a particular call site might resolve to a call to a + * particular target node. Returns true if this is a new target + */ + @Deprecated + public boolean addTarget(CallSiteReference site, CGNode target); + + /** + * @return the "default" IR for this node used by the governing call graph + */ + public IR getIR(); + + /** + * @return DefUse for the "default" IR for this node used by the governing call graph + */ + public DefUse getDU(); + + /** + * @return an Iterator of the types that may be allocated by a given + * method in a given context. + */ + public Iterator iterateNewSites(); + /** + * @return an Iterator of the call statements that may execute + * in a given method for a given context + */ + public Iterator iterateCallSites(); +} diff --git a/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/CallGraph.java b/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/CallGraph.java index 9677350cd..e360392aa 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/CallGraph.java +++ b/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/CallGraph.java @@ -1,74 +1,74 @@ -/******************************************************************************* - * 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.ipa.callgraph; - -import java.util.Collection; -import java.util.Iterator; -import java.util.Set; - -import com.ibm.wala.classLoader.CallSiteReference; -import com.ibm.wala.classLoader.IMethod; -import com.ibm.wala.ipa.cha.IClassHierarchy; -import com.ibm.wala.types.MethodReference; -import com.ibm.wala.util.graph.NumberedGraph; - -/** - * Basic interface for a call graph, which is a graph of {@link CGNode} - */ -public interface CallGraph extends NumberedGraph { - - /** - * Return the (fake) interprocedural {@link CGNode root node} of the call graph. - * - * @return the "fake" root node the call graph - */ - public CGNode getFakeRootNode(); - - /** - * @return an Iterator of the nodes designated as "root nodes" - */ - public Collection getEntrypointNodes(); - - /** - * If you want to get all the nodes corresponding to a particular method, regardless of context, then use - * {@link CGNode getNodes} - * - * @return the node corresponding a method in a context - */ - public CGNode getNode(IMethod method, Context C); - - /** - * @param m a method reference - * @return the set of all nodes in the call graph that represent this method. - */ - public Set getNodes(MethodReference m); - - /** - * @return the governing class hierarchy for this call graph - */ - public IClassHierarchy getClassHierarchy(); - - /** - * Return the set of CGNodes that represent possible targets of a particular call site from a particular node - */ - public Set getPossibleTargets(CGNode node, CallSiteReference site); - - /** - * @return the number of nodes that the call site may dispatch to - */ - public int getNumberOfTargets(CGNode node, CallSiteReference site); - - /** - * @return iterator of CallSiteReference, the call sites in a node that might dispatch to the target node. - */ - Iterator getPossibleSites(CGNode src, CGNode target); - -} +/******************************************************************************* + * 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.ipa.callgraph; + +import java.util.Collection; +import java.util.Iterator; +import java.util.Set; + +import com.ibm.wala.classLoader.CallSiteReference; +import com.ibm.wala.classLoader.IMethod; +import com.ibm.wala.ipa.cha.IClassHierarchy; +import com.ibm.wala.types.MethodReference; +import com.ibm.wala.util.graph.NumberedGraph; + +/** + * Basic interface for a call graph, which is a graph of {@link CGNode} + */ +public interface CallGraph extends NumberedGraph { + + /** + * Return the (fake) interprocedural {@link CGNode root node} of the call graph. + * + * @return the "fake" root node the call graph + */ + public CGNode getFakeRootNode(); + + /** + * @return an Iterator of the nodes designated as "root nodes" + */ + public Collection getEntrypointNodes(); + + /** + * If you want to get all the nodes corresponding to a particular method, regardless of context, then use + * {@link CGNode getNodes} + * + * @return the node corresponding a method in a context + */ + public CGNode getNode(IMethod method, Context C); + + /** + * @param m a method reference + * @return the set of all nodes in the call graph that represent this method. + */ + public Set getNodes(MethodReference m); + + /** + * @return the governing class hierarchy for this call graph + */ + public IClassHierarchy getClassHierarchy(); + + /** + * Return the set of CGNodes that represent possible targets of a particular call site from a particular node + */ + public Set getPossibleTargets(CGNode node, CallSiteReference site); + + /** + * @return the number of nodes that the call site may dispatch to + */ + public int getNumberOfTargets(CGNode node, CallSiteReference site); + + /** + * @return iterator of CallSiteReference, the call sites in a node that might dispatch to the target node. + */ + Iterator getPossibleSites(CGNode src, CGNode target); + +} diff --git a/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/CallGraphBuilder.java b/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/CallGraphBuilder.java index d40b2e51a..baadcadaa 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/CallGraphBuilder.java +++ b/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/CallGraphBuilder.java @@ -1,40 +1,40 @@ -/******************************************************************************* - * Copyright (c) 2002 - 2006 IBM Corporation. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * IBM Corporation - initial API and implementation - *******************************************************************************/ -package com.ibm.wala.ipa.callgraph; - - -import com.ibm.wala.ipa.callgraph.propagation.PointerAnalysis; -import com.ibm.wala.util.MonitorUtil.IProgressMonitor; - -/** - * Basic interface for an object that can build a call graph. - */ -public interface CallGraphBuilder { - /** - * Build a call graph. - * - * @param options an object representing controlling options that the call graph building algorithm needs to know. - * @return the built call graph - */ - public CallGraph makeCallGraph(AnalysisOptions options, IProgressMonitor monitor) throws IllegalArgumentException, - CallGraphBuilderCancelException; - - /** - * @return the Pointer Analysis information computed as a side-effect of call graph construction. - */ - public PointerAnalysis getPointerAnalysis(); - - /** - * @return A cache of various analysis artifacts used during call graph construction. - */ - public AnalysisCache getAnalysisCache(); - -} +/******************************************************************************* + * 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.ipa.callgraph; + + +import com.ibm.wala.ipa.callgraph.propagation.PointerAnalysis; +import com.ibm.wala.util.MonitorUtil.IProgressMonitor; + +/** + * Basic interface for an object that can build a call graph. + */ +public interface CallGraphBuilder { + /** + * Build a call graph. + * + * @param options an object representing controlling options that the call graph building algorithm needs to know. + * @return the built call graph + */ + public CallGraph makeCallGraph(AnalysisOptions options, IProgressMonitor monitor) throws IllegalArgumentException, + CallGraphBuilderCancelException; + + /** + * @return the Pointer Analysis information computed as a side-effect of call graph construction. + */ + public PointerAnalysis getPointerAnalysis(); + + /** + * @return A cache of various analysis artifacts used during call graph construction. + */ + public AnalysisCache getAnalysisCache(); + +} diff --git a/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/CallGraphBuilderCancelException.java b/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/CallGraphBuilderCancelException.java index 06914176b..946923cf0 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/CallGraphBuilderCancelException.java +++ b/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/CallGraphBuilderCancelException.java @@ -1,62 +1,62 @@ -/******************************************************************************* - * Copyright (c) 2007 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.ipa.callgraph; - -import com.ibm.wala.ipa.callgraph.propagation.PointerAnalysis; -import com.ibm.wala.util.CancelException; - -/** - * An exception to throw when call graph construction is canceled. This exception allows clients to retrieve the partially-built - * call graph and pointer analysis - */ -public class CallGraphBuilderCancelException extends CancelException { - - private final CallGraph cg; - - private final PointerAnalysis pointerAnalysis; - - public static CallGraphBuilderCancelException createCallGraphBuilderCancelException(Exception cause, CallGraph cg, - PointerAnalysis pointerAnalysis) { - return new CallGraphBuilderCancelException(cause, cg, pointerAnalysis); - } - - public static CallGraphBuilderCancelException createCallGraphBuilderCancelException(String msg, CallGraph cg, - PointerAnalysis pointerAnalysis) { - return new CallGraphBuilderCancelException(msg, cg, pointerAnalysis); - } - - /** - * @return the {@link CallGraph} in whatever state it was left when computation was canceled - */ - public CallGraph getPartialCallGraph() { - return cg; - } - - /** - * @return the {@link PointerAnalysis} in whatever state it was left when computation was canceled - */ - public PointerAnalysis getPartialPointerAnalysis() { - return pointerAnalysis; - } - - private CallGraphBuilderCancelException(String msg, CallGraph cg, PointerAnalysis pointerAnalysis) { - super(msg); - this.cg = cg; - this.pointerAnalysis = pointerAnalysis; - } - - private CallGraphBuilderCancelException(Exception cause, CallGraph cg, PointerAnalysis pointerAnalysis) { - super(cause); - this.cg = cg; - this.pointerAnalysis = pointerAnalysis; - } - -} +/******************************************************************************* + * Copyright (c) 2007 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.ipa.callgraph; + +import com.ibm.wala.ipa.callgraph.propagation.PointerAnalysis; +import com.ibm.wala.util.CancelException; + +/** + * An exception to throw when call graph construction is canceled. This exception allows clients to retrieve the partially-built + * call graph and pointer analysis + */ +public class CallGraphBuilderCancelException extends CancelException { + + private final CallGraph cg; + + private final PointerAnalysis pointerAnalysis; + + public static CallGraphBuilderCancelException createCallGraphBuilderCancelException(Exception cause, CallGraph cg, + PointerAnalysis pointerAnalysis) { + return new CallGraphBuilderCancelException(cause, cg, pointerAnalysis); + } + + public static CallGraphBuilderCancelException createCallGraphBuilderCancelException(String msg, CallGraph cg, + PointerAnalysis pointerAnalysis) { + return new CallGraphBuilderCancelException(msg, cg, pointerAnalysis); + } + + /** + * @return the {@link CallGraph} in whatever state it was left when computation was canceled + */ + public CallGraph getPartialCallGraph() { + return cg; + } + + /** + * @return the {@link PointerAnalysis} in whatever state it was left when computation was canceled + */ + public PointerAnalysis getPartialPointerAnalysis() { + return pointerAnalysis; + } + + private CallGraphBuilderCancelException(String msg, CallGraph cg, PointerAnalysis pointerAnalysis) { + super(msg); + this.cg = cg; + this.pointerAnalysis = pointerAnalysis; + } + + private CallGraphBuilderCancelException(Exception cause, CallGraph cg, PointerAnalysis pointerAnalysis) { + super(cause); + this.cg = cg; + this.pointerAnalysis = pointerAnalysis; + } + +} diff --git a/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/CallGraphStats.java b/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/CallGraphStats.java index 8864f7b15..8e37f04e0 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/CallGraphStats.java +++ b/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/CallGraphStats.java @@ -1,178 +1,178 @@ -/******************************************************************************* - * 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.ipa.callgraph; - -import java.util.Collections; -import java.util.HashSet; -import java.util.Iterator; -import java.util.Set; - -import com.ibm.wala.classLoader.IMethod; -import com.ibm.wala.classLoader.ShrikeCTMethod; -import com.ibm.wala.types.MethodReference; -import com.ibm.wala.util.collections.HashSetFactory; -import com.ibm.wala.util.graph.traverse.DFS; - -/** - * Collect basic call graph statistics - */ -public class CallGraphStats { - - public static class CGStats { - - private final int nNodes; - - private final int nEdges; - - private final int nMethods; - - private final int bytecodeBytes; - - private CGStats(int nodes, int edges, int methods, int bytecodeBytes) { - super(); - nNodes = nodes; - nEdges = edges; - nMethods = methods; - this.bytecodeBytes = bytecodeBytes; - } - - public int getNNodes() { - return nNodes; - } - - public int getNEdges() { - return nEdges; - } - - public int getNMethods() { - return nMethods; - } - - public int getBytecodeBytes() { - return bytecodeBytes; - } - - @Override - public int hashCode() { - final int prime = 31; - int result = 1; - result = prime * result + bytecodeBytes; - result = prime * result + nEdges; - result = prime * result + nMethods; - result = prime * result + nNodes; - return result; - } - - @Override - public boolean equals(Object obj) { - if (this == obj) - return true; - if (obj == null) - return false; - if (getClass() != obj.getClass()) - return false; - CGStats other = (CGStats) obj; - if (bytecodeBytes != other.bytecodeBytes) - return false; - if (nEdges != other.nEdges) - return false; - if (nMethods != other.nMethods) - return false; - if (nNodes != other.nNodes) - return false; - return true; - } - - @Override - public String toString() { - StringBuffer result = new StringBuffer(); - result.append("Call graph stats:"); - result.append("\n"); - result.append(" Nodes: " + nNodes); - result.append("\n"); - result.append(" Edges: " + nEdges); - result.append("\n"); - result.append(" Methods: " + nMethods); - result.append("\n"); - result.append(" Bytecode Bytes: " + bytecodeBytes); - result.append("\n"); - return result.toString(); - - } - } - - public static CGStats getCGStats(CallGraph cg) { - if (cg == null) { - throw new IllegalArgumentException("cg is null"); - } - Set reachableNodes = DFS.getReachableNodes(cg, Collections.singleton(cg.getFakeRootNode())); - int nNodes = 0; - int nEdges = 0; - for (Iterator it = reachableNodes.iterator(); it.hasNext();) { - CGNode n = it.next(); - nNodes++; - nEdges += cg.getSuccNodeCount(n); - } - return new CGStats(nNodes, nEdges, collectMethods(cg).size(), countBytecodeBytes(cg)); - } - - /** - * @throws IllegalArgumentException if cg is null - */ - public static String getStats(CallGraph cg) { - return getCGStats(cg).toString(); - } - - /** - * @param cg - * @return the number of bytecode bytes - * @throws IllegalArgumentException if cg is null - */ - public static int countBytecodeBytes(CallGraph cg) { - if (cg == null) { - throw new IllegalArgumentException("cg is null"); - } - int ret = 0; - HashSet counted = HashSetFactory.make(); - for (Iterator iter = cg.iterator(); iter.hasNext();) { - CGNode node = iter.next(); - IMethod method = node.getMethod(); - if (counted.add(method)) { - if (method instanceof ShrikeCTMethod) { - byte[] bytecodes = ((ShrikeCTMethod) method).getBytecodes(); - if (bytecodes != null) { - ret += bytecodes.length; - } - } - } - } - return ret; - } - - /** - * Walk the call graph and return the set of MethodReferences that appear in the graph. - * - * @param cg - * @return a set of MethodReferences - * @throws IllegalArgumentException if cg is null - */ - public static Set collectMethods(CallGraph cg) { - if (cg == null) { - throw new IllegalArgumentException("cg is null"); - } - HashSet result = HashSetFactory.make(); - for (Iterator it = cg.iterator(); it.hasNext();) { - CGNode N = (CGNode) it.next(); - result.add(N.getMethod().getReference()); - } - return result; - } -} +/******************************************************************************* + * 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.ipa.callgraph; + +import java.util.Collections; +import java.util.HashSet; +import java.util.Iterator; +import java.util.Set; + +import com.ibm.wala.classLoader.IMethod; +import com.ibm.wala.classLoader.ShrikeCTMethod; +import com.ibm.wala.types.MethodReference; +import com.ibm.wala.util.collections.HashSetFactory; +import com.ibm.wala.util.graph.traverse.DFS; + +/** + * Collect basic call graph statistics + */ +public class CallGraphStats { + + public static class CGStats { + + private final int nNodes; + + private final int nEdges; + + private final int nMethods; + + private final int bytecodeBytes; + + private CGStats(int nodes, int edges, int methods, int bytecodeBytes) { + super(); + nNodes = nodes; + nEdges = edges; + nMethods = methods; + this.bytecodeBytes = bytecodeBytes; + } + + public int getNNodes() { + return nNodes; + } + + public int getNEdges() { + return nEdges; + } + + public int getNMethods() { + return nMethods; + } + + public int getBytecodeBytes() { + return bytecodeBytes; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + bytecodeBytes; + result = prime * result + nEdges; + result = prime * result + nMethods; + result = prime * result + nNodes; + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + CGStats other = (CGStats) obj; + if (bytecodeBytes != other.bytecodeBytes) + return false; + if (nEdges != other.nEdges) + return false; + if (nMethods != other.nMethods) + return false; + if (nNodes != other.nNodes) + return false; + return true; + } + + @Override + public String toString() { + StringBuffer result = new StringBuffer(); + result.append("Call graph stats:"); + result.append("\n"); + result.append(" Nodes: " + nNodes); + result.append("\n"); + result.append(" Edges: " + nEdges); + result.append("\n"); + result.append(" Methods: " + nMethods); + result.append("\n"); + result.append(" Bytecode Bytes: " + bytecodeBytes); + result.append("\n"); + return result.toString(); + + } + } + + public static CGStats getCGStats(CallGraph cg) { + if (cg == null) { + throw new IllegalArgumentException("cg is null"); + } + Set reachableNodes = DFS.getReachableNodes(cg, Collections.singleton(cg.getFakeRootNode())); + int nNodes = 0; + int nEdges = 0; + for (Iterator it = reachableNodes.iterator(); it.hasNext();) { + CGNode n = it.next(); + nNodes++; + nEdges += cg.getSuccNodeCount(n); + } + return new CGStats(nNodes, nEdges, collectMethods(cg).size(), countBytecodeBytes(cg)); + } + + /** + * @throws IllegalArgumentException if cg is null + */ + public static String getStats(CallGraph cg) { + return getCGStats(cg).toString(); + } + + /** + * @param cg + * @return the number of bytecode bytes + * @throws IllegalArgumentException if cg is null + */ + public static int countBytecodeBytes(CallGraph cg) { + if (cg == null) { + throw new IllegalArgumentException("cg is null"); + } + int ret = 0; + HashSet counted = HashSetFactory.make(); + for (Iterator iter = cg.iterator(); iter.hasNext();) { + CGNode node = iter.next(); + IMethod method = node.getMethod(); + if (counted.add(method)) { + if (method instanceof ShrikeCTMethod) { + byte[] bytecodes = ((ShrikeCTMethod) method).getBytecodes(); + if (bytecodes != null) { + ret += bytecodes.length; + } + } + } + } + return ret; + } + + /** + * Walk the call graph and return the set of MethodReferences that appear in the graph. + * + * @param cg + * @return a set of MethodReferences + * @throws IllegalArgumentException if cg is null + */ + public static Set collectMethods(CallGraph cg) { + if (cg == null) { + throw new IllegalArgumentException("cg is null"); + } + HashSet result = HashSetFactory.make(); + for (Iterator it = cg.iterator(); it.hasNext();) { + CGNode N = (CGNode) it.next(); + result.add(N.getMethod().getReference()); + } + return result; + } +} diff --git a/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/ClassTargetSelector.java b/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/ClassTargetSelector.java index 4ac3e8b55..13ca3f6b2 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/ClassTargetSelector.java +++ b/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/ClassTargetSelector.java @@ -1,41 +1,41 @@ -/******************************************************************************* - * 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.ipa.callgraph; - -import com.ibm.wala.classLoader.IClass; -import com.ibm.wala.classLoader.NewSiteReference; - -/** - * This interface represents policies for selecting a class to allocate at a given new site. The most obvious such policy would be - * to look at the relevant class hierarchy and lookup the appropriate class based on the type reference at the new site. However, - * other policies are possible for purposes such as providing an abstraction of unanalyzed libraries or specialized J2EE - * functionality. - * - * Such policies are consulted by the different analysis mechanisms, both the flow-based and non-flow algorithms. The current - * mechanism is that the policy object are registered with the AnalysisOptions object, and all analyses that need to analyze - * allocations ask that object for the class selector to use. - * - * In general, for specialized selectors, it is good practice to build selectors that handle the special case of interest, and - * otherwise delegate to a child selector. When registering with the AnalysisOptions object, make the child selector be whatever the - * options object had before. - */ -public interface ClassTargetSelector { - - /** - * Given a calling node and a new site, return the type to be allocated. - * - * @param caller the GCNode in the call graph containing the new site. - * @param site the new site reference of the new site. - * @return the class to be allocated. - */ - IClass getAllocatedTarget(CGNode caller, NewSiteReference site); - -} +/******************************************************************************* + * 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.ipa.callgraph; + +import com.ibm.wala.classLoader.IClass; +import com.ibm.wala.classLoader.NewSiteReference; + +/** + * This interface represents policies for selecting a class to allocate at a given new site. The most obvious such policy would be + * to look at the relevant class hierarchy and lookup the appropriate class based on the type reference at the new site. However, + * other policies are possible for purposes such as providing an abstraction of unanalyzed libraries or specialized J2EE + * functionality. + * + * Such policies are consulted by the different analysis mechanisms, both the flow-based and non-flow algorithms. The current + * mechanism is that the policy object are registered with the AnalysisOptions object, and all analyses that need to analyze + * allocations ask that object for the class selector to use. + * + * In general, for specialized selectors, it is good practice to build selectors that handle the special case of interest, and + * otherwise delegate to a child selector. When registering with the AnalysisOptions object, make the child selector be whatever the + * options object had before. + */ +public interface ClassTargetSelector { + + /** + * Given a calling node and a new site, return the type to be allocated. + * + * @param caller the GCNode in the call graph containing the new site. + * @param site the new site reference of the new site. + * @return the class to be allocated. + */ + IClass getAllocatedTarget(CGNode caller, NewSiteReference site); + +} diff --git a/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/Context.java b/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/Context.java index f48c05dee..7d9c76ff3 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/Context.java +++ b/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/Context.java @@ -1,26 +1,26 @@ -/******************************************************************************* - * Copyright (c) 2002 - 2006 IBM Corporation. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * IBM Corporation - initial API and implementation - *******************************************************************************/ -package com.ibm.wala.ipa.callgraph; - -/** - * A Context is a mapping from a name (ContextKey) to a value (ContextItem) - * - * For example, for CFA-1, there is only one name ("caller"); and the context maps "caller" to an IMethod - * - * As another example, for CPA, there would be name for each parameter slot ("zero","one","two"), and the Context provides a mapping - * from this name to a set of types. eg. "one" -> {java.lang.String, java.lang.Date} - */ -public interface Context { - /** - * @return the objects corresponding to a given name - */ - ContextItem get(ContextKey name); -} +/******************************************************************************* + * 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.ipa.callgraph; + +/** + * A Context is a mapping from a name (ContextKey) to a value (ContextItem) + * + * For example, for CFA-1, there is only one name ("caller"); and the context maps "caller" to an IMethod + * + * As another example, for CPA, there would be name for each parameter slot ("zero","one","two"), and the Context provides a mapping + * from this name to a set of types. eg. "one" -> {java.lang.String, java.lang.Date} + */ +public interface Context { + /** + * @return the objects corresponding to a given name + */ + ContextItem get(ContextKey name); +} diff --git a/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/ContextItem.java b/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/ContextItem.java index d5ee77481..8398d49aa 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/ContextItem.java +++ b/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/ContextItem.java @@ -1,57 +1,57 @@ -/******************************************************************************* - * 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.ipa.callgraph; - -/** - * A placeholder for strong typing. - */ -public interface ContextItem { - - public class Value implements ContextItem { - private final T v; - - public Value(T v) { - this.v = v; - } - - public T getValue() { - return v; - } - - public static Value make(T v) { - return new Value(v); - } - - @Override - public int hashCode() { - return 31 + ((v == null) ? 0 : v.hashCode()); - } - - @Override - public boolean equals(Object obj) { - if (this == obj) - return true; - if (obj == null) - return false; - if (getClass() != obj.getClass()) - return false; - Value other = (Value) obj; - if (v == null) { - if (other.v != null) - return false; - } else if (!v.equals(other.v)) - return false; - return true; - } - - } -} +/******************************************************************************* + * 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.ipa.callgraph; + +/** + * A placeholder for strong typing. + */ +public interface ContextItem { + + public class Value implements ContextItem { + private final T v; + + public Value(T v) { + this.v = v; + } + + public T getValue() { + return v; + } + + public static Value make(T v) { + return new Value(v); + } + + @Override + public int hashCode() { + return 31 + ((v == null) ? 0 : v.hashCode()); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + Value other = (Value) obj; + if (v == null) { + if (other.v != null) + return false; + } else if (!v.equals(other.v)) + return false; + return true; + } + + } +} diff --git a/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/ContextKey.java b/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/ContextKey.java index e5c11311b..154eed38f 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/ContextKey.java +++ b/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/ContextKey.java @@ -1,107 +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.ipa.callgraph; - -/** - * This just exists to enforce strong typing. - */ -public interface ContextKey { - - /** - * A property of contexts that might be generally useful: the "caller" method ... used for call-string context schemes. - */ - public final static ContextKey CALLER = new ContextKey() { - }; - - /** - * A property of contexts that might be generally useful: the "call site" method ... used for call-string context schemes. - */ - public final static ContextKey CALLSITE = new ContextKey() { - }; - - /** - * A property of contexts that might be generally useful: an identifier for the receiver object ... used for object-sensitivity - * context policies. - * - * Known implementations (ContextItems) for RECEIVER include TypeAbstraction and InstanceKey - */ - public final static ContextKey RECEIVER = new ContextKey() { - }; - - /** - * context key representing some parameter index, useful, e.g. for CPA-style - * context-sensitivity policies. - */ - public static class ParameterKey implements ContextKey { - public final int index; - - public ParameterKey(int index) { - super(); - this.index = index; - } - } - - /** - * Generally useful constants for possible parameter indices - */ - public static final ContextKey PARAMETERS[] = new ContextKey[]{ - new ParameterKey(0), - new ParameterKey(1), - new ParameterKey(2), - new ParameterKey(3), - new ParameterKey(4), - new ParameterKey(5), - new ParameterKey(6), - new ParameterKey(7), - new ParameterKey(8), - new ParameterKey(9), - new ParameterKey(10), - new ParameterKey(11), - new ParameterKey(12), - new ParameterKey(13), - new ParameterKey(14), - new ParameterKey(15), - new ParameterKey(16), - new ParameterKey(17), - new ParameterKey(18), - new ParameterKey(19), - new ParameterKey(20), - new ParameterKey(21), - new ParameterKey(22), - new ParameterKey(23), - new ParameterKey(24), - new ParameterKey(25), - new ParameterKey(26), - new ParameterKey(27), - new ParameterKey(28), - new ParameterKey(29), - new ParameterKey(30), - new ParameterKey(31), - new ParameterKey(32), - new ParameterKey(33), - new ParameterKey(34), - new ParameterKey(35), - new ParameterKey(36), - new ParameterKey(37), - new ParameterKey(38), - new ParameterKey(39), - new ParameterKey(40), - new ParameterKey(41), - new ParameterKey(42), - new ParameterKey(43), - new ParameterKey(44), - new ParameterKey(45), - new ParameterKey(46), - new ParameterKey(47), - new ParameterKey(48), - new ParameterKey(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.ipa.callgraph; + +/** + * This just exists to enforce strong typing. + */ +public interface ContextKey { + + /** + * A property of contexts that might be generally useful: the "caller" method ... used for call-string context schemes. + */ + public final static ContextKey CALLER = new ContextKey() { + }; + + /** + * A property of contexts that might be generally useful: the "call site" method ... used for call-string context schemes. + */ + public final static ContextKey CALLSITE = new ContextKey() { + }; + + /** + * A property of contexts that might be generally useful: an identifier for the receiver object ... used for object-sensitivity + * context policies. + * + * Known implementations (ContextItems) for RECEIVER include TypeAbstraction and InstanceKey + */ + public final static ContextKey RECEIVER = new ContextKey() { + }; + + /** + * context key representing some parameter index, useful, e.g. for CPA-style + * context-sensitivity policies. + */ + public static class ParameterKey implements ContextKey { + public final int index; + + public ParameterKey(int index) { + super(); + this.index = index; + } + } + + /** + * Generally useful constants for possible parameter indices + */ + public static final ContextKey PARAMETERS[] = new ContextKey[]{ + new ParameterKey(0), + new ParameterKey(1), + new ParameterKey(2), + new ParameterKey(3), + new ParameterKey(4), + new ParameterKey(5), + new ParameterKey(6), + new ParameterKey(7), + new ParameterKey(8), + new ParameterKey(9), + new ParameterKey(10), + new ParameterKey(11), + new ParameterKey(12), + new ParameterKey(13), + new ParameterKey(14), + new ParameterKey(15), + new ParameterKey(16), + new ParameterKey(17), + new ParameterKey(18), + new ParameterKey(19), + new ParameterKey(20), + new ParameterKey(21), + new ParameterKey(22), + new ParameterKey(23), + new ParameterKey(24), + new ParameterKey(25), + new ParameterKey(26), + new ParameterKey(27), + new ParameterKey(28), + new ParameterKey(29), + new ParameterKey(30), + new ParameterKey(31), + new ParameterKey(32), + new ParameterKey(33), + new ParameterKey(34), + new ParameterKey(35), + new ParameterKey(36), + new ParameterKey(37), + new ParameterKey(38), + new ParameterKey(39), + new ParameterKey(40), + new ParameterKey(41), + new ParameterKey(42), + new ParameterKey(43), + new ParameterKey(44), + new ParameterKey(45), + new ParameterKey(46), + new ParameterKey(47), + new ParameterKey(48), + new ParameterKey(49) + }; +} diff --git a/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/ContextSelector.java b/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/ContextSelector.java index d1f5b2b48..66e399cc2 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/ContextSelector.java +++ b/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/ContextSelector.java @@ -1,42 +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.ipa.callgraph; - -import com.ibm.wala.classLoader.CallSiteReference; -import com.ibm.wala.classLoader.IMethod; -import com.ibm.wala.ipa.callgraph.propagation.InstanceKey; -import com.ibm.wala.util.intset.IntSet; - -/** - * An interface to an object which helps control context-sensitivity. - */ -public interface ContextSelector { - /** - * Given a calling node and a call site, returns the Context in which the callee should be evaluated. - * - * @param caller the node containing the call site - * @param site description of the call site - * @param actualParameters the abstract objects (InstanceKeys) of parameters of interest to the selector - * @return the Context in which the callee should be evaluated, or null if no information is available. - */ - Context getCalleeTarget(CGNode caller, CallSiteReference site, IMethod callee, InstanceKey[] actualParameters); - - /** - * Given a calling node and a call site, return the set of parameters based - * on which this selector may choose to specialize contexts. - * - * @param caller the calling node - * @param site the specific call site - * @return the set of parameters of interest - */ - IntSet getRelevantParameters(CGNode caller, CallSiteReference site); - -} +/******************************************************************************* + * 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.ipa.callgraph; + +import com.ibm.wala.classLoader.CallSiteReference; +import com.ibm.wala.classLoader.IMethod; +import com.ibm.wala.ipa.callgraph.propagation.InstanceKey; +import com.ibm.wala.util.intset.IntSet; + +/** + * An interface to an object which helps control context-sensitivity. + */ +public interface ContextSelector { + /** + * Given a calling node and a call site, returns the Context in which the callee should be evaluated. + * + * @param caller the node containing the call site + * @param site description of the call site + * @param actualParameters the abstract objects (InstanceKeys) of parameters of interest to the selector + * @return the Context in which the callee should be evaluated, or null if no information is available. + */ + Context getCalleeTarget(CGNode caller, CallSiteReference site, IMethod callee, InstanceKey[] actualParameters); + + /** + * Given a calling node and a call site, return the set of parameters based + * on which this selector may choose to specialize contexts. + * + * @param caller the calling node + * @param site the specific call site + * @return the set of parameters of interest + */ + IntSet getRelevantParameters(CGNode caller, CallSiteReference site); + +} diff --git a/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/ContextUtil.java b/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/ContextUtil.java index 30ddc5c7f..170d7e2ab 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/ContextUtil.java +++ b/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/ContextUtil.java @@ -1,48 +1,48 @@ -/******************************************************************************* - * Copyright (c) 2002 - 2006 IBM Corporation. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * IBM Corporation - initial API and implementation - *******************************************************************************/ -package com.ibm.wala.ipa.callgraph; - -import com.ibm.wala.analysis.typeInference.PointType; -import com.ibm.wala.classLoader.IClass; -import com.ibm.wala.ipa.callgraph.propagation.InstanceKey; -import com.ibm.wala.util.debug.Assertions; - -/** - * misc utilities for dealing with contexts - */ -public class ContextUtil { - - /** - * @param c a context - * @return If this is an object-sensitive context that identifies a unique class for the receiver object, then return the unique - * class. Else, return null. - * @throws IllegalArgumentException if c is null - */ - public static IClass getConcreteClassFromContext(Context c) { - if (c == null) { - throw new IllegalArgumentException("c is null"); - } - ContextItem item = c.get(ContextKey.RECEIVER); - if (item == null) { - return null; - } else { - if (item instanceof PointType) { - return ((PointType) item).getIClass(); - } else if (item instanceof InstanceKey) { - return ((InstanceKey) item).getConcreteType(); - } else { - Assertions.UNREACHABLE("Unexpected: " + item.getClass()); - return null; - } - } - } - -} +/******************************************************************************* + * 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.ipa.callgraph; + +import com.ibm.wala.analysis.typeInference.PointType; +import com.ibm.wala.classLoader.IClass; +import com.ibm.wala.ipa.callgraph.propagation.InstanceKey; +import com.ibm.wala.util.debug.Assertions; + +/** + * misc utilities for dealing with contexts + */ +public class ContextUtil { + + /** + * @param c a context + * @return If this is an object-sensitive context that identifies a unique class for the receiver object, then return the unique + * class. Else, return null. + * @throws IllegalArgumentException if c is null + */ + public static IClass getConcreteClassFromContext(Context c) { + if (c == null) { + throw new IllegalArgumentException("c is null"); + } + ContextItem item = c.get(ContextKey.RECEIVER); + if (item == null) { + return null; + } else { + if (item instanceof PointType) { + return ((PointType) item).getIClass(); + } else if (item instanceof InstanceKey) { + return ((InstanceKey) item).getConcreteType(); + } else { + Assertions.UNREACHABLE("Unexpected: " + item.getClass()); + return null; + } + } + } + +} diff --git a/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/Entrypoint.java b/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/Entrypoint.java index 28a1d686e..f51a5c2d7 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/Entrypoint.java +++ b/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/Entrypoint.java @@ -1,211 +1,211 @@ -/******************************************************************************* - * 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.ipa.callgraph; - -import java.util.Arrays; - -import com.ibm.wala.analysis.typeInference.ConeType; -import com.ibm.wala.analysis.typeInference.PrimitiveType; -import com.ibm.wala.analysis.typeInference.TypeAbstraction; -import com.ibm.wala.classLoader.CallSiteReference; -import com.ibm.wala.classLoader.IClass; -import com.ibm.wala.classLoader.IMethod; -import com.ibm.wala.ipa.callgraph.impl.AbstractRootMethod; -import com.ibm.wala.ipa.cha.IClassHierarchy; -import com.ibm.wala.shrikeBT.BytecodeConstants; -import com.ibm.wala.shrikeBT.IInvokeInstruction; -import com.ibm.wala.ssa.SSAAbstractInvokeInstruction; -import com.ibm.wala.ssa.SSANewInstruction; -import com.ibm.wala.types.MethodReference; -import com.ibm.wala.types.TypeReference; -import com.ibm.wala.util.debug.Assertions; - -/** - * A representation of an entrypoint in the call graph. - */ -public abstract class Entrypoint implements BytecodeConstants { - - /** - * The method to be called - */ - protected final IMethod method; - - /** - * @param method the method to be called for this entrypoint - */ - protected Entrypoint(IMethod method) { - if (method == null) { - throw new IllegalArgumentException("method is null"); - } - this.method = method; - assert method.getDeclaringClass() != null : "null declaring class"; - } - - protected Entrypoint(MethodReference method, IClassHierarchy cha) { - if (cha == null) { - throw new IllegalArgumentException("cha is null"); - } - IMethod m = cha.resolveMethod(method); - if (m == null) { - Assertions.UNREACHABLE("could not resolve " + method); - } - this.method = m; - } - - /** - * Create a call site reference representing a call to this entrypoint - * - * @param programCounter the bytecode index of the synthesize call - * @return the call site reference, or null if failed to find entrypoint - */ - public CallSiteReference makeSite(int programCounter) { - - if (method.getSelector().equals(MethodReference.clinitSelector)) { - assert method.isStatic(); - return CallSiteReference.make(programCounter, method.getReference(), IInvokeInstruction.Dispatch.STATIC); - } else if (method.getSelector().equals(MethodReference.initSelector)) { - assert !method.isStatic(); - return CallSiteReference.make(programCounter, method.getReference(), IInvokeInstruction.Dispatch.SPECIAL); - } else { - if (method.getDeclaringClass().isInterface()) { - return CallSiteReference.make(programCounter, method.getReference(), IInvokeInstruction.Dispatch.INTERFACE); - } else { - if (method.isStatic()) { - return CallSiteReference.make(programCounter, method.getReference(), IInvokeInstruction.Dispatch.STATIC); - } else { - return CallSiteReference.make(programCounter, method.getReference(), IInvokeInstruction.Dispatch.VIRTUAL); - } - } - } - } - - /** - * Add allocation statements to the fake root method for each possible value of parameter i. If necessary, add a phi to combine - * the values. - * - * @return value number holding the parameter to the call; -1 if there was some error - */ - protected int makeArgument(AbstractRootMethod m, int i) { - TypeReference[] p = getParameterTypes(i); - if (p.length == 0) { - return -1; - } else if (p.length == 1) { - if (p[0].isPrimitiveType()) { - return m.addLocal(); - } else { - SSANewInstruction n = m.addAllocation(p[0]); - return (n == null) ? -1 : n.getDef(); - } - } else { - int[] values = new int[p.length]; - int countErrors = 0; - for (int j = 0; j < p.length; j++) { - SSANewInstruction n = m.addAllocation(p[j]); - int value = (n == null) ? -1 : n.getDef(); - if (value == -1) { - countErrors++; - } else { - values[j - countErrors] = value; - } - } - if (countErrors > 0) { - int[] oldValues = values; - values = new int[oldValues.length - countErrors]; - System.arraycopy(oldValues, 0, values, 0, values.length); - } - - TypeAbstraction a; - if (p[0].isPrimitiveType()) { - a = PrimitiveType.getPrimitive(p[0]); - for (i = 1; i < p.length; i++) { - a = a.meet(PrimitiveType.getPrimitive(p[i])); - } - } else { - IClassHierarchy cha = m.getClassHierarchy(); - IClass p0 = cha.lookupClass(p[0]); - a = new ConeType(p0); - for (i = 1; i < p.length; i++) { - IClass pi = cha.lookupClass(p[i]); - a = a.meet(new ConeType(pi)); - } - } - - return m.addPhi(values); - } - } - - @Override - public boolean equals(Object obj) { - // assume these are managed canonically - return this == obj; - } - - /** - * Add a call to this entrypoint from the fake root method - * - * @param m the Fake Root Method - * @return the call instruction added, or null if the operation fails - */ - public SSAAbstractInvokeInstruction addCall(AbstractRootMethod m) { - int paramValues[]; - CallSiteReference site = makeSite(0); - if (site == null) { - return null; - } - paramValues = new int[getNumberOfParameters()]; - for (int j = 0; j < paramValues.length; j++) { - paramValues[j] = makeArgument(m, j); - if (paramValues[j] == -1) { - // there was a problem - return null; - } - } - - return m.addInvocation(paramValues, site); - } - - /** - * @return the method this call invokes - */ - public IMethod getMethod() { - return method; - } - - /** - * @return types to allocate for parameter i; for non-static methods, parameter 0 is "this" - */ - public abstract TypeReference[] getParameterTypes(int i); - - /** - * @return number of parameters to this call, including "this" for non-statics - */ - public abstract int getNumberOfParameters(); - - @Override - public String toString() { - StringBuffer result = new StringBuffer(method.toString()); - result.append("("); - for (int i = 0; i < getNumberOfParameters() - 1; i++) { - result.append(Arrays.toString(getParameterTypes(i))); - result.append(","); - } - if (getNumberOfParameters() > 0) { - result.append(Arrays.toString(getParameterTypes(getNumberOfParameters() - 1))); - } - result.append(")"); - return result.toString(); - } - - @Override - public int hashCode() { - return method.hashCode() * 1009; - } -} +/******************************************************************************* + * 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.ipa.callgraph; + +import java.util.Arrays; + +import com.ibm.wala.analysis.typeInference.ConeType; +import com.ibm.wala.analysis.typeInference.PrimitiveType; +import com.ibm.wala.analysis.typeInference.TypeAbstraction; +import com.ibm.wala.classLoader.CallSiteReference; +import com.ibm.wala.classLoader.IClass; +import com.ibm.wala.classLoader.IMethod; +import com.ibm.wala.ipa.callgraph.impl.AbstractRootMethod; +import com.ibm.wala.ipa.cha.IClassHierarchy; +import com.ibm.wala.shrikeBT.BytecodeConstants; +import com.ibm.wala.shrikeBT.IInvokeInstruction; +import com.ibm.wala.ssa.SSAAbstractInvokeInstruction; +import com.ibm.wala.ssa.SSANewInstruction; +import com.ibm.wala.types.MethodReference; +import com.ibm.wala.types.TypeReference; +import com.ibm.wala.util.debug.Assertions; + +/** + * A representation of an entrypoint in the call graph. + */ +public abstract class Entrypoint implements BytecodeConstants { + + /** + * The method to be called + */ + protected final IMethod method; + + /** + * @param method the method to be called for this entrypoint + */ + protected Entrypoint(IMethod method) { + if (method == null) { + throw new IllegalArgumentException("method is null"); + } + this.method = method; + assert method.getDeclaringClass() != null : "null declaring class"; + } + + protected Entrypoint(MethodReference method, IClassHierarchy cha) { + if (cha == null) { + throw new IllegalArgumentException("cha is null"); + } + IMethod m = cha.resolveMethod(method); + if (m == null) { + Assertions.UNREACHABLE("could not resolve " + method); + } + this.method = m; + } + + /** + * Create a call site reference representing a call to this entrypoint + * + * @param programCounter the bytecode index of the synthesize call + * @return the call site reference, or null if failed to find entrypoint + */ + public CallSiteReference makeSite(int programCounter) { + + if (method.getSelector().equals(MethodReference.clinitSelector)) { + assert method.isStatic(); + return CallSiteReference.make(programCounter, method.getReference(), IInvokeInstruction.Dispatch.STATIC); + } else if (method.getSelector().equals(MethodReference.initSelector)) { + assert !method.isStatic(); + return CallSiteReference.make(programCounter, method.getReference(), IInvokeInstruction.Dispatch.SPECIAL); + } else { + if (method.getDeclaringClass().isInterface()) { + return CallSiteReference.make(programCounter, method.getReference(), IInvokeInstruction.Dispatch.INTERFACE); + } else { + if (method.isStatic()) { + return CallSiteReference.make(programCounter, method.getReference(), IInvokeInstruction.Dispatch.STATIC); + } else { + return CallSiteReference.make(programCounter, method.getReference(), IInvokeInstruction.Dispatch.VIRTUAL); + } + } + } + } + + /** + * Add allocation statements to the fake root method for each possible value of parameter i. If necessary, add a phi to combine + * the values. + * + * @return value number holding the parameter to the call; -1 if there was some error + */ + protected int makeArgument(AbstractRootMethod m, int i) { + TypeReference[] p = getParameterTypes(i); + if (p.length == 0) { + return -1; + } else if (p.length == 1) { + if (p[0].isPrimitiveType()) { + return m.addLocal(); + } else { + SSANewInstruction n = m.addAllocation(p[0]); + return (n == null) ? -1 : n.getDef(); + } + } else { + int[] values = new int[p.length]; + int countErrors = 0; + for (int j = 0; j < p.length; j++) { + SSANewInstruction n = m.addAllocation(p[j]); + int value = (n == null) ? -1 : n.getDef(); + if (value == -1) { + countErrors++; + } else { + values[j - countErrors] = value; + } + } + if (countErrors > 0) { + int[] oldValues = values; + values = new int[oldValues.length - countErrors]; + System.arraycopy(oldValues, 0, values, 0, values.length); + } + + TypeAbstraction a; + if (p[0].isPrimitiveType()) { + a = PrimitiveType.getPrimitive(p[0]); + for (i = 1; i < p.length; i++) { + a = a.meet(PrimitiveType.getPrimitive(p[i])); + } + } else { + IClassHierarchy cha = m.getClassHierarchy(); + IClass p0 = cha.lookupClass(p[0]); + a = new ConeType(p0); + for (i = 1; i < p.length; i++) { + IClass pi = cha.lookupClass(p[i]); + a = a.meet(new ConeType(pi)); + } + } + + return m.addPhi(values); + } + } + + @Override + public boolean equals(Object obj) { + // assume these are managed canonically + return this == obj; + } + + /** + * Add a call to this entrypoint from the fake root method + * + * @param m the Fake Root Method + * @return the call instruction added, or null if the operation fails + */ + public SSAAbstractInvokeInstruction addCall(AbstractRootMethod m) { + int paramValues[]; + CallSiteReference site = makeSite(0); + if (site == null) { + return null; + } + paramValues = new int[getNumberOfParameters()]; + for (int j = 0; j < paramValues.length; j++) { + paramValues[j] = makeArgument(m, j); + if (paramValues[j] == -1) { + // there was a problem + return null; + } + } + + return m.addInvocation(paramValues, site); + } + + /** + * @return the method this call invokes + */ + public IMethod getMethod() { + return method; + } + + /** + * @return types to allocate for parameter i; for non-static methods, parameter 0 is "this" + */ + public abstract TypeReference[] getParameterTypes(int i); + + /** + * @return number of parameters to this call, including "this" for non-statics + */ + public abstract int getNumberOfParameters(); + + @Override + public String toString() { + StringBuffer result = new StringBuffer(method.toString()); + result.append("("); + for (int i = 0; i < getNumberOfParameters() - 1; i++) { + result.append(Arrays.toString(getParameterTypes(i))); + result.append(","); + } + if (getNumberOfParameters() > 0) { + result.append(Arrays.toString(getParameterTypes(getNumberOfParameters() - 1))); + } + result.append(")"); + return result.toString(); + } + + @Override + public int hashCode() { + return method.hashCode() * 1009; + } +} diff --git a/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/MethodTargetSelector.java b/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/MethodTargetSelector.java index e1fe76184..81a2cc037 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/MethodTargetSelector.java +++ b/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/MethodTargetSelector.java @@ -1,42 +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.ipa.callgraph; - -import com.ibm.wala.classLoader.CallSiteReference; -import com.ibm.wala.classLoader.IClass; -import com.ibm.wala.classLoader.IMethod; - -/** - * This interface represents policies for selecting a method to call at a given invocation site. The most obvious such policy would - * be to look at the relevant class hierarchy and lookup the appropriate method based on the type reference and name and descriptor - * at the call site. However, other policies are possible for purposes such as providing an abstraction of unanalyzed libraries or - * specialized J2EE functionality. - * - * Such policies are consulted by the different analysis mechanisms, both the flow-based and non-flow algorithms. The current - * mechanism is that the policy object are registered with the AnalysisOptions object, and all analyses that need to analyze - * invocations ask that object for the method selector to use. - * - * In general, for specialized selectors, it is good practice to build selectors that handle the special case of interest, and - * otherwise delegate to a child selector. When registering with the AnalysisOptions object, make the child selector be whatever the - * options object had before. - */ -public interface MethodTargetSelector { - - /** - * Given a calling node, a call site and (optionally) a dispatch type, return the target method to be called. - * - * @param caller the GCNode in the call graph containing the call - * @param site the call site reference of the call site - * @param receiver the type of the target object or null - * @return the method to be called. - */ - IMethod getCalleeTarget(CGNode caller, CallSiteReference site, IClass receiver); -} +/******************************************************************************* + * 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.ipa.callgraph; + +import com.ibm.wala.classLoader.CallSiteReference; +import com.ibm.wala.classLoader.IClass; +import com.ibm.wala.classLoader.IMethod; + +/** + * This interface represents policies for selecting a method to call at a given invocation site. The most obvious such policy would + * be to look at the relevant class hierarchy and lookup the appropriate method based on the type reference and name and descriptor + * at the call site. However, other policies are possible for purposes such as providing an abstraction of unanalyzed libraries or + * specialized J2EE functionality. + * + * Such policies are consulted by the different analysis mechanisms, both the flow-based and non-flow algorithms. The current + * mechanism is that the policy object are registered with the AnalysisOptions object, and all analyses that need to analyze + * invocations ask that object for the method selector to use. + * + * In general, for specialized selectors, it is good practice to build selectors that handle the special case of interest, and + * otherwise delegate to a child selector. When registering with the AnalysisOptions object, make the child selector be whatever the + * options object had before. + */ +public interface MethodTargetSelector { + + /** + * Given a calling node, a call site and (optionally) a dispatch type, return the target method to be called. + * + * @param caller the GCNode in the call graph containing the call + * @param site the call site reference of the call site + * @param receiver the type of the target object or null + * @return the method to be called. + */ + IMethod getCalleeTarget(CGNode caller, CallSiteReference site, IClass receiver); +} diff --git a/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/ShallowAnalysisScope.java b/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/ShallowAnalysisScope.java index 4f0dd15c0..d9ff82485 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/ShallowAnalysisScope.java +++ b/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/ShallowAnalysisScope.java @@ -1,74 +1,74 @@ -/******************************************************************************* - * Copyright (c) 2007 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.ipa.callgraph; - -import java.io.IOException; -import java.io.Serializable; -import java.util.List; - -import com.ibm.wala.ipa.callgraph.impl.SetOfClasses; -import com.ibm.wala.util.config.AnalysisScopeReader; - -/** - * A serializable version of {@link AnalysisScope}. Note: any information about the array class loader is lost using this - * representation. - */ -public class ShallowAnalysisScope implements Serializable { - - /* Serial version */ - private static final long serialVersionUID = -3256390509887654321L; - - private final SetOfClasses exclusions; - - // example for a line: "Primordial,Java,jarFile,primordial.jar.model" - private final List moduleLinesList; - - // example for a line: "Synthetic, Java, loaderImpl, com.ibm.wala.ipa.summaries.BypassSyntheticClassLoader" - // may be empty - private final List ldrImplLinesList; - - public ShallowAnalysisScope(SetOfClasses exclusions, List moduleLinesList, List ldrImplLinesList) { - if (moduleLinesList == null) { - throw new IllegalArgumentException("null moduleLinesList"); - } - if (ldrImplLinesList == null) { - throw new IllegalArgumentException("null ldrImplLinesList"); - } - this.exclusions = exclusions; - this.moduleLinesList = moduleLinesList; - this.ldrImplLinesList = ldrImplLinesList; - } - - public AnalysisScope toAnalysisScope() throws IOException { - AnalysisScope analysisScope = AnalysisScope.createJavaAnalysisScope(); - analysisScope.setExclusions(exclusions); - - for (String moduleLine : moduleLinesList) { - AnalysisScopeReader.processScopeDefLine(analysisScope, this.getClass().getClassLoader(), moduleLine); - } - - for (String ldrLine : ldrImplLinesList) { - AnalysisScopeReader.processScopeDefLine(analysisScope, this.getClass().getClassLoader(), ldrLine); - } - - return analysisScope; - } - - @Override - public String toString() { - StringBuilder result = new StringBuilder(); - for (String moduleLine : moduleLinesList) { - result.append(moduleLine); - result.append("\n"); - } - return result.toString(); - } -} +/******************************************************************************* + * Copyright (c) 2007 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.ipa.callgraph; + +import java.io.IOException; +import java.io.Serializable; +import java.util.List; + +import com.ibm.wala.ipa.callgraph.impl.SetOfClasses; +import com.ibm.wala.util.config.AnalysisScopeReader; + +/** + * A serializable version of {@link AnalysisScope}. Note: any information about the array class loader is lost using this + * representation. + */ +public class ShallowAnalysisScope implements Serializable { + + /* Serial version */ + private static final long serialVersionUID = -3256390509887654321L; + + private final SetOfClasses exclusions; + + // example for a line: "Primordial,Java,jarFile,primordial.jar.model" + private final List moduleLinesList; + + // example for a line: "Synthetic, Java, loaderImpl, com.ibm.wala.ipa.summaries.BypassSyntheticClassLoader" + // may be empty + private final List ldrImplLinesList; + + public ShallowAnalysisScope(SetOfClasses exclusions, List moduleLinesList, List ldrImplLinesList) { + if (moduleLinesList == null) { + throw new IllegalArgumentException("null moduleLinesList"); + } + if (ldrImplLinesList == null) { + throw new IllegalArgumentException("null ldrImplLinesList"); + } + this.exclusions = exclusions; + this.moduleLinesList = moduleLinesList; + this.ldrImplLinesList = ldrImplLinesList; + } + + public AnalysisScope toAnalysisScope() throws IOException { + AnalysisScope analysisScope = AnalysisScope.createJavaAnalysisScope(); + analysisScope.setExclusions(exclusions); + + for (String moduleLine : moduleLinesList) { + AnalysisScopeReader.processScopeDefLine(analysisScope, this.getClass().getClassLoader(), moduleLine); + } + + for (String ldrLine : ldrImplLinesList) { + AnalysisScopeReader.processScopeDefLine(analysisScope, this.getClass().getClassLoader(), ldrLine); + } + + return analysisScope; + } + + @Override + public String toString() { + StringBuilder result = new StringBuilder(); + for (String moduleLine : moduleLinesList) { + result.append(moduleLine); + result.append("\n"); + } + return result.toString(); + } +} diff --git a/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/impl/AbstractRootMethod.java b/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/impl/AbstractRootMethod.java index 61bee7603..36aaabdcf 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/impl/AbstractRootMethod.java +++ b/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/impl/AbstractRootMethod.java @@ -1,403 +1,403 @@ -/******************************************************************************* - * 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.ipa.callgraph.impl; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Iterator; -import java.util.Map; - -import com.ibm.wala.cfg.InducedCFG; -import com.ibm.wala.classLoader.ArrayClass; -import com.ibm.wala.classLoader.CallSiteReference; -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.AnalysisCache; -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.propagation.rta.RTAContextInterpreter; -import com.ibm.wala.ipa.cha.IClassHierarchy; -import com.ibm.wala.ipa.summaries.SyntheticIR; -import com.ibm.wala.shrikeBT.IInvokeInstruction; -import com.ibm.wala.ssa.ConstantValue; -import com.ibm.wala.ssa.IR; -import com.ibm.wala.ssa.SSAArrayStoreInstruction; -import com.ibm.wala.ssa.SSAInstruction; -import com.ibm.wala.ssa.SSAInstructionFactory; -import com.ibm.wala.ssa.SSAInvokeInstruction; -import com.ibm.wala.ssa.SSANewInstruction; -import com.ibm.wala.ssa.SSAOptions; -import com.ibm.wala.ssa.SSAPhiInstruction; -import com.ibm.wala.ssa.SSAReturnInstruction; -import com.ibm.wala.types.FieldReference; -import com.ibm.wala.types.MethodReference; -import com.ibm.wala.types.TypeReference; -import com.ibm.wala.util.collections.EmptyIterator; -import com.ibm.wala.util.collections.HashMapFactory; -import com.ibm.wala.util.debug.Assertions; -import com.ibm.wala.util.warnings.Warning; -import com.ibm.wala.util.warnings.Warnings; - -/** - * A synthetic method from the {@link FakeRootClass} - */ -public abstract class AbstractRootMethod extends SyntheticMethod { - - final protected ArrayList statements = new ArrayList(); - - private Map constant2ValueNumber = HashMapFactory.make(); - - /** - * The number of the next local value number available for the fake root method. Note that we reserve value number 1 to represent - * the value "any exception caught by the root method" - */ - protected int nextLocal = 2; - - protected final IClassHierarchy cha; - - private final AnalysisOptions options; - - protected final AnalysisCache cache; - - protected final SSAInstructionFactory insts; - - public AbstractRootMethod(MethodReference method, IClass declaringClass, final IClassHierarchy cha, AnalysisOptions options, - AnalysisCache cache) { - super(method, declaringClass, true, false); - this.cha = cha; - this.options = options; - this.cache = cache; - this.insts = declaringClass.getClassLoader().getInstructionFactory(); - if (cache == null) { - throw new IllegalArgumentException("null cache"); - } - // I'd like to enforce that declaringClass is a FakeRootClass ... but CASt would currently break. - // so checking dynamically instead. - if (declaringClass instanceof FakeRootClass) { - ((FakeRootClass) declaringClass).addMethod(this); - } - } - - public AbstractRootMethod(MethodReference method, final IClassHierarchy cha, AnalysisOptions options, AnalysisCache cache) { - this(method, new FakeRootClass(cha), cha, options, cache); - } - - /* - * @see com.ibm.wala.classLoader.IMethod#getStatements(com.ibm.wala.util.warnings.WarningSet) - */ - @Override - public SSAInstruction[] getStatements(SSAOptions options) { - SSAInstruction[] result = new SSAInstruction[statements.size()]; - int i = 0; - for (Iterator it = statements.iterator(); it.hasNext();) { - result[i++] = it.next(); - } - - return result; - } - - @Override - public IR makeIR(Context context, SSAOptions options) { - SSAInstruction instrs[] = getStatements(options); - Map constants = null; - if (!constant2ValueNumber.isEmpty()) { - constants = HashMapFactory.make(constant2ValueNumber.size()); - for (ConstantValue c : constant2ValueNumber.keySet()) { - int vn = constant2ValueNumber.get(c); - constants.put(vn, c); - } - } - InducedCFG cfg = makeControlFlowGraph(instrs); - return new SyntheticIR(this, Everywhere.EVERYWHERE, cfg, instrs, options, constants); - } - - public int addLocal() { - return nextLocal++; - } - - /** - * @return the invoke instructions added by this operation - * @throws IllegalArgumentException if site is null - */ - public SSAInvokeInstruction addInvocation(int[] params, CallSiteReference site) { - if (site == null) { - throw new IllegalArgumentException("site is null"); - } - CallSiteReference newSite = CallSiteReference.make(statements.size(), site.getDeclaredTarget(), site.getInvocationCode()); - SSAInvokeInstruction s = null; - if (newSite.getDeclaredTarget().getReturnType().equals(TypeReference.Void)) { - s = insts.InvokeInstruction(params, nextLocal++, newSite); - } else { - s = insts.InvokeInstruction(nextLocal++, params, nextLocal++, newSite); - } - statements.add(s); - cache.invalidate(this, Everywhere.EVERYWHERE); - return s; - } - - /** - * Add a return statement - */ - public SSAReturnInstruction addReturn(int vn, boolean isPrimitive) { - SSAReturnInstruction s = insts.ReturnInstruction(vn, isPrimitive); - statements.add(s); - cache.invalidate(this, Everywhere.EVERYWHERE); - return s; - } - - /** - * Add a New statement of the given type - * - * Side effect: adds call to default constructor of given type if one exists. - * - * @return instruction added, or null - * @throws IllegalArgumentException if T is null - */ - public SSANewInstruction addAllocation(TypeReference T) { - return addAllocation(T, true); - } - - /** - * Add a New statement of the given array type and length - */ - public SSANewInstruction add1DArrayAllocation(TypeReference T, int length) { - int instance = nextLocal++; - NewSiteReference ref = NewSiteReference.make(statements.size(), T); - assert T.isArrayType(); - assert ((ArrayClass)cha.lookupClass(T)).getDimensionality() == 1; - int[] sizes = new int[1]; - Arrays.fill(sizes, getValueNumberForIntConstant(length)); - SSANewInstruction result = insts.NewInstruction(instance, ref, sizes); - statements.add(result); - cache.invalidate(this, Everywhere.EVERYWHERE); - return result; - } - - /** - * Add a New statement of the given type - */ - public SSANewInstruction addAllocationWithoutCtor(TypeReference T) { - return addAllocation(T, false); - } - - /** - * Add a New statement of the given type - * - * @return instruction added, or null - * @throws IllegalArgumentException if T is null - */ - private SSANewInstruction addAllocation(TypeReference T, boolean invokeCtor) { - if (T == null) { - throw new IllegalArgumentException("T is null"); - } - int instance = nextLocal++; - SSANewInstruction result = null; - - if (T.isReferenceType()) { - NewSiteReference ref = NewSiteReference.make(statements.size(), T); - if (T.isArrayType()) { - int[] sizes = new int[((ArrayClass)cha.lookupClass(T)).getDimensionality()]; - Arrays.fill(sizes, getValueNumberForIntConstant(1)); - result = insts.NewInstruction(instance, ref, sizes); - } else { - result = insts.NewInstruction(instance, ref); - } - statements.add(result); - - IClass klass = cha.lookupClass(T); - if (klass == null) { - Warnings.add(AllocationFailure.create(T)); - return null; - } - - if (klass.isArrayClass()) { - int arrayRef = result.getDef(); - TypeReference e = klass.getReference().getArrayElementType(); - while (e != null && !e.isPrimitiveType()) { - // allocate an instance for the array contents - NewSiteReference n = NewSiteReference.make(statements.size(), e); - int alloc = nextLocal++; - SSANewInstruction ni = null; - if (e.isArrayType()) { - int[] sizes = new int[((ArrayClass)cha.lookupClass(T)).getDimensionality()]; - Arrays.fill(sizes, getValueNumberForIntConstant(1)); - ni = insts.NewInstruction(alloc, n, sizes); - } else { - ni = insts.NewInstruction(alloc, n); - } - statements.add(ni); - - // emit an astore - SSAArrayStoreInstruction store = insts.ArrayStoreInstruction(arrayRef, getValueNumberForIntConstant(0), alloc, e); - statements.add(store); - - e = e.isArrayType() ? e.getArrayElementType() : null; - arrayRef = alloc; - } - } - if (invokeCtor) { - IMethod ctor = cha.resolveMethod(klass, MethodReference.initSelector); - if (ctor != null) { - addInvocation(new int[] { instance }, CallSiteReference.make(statements.size(), ctor.getReference(), - IInvokeInstruction.Dispatch.SPECIAL)); - } - } - } - cache.invalidate(this, Everywhere.EVERYWHERE); - return result; - } - - protected int getValueNumberForIntConstant(int c) { - ConstantValue v = new ConstantValue(c); - Integer result = constant2ValueNumber.get(v); - if (result == null) { - result = nextLocal++; - constant2ValueNumber.put(v, result); - } - return result; - } - - protected int getValueNumberForByteConstant(byte c) { - // treat it like an int constant for now. - ConstantValue v = new ConstantValue(c); - Integer result = constant2ValueNumber.get(v); - if (result == null) { - result = nextLocal++; - constant2ValueNumber.put(v, result); - } - return result; - } - - protected int getValueNumberForCharConstant(char c) { - // treat it like an int constant for now. - ConstantValue v = new ConstantValue(c); - Integer result = constant2ValueNumber.get(v); - if (result == null) { - result = nextLocal++; - constant2ValueNumber.put(v, result); - } - return result; - } - - /** - * A warning for when we fail to allocate a type in the fake root method - */ - private static class AllocationFailure extends Warning { - - final TypeReference t; - - AllocationFailure(TypeReference t) { - super(Warning.SEVERE); - this.t = t; - } - - @Override - public String getMsg() { - return getClass().toString() + " : " + t; - } - - public static AllocationFailure create(TypeReference t) { - return new AllocationFailure(t); - } - } - - public int addPhi(int[] values) { - int result = nextLocal++; - SSAPhiInstruction phi = insts.PhiInstruction(result, values); - statements.add(phi); - return result; - } - - public int addGetInstance(FieldReference ref, int object) { - int result = nextLocal++; - statements.add(insts.GetInstruction(result, object, ref)); - return result; - } - - public int addGetStatic(FieldReference ref) { - int result = nextLocal++; - statements.add(insts.GetInstruction(result, ref)); - return result; - } - - public int addCheckcast(TypeReference[] types, int rv, boolean isPEI) { - int lv = nextLocal++; - - statements.add(insts.CheckCastInstruction(lv, rv, types, isPEI)); - return lv; - } - - public RTAContextInterpreter getInterpreter() { - return new RTAContextInterpreter() { - - public Iterator iterateNewSites(CGNode node) { - ArrayList result = new ArrayList(); - SSAInstruction[] statements = getStatements(options.getSSAOptions()); - for (int i = 0; i < statements.length; i++) { - if (statements[i] instanceof SSANewInstruction) { - SSANewInstruction s = (SSANewInstruction) statements[i]; - result.add(s.getNewSite()); - } - } - return result.iterator(); - } - - public Iterator getInvokeStatements() { - ArrayList result = new ArrayList(); - SSAInstruction[] statements = getStatements(options.getSSAOptions()); - for (int i = 0; i < statements.length; i++) { - if (statements[i] instanceof SSAInvokeInstruction) { - result.add(statements[i]); - } - } - return result.iterator(); - } - - public Iterator iterateCallSites(CGNode node) { - final Iterator I = getInvokeStatements(); - return new Iterator() { - public boolean hasNext() { - return I.hasNext(); - } - - public CallSiteReference next() { - SSAInvokeInstruction s = (SSAInvokeInstruction) I.next(); - return s.getCallSite(); - } - - public void remove() { - Assertions.UNREACHABLE(); - } - }; - } - - public boolean understands(CGNode node) { - return node.getMethod().getDeclaringClass().getReference().equals(FakeRootClass.FAKE_ROOT_CLASS); - } - - public boolean recordFactoryType(CGNode node, IClass klass) { - // not a factory type - return false; - } - - public Iterator iterateFieldsRead(CGNode node) { - return EmptyIterator.instance(); - } - - public Iterator iterateFieldsWritten(CGNode node) { - return EmptyIterator.instance(); - } - }; - } -} +/******************************************************************************* + * 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.ipa.callgraph.impl; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Iterator; +import java.util.Map; + +import com.ibm.wala.cfg.InducedCFG; +import com.ibm.wala.classLoader.ArrayClass; +import com.ibm.wala.classLoader.CallSiteReference; +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.AnalysisCache; +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.propagation.rta.RTAContextInterpreter; +import com.ibm.wala.ipa.cha.IClassHierarchy; +import com.ibm.wala.ipa.summaries.SyntheticIR; +import com.ibm.wala.shrikeBT.IInvokeInstruction; +import com.ibm.wala.ssa.ConstantValue; +import com.ibm.wala.ssa.IR; +import com.ibm.wala.ssa.SSAArrayStoreInstruction; +import com.ibm.wala.ssa.SSAInstruction; +import com.ibm.wala.ssa.SSAInstructionFactory; +import com.ibm.wala.ssa.SSAInvokeInstruction; +import com.ibm.wala.ssa.SSANewInstruction; +import com.ibm.wala.ssa.SSAOptions; +import com.ibm.wala.ssa.SSAPhiInstruction; +import com.ibm.wala.ssa.SSAReturnInstruction; +import com.ibm.wala.types.FieldReference; +import com.ibm.wala.types.MethodReference; +import com.ibm.wala.types.TypeReference; +import com.ibm.wala.util.collections.EmptyIterator; +import com.ibm.wala.util.collections.HashMapFactory; +import com.ibm.wala.util.debug.Assertions; +import com.ibm.wala.util.warnings.Warning; +import com.ibm.wala.util.warnings.Warnings; + +/** + * A synthetic method from the {@link FakeRootClass} + */ +public abstract class AbstractRootMethod extends SyntheticMethod { + + final protected ArrayList statements = new ArrayList(); + + private Map constant2ValueNumber = HashMapFactory.make(); + + /** + * The number of the next local value number available for the fake root method. Note that we reserve value number 1 to represent + * the value "any exception caught by the root method" + */ + protected int nextLocal = 2; + + protected final IClassHierarchy cha; + + private final AnalysisOptions options; + + protected final AnalysisCache cache; + + protected final SSAInstructionFactory insts; + + public AbstractRootMethod(MethodReference method, IClass declaringClass, final IClassHierarchy cha, AnalysisOptions options, + AnalysisCache cache) { + super(method, declaringClass, true, false); + this.cha = cha; + this.options = options; + this.cache = cache; + this.insts = declaringClass.getClassLoader().getInstructionFactory(); + if (cache == null) { + throw new IllegalArgumentException("null cache"); + } + // I'd like to enforce that declaringClass is a FakeRootClass ... but CASt would currently break. + // so checking dynamically instead. + if (declaringClass instanceof FakeRootClass) { + ((FakeRootClass) declaringClass).addMethod(this); + } + } + + public AbstractRootMethod(MethodReference method, final IClassHierarchy cha, AnalysisOptions options, AnalysisCache cache) { + this(method, new FakeRootClass(cha), cha, options, cache); + } + + /* + * @see com.ibm.wala.classLoader.IMethod#getStatements(com.ibm.wala.util.warnings.WarningSet) + */ + @Override + public SSAInstruction[] getStatements(SSAOptions options) { + SSAInstruction[] result = new SSAInstruction[statements.size()]; + int i = 0; + for (Iterator it = statements.iterator(); it.hasNext();) { + result[i++] = it.next(); + } + + return result; + } + + @Override + public IR makeIR(Context context, SSAOptions options) { + SSAInstruction instrs[] = getStatements(options); + Map constants = null; + if (!constant2ValueNumber.isEmpty()) { + constants = HashMapFactory.make(constant2ValueNumber.size()); + for (ConstantValue c : constant2ValueNumber.keySet()) { + int vn = constant2ValueNumber.get(c); + constants.put(vn, c); + } + } + InducedCFG cfg = makeControlFlowGraph(instrs); + return new SyntheticIR(this, Everywhere.EVERYWHERE, cfg, instrs, options, constants); + } + + public int addLocal() { + return nextLocal++; + } + + /** + * @return the invoke instructions added by this operation + * @throws IllegalArgumentException if site is null + */ + public SSAInvokeInstruction addInvocation(int[] params, CallSiteReference site) { + if (site == null) { + throw new IllegalArgumentException("site is null"); + } + CallSiteReference newSite = CallSiteReference.make(statements.size(), site.getDeclaredTarget(), site.getInvocationCode()); + SSAInvokeInstruction s = null; + if (newSite.getDeclaredTarget().getReturnType().equals(TypeReference.Void)) { + s = insts.InvokeInstruction(params, nextLocal++, newSite); + } else { + s = insts.InvokeInstruction(nextLocal++, params, nextLocal++, newSite); + } + statements.add(s); + cache.invalidate(this, Everywhere.EVERYWHERE); + return s; + } + + /** + * Add a return statement + */ + public SSAReturnInstruction addReturn(int vn, boolean isPrimitive) { + SSAReturnInstruction s = insts.ReturnInstruction(vn, isPrimitive); + statements.add(s); + cache.invalidate(this, Everywhere.EVERYWHERE); + return s; + } + + /** + * Add a New statement of the given type + * + * Side effect: adds call to default constructor of given type if one exists. + * + * @return instruction added, or null + * @throws IllegalArgumentException if T is null + */ + public SSANewInstruction addAllocation(TypeReference T) { + return addAllocation(T, true); + } + + /** + * Add a New statement of the given array type and length + */ + public SSANewInstruction add1DArrayAllocation(TypeReference T, int length) { + int instance = nextLocal++; + NewSiteReference ref = NewSiteReference.make(statements.size(), T); + assert T.isArrayType(); + assert ((ArrayClass)cha.lookupClass(T)).getDimensionality() == 1; + int[] sizes = new int[1]; + Arrays.fill(sizes, getValueNumberForIntConstant(length)); + SSANewInstruction result = insts.NewInstruction(instance, ref, sizes); + statements.add(result); + cache.invalidate(this, Everywhere.EVERYWHERE); + return result; + } + + /** + * Add a New statement of the given type + */ + public SSANewInstruction addAllocationWithoutCtor(TypeReference T) { + return addAllocation(T, false); + } + + /** + * Add a New statement of the given type + * + * @return instruction added, or null + * @throws IllegalArgumentException if T is null + */ + private SSANewInstruction addAllocation(TypeReference T, boolean invokeCtor) { + if (T == null) { + throw new IllegalArgumentException("T is null"); + } + int instance = nextLocal++; + SSANewInstruction result = null; + + if (T.isReferenceType()) { + NewSiteReference ref = NewSiteReference.make(statements.size(), T); + if (T.isArrayType()) { + int[] sizes = new int[((ArrayClass)cha.lookupClass(T)).getDimensionality()]; + Arrays.fill(sizes, getValueNumberForIntConstant(1)); + result = insts.NewInstruction(instance, ref, sizes); + } else { + result = insts.NewInstruction(instance, ref); + } + statements.add(result); + + IClass klass = cha.lookupClass(T); + if (klass == null) { + Warnings.add(AllocationFailure.create(T)); + return null; + } + + if (klass.isArrayClass()) { + int arrayRef = result.getDef(); + TypeReference e = klass.getReference().getArrayElementType(); + while (e != null && !e.isPrimitiveType()) { + // allocate an instance for the array contents + NewSiteReference n = NewSiteReference.make(statements.size(), e); + int alloc = nextLocal++; + SSANewInstruction ni = null; + if (e.isArrayType()) { + int[] sizes = new int[((ArrayClass)cha.lookupClass(T)).getDimensionality()]; + Arrays.fill(sizes, getValueNumberForIntConstant(1)); + ni = insts.NewInstruction(alloc, n, sizes); + } else { + ni = insts.NewInstruction(alloc, n); + } + statements.add(ni); + + // emit an astore + SSAArrayStoreInstruction store = insts.ArrayStoreInstruction(arrayRef, getValueNumberForIntConstant(0), alloc, e); + statements.add(store); + + e = e.isArrayType() ? e.getArrayElementType() : null; + arrayRef = alloc; + } + } + if (invokeCtor) { + IMethod ctor = cha.resolveMethod(klass, MethodReference.initSelector); + if (ctor != null) { + addInvocation(new int[] { instance }, CallSiteReference.make(statements.size(), ctor.getReference(), + IInvokeInstruction.Dispatch.SPECIAL)); + } + } + } + cache.invalidate(this, Everywhere.EVERYWHERE); + return result; + } + + protected int getValueNumberForIntConstant(int c) { + ConstantValue v = new ConstantValue(c); + Integer result = constant2ValueNumber.get(v); + if (result == null) { + result = nextLocal++; + constant2ValueNumber.put(v, result); + } + return result; + } + + protected int getValueNumberForByteConstant(byte c) { + // treat it like an int constant for now. + ConstantValue v = new ConstantValue(c); + Integer result = constant2ValueNumber.get(v); + if (result == null) { + result = nextLocal++; + constant2ValueNumber.put(v, result); + } + return result; + } + + protected int getValueNumberForCharConstant(char c) { + // treat it like an int constant for now. + ConstantValue v = new ConstantValue(c); + Integer result = constant2ValueNumber.get(v); + if (result == null) { + result = nextLocal++; + constant2ValueNumber.put(v, result); + } + return result; + } + + /** + * A warning for when we fail to allocate a type in the fake root method + */ + private static class AllocationFailure extends Warning { + + final TypeReference t; + + AllocationFailure(TypeReference t) { + super(Warning.SEVERE); + this.t = t; + } + + @Override + public String getMsg() { + return getClass().toString() + " : " + t; + } + + public static AllocationFailure create(TypeReference t) { + return new AllocationFailure(t); + } + } + + public int addPhi(int[] values) { + int result = nextLocal++; + SSAPhiInstruction phi = insts.PhiInstruction(result, values); + statements.add(phi); + return result; + } + + public int addGetInstance(FieldReference ref, int object) { + int result = nextLocal++; + statements.add(insts.GetInstruction(result, object, ref)); + return result; + } + + public int addGetStatic(FieldReference ref) { + int result = nextLocal++; + statements.add(insts.GetInstruction(result, ref)); + return result; + } + + public int addCheckcast(TypeReference[] types, int rv, boolean isPEI) { + int lv = nextLocal++; + + statements.add(insts.CheckCastInstruction(lv, rv, types, isPEI)); + return lv; + } + + public RTAContextInterpreter getInterpreter() { + return new RTAContextInterpreter() { + + public Iterator iterateNewSites(CGNode node) { + ArrayList result = new ArrayList(); + SSAInstruction[] statements = getStatements(options.getSSAOptions()); + for (int i = 0; i < statements.length; i++) { + if (statements[i] instanceof SSANewInstruction) { + SSANewInstruction s = (SSANewInstruction) statements[i]; + result.add(s.getNewSite()); + } + } + return result.iterator(); + } + + public Iterator getInvokeStatements() { + ArrayList result = new ArrayList(); + SSAInstruction[] statements = getStatements(options.getSSAOptions()); + for (int i = 0; i < statements.length; i++) { + if (statements[i] instanceof SSAInvokeInstruction) { + result.add(statements[i]); + } + } + return result.iterator(); + } + + public Iterator iterateCallSites(CGNode node) { + final Iterator I = getInvokeStatements(); + return new Iterator() { + public boolean hasNext() { + return I.hasNext(); + } + + public CallSiteReference next() { + SSAInvokeInstruction s = (SSAInvokeInstruction) I.next(); + return s.getCallSite(); + } + + public void remove() { + Assertions.UNREACHABLE(); + } + }; + } + + public boolean understands(CGNode node) { + return node.getMethod().getDeclaringClass().getReference().equals(FakeRootClass.FAKE_ROOT_CLASS); + } + + public boolean recordFactoryType(CGNode node, IClass klass) { + // not a factory type + return false; + } + + public Iterator iterateFieldsRead(CGNode node) { + return EmptyIterator.instance(); + } + + public Iterator iterateFieldsWritten(CGNode node) { + return EmptyIterator.instance(); + } + }; + } +} diff --git a/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/impl/AllApplicationEntrypoints.java b/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/impl/AllApplicationEntrypoints.java index 8d4d9561d..13277157e 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/impl/AllApplicationEntrypoints.java +++ b/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/impl/AllApplicationEntrypoints.java @@ -1,63 +1,63 @@ -/******************************************************************************* - * 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.ipa.callgraph.impl; - -import java.util.HashSet; -import java.util.Iterator; - -import com.ibm.wala.classLoader.IClass; -import com.ibm.wala.classLoader.IMethod; -import com.ibm.wala.ipa.callgraph.AnalysisScope; -import com.ibm.wala.ipa.callgraph.Entrypoint; -import com.ibm.wala.ipa.cha.IClassHierarchy; - -/** - * Includes all application methods in an analysis scope as entrypoints. - */ -public class AllApplicationEntrypoints extends HashSet { - - private final static boolean DEBUG = false; - - /** - * @param scope governing analyais scope - * @param cha governing class hierarchy - * @throws IllegalArgumentException if cha is null - */ - public AllApplicationEntrypoints(AnalysisScope scope, final IClassHierarchy cha) { - - if (cha == null) { - throw new IllegalArgumentException("cha is null"); - } - for (IClass klass : cha) { - if (!klass.isInterface()) { - if (isApplicationClass(scope, klass)) { - for (Iterator methodIt = klass.getDeclaredMethods().iterator(); methodIt.hasNext();) { - IMethod method = (IMethod) methodIt.next(); - if (!method.isAbstract()) { - add(new ArgumentTypeEntrypoint(method, cha)); - } - } - } - } - } - if (DEBUG) { - System.err.println((getClass() + "Number of EntryPoints:" + size())); - } - - } - - /** - * @return true iff klass is loaded by the application loader. - */ - private boolean isApplicationClass(AnalysisScope scope, IClass klass) { - return scope.getApplicationLoader().equals(klass.getClassLoader().getReference()); - } +/******************************************************************************* + * 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.ipa.callgraph.impl; + +import java.util.HashSet; +import java.util.Iterator; + +import com.ibm.wala.classLoader.IClass; +import com.ibm.wala.classLoader.IMethod; +import com.ibm.wala.ipa.callgraph.AnalysisScope; +import com.ibm.wala.ipa.callgraph.Entrypoint; +import com.ibm.wala.ipa.cha.IClassHierarchy; + +/** + * Includes all application methods in an analysis scope as entrypoints. + */ +public class AllApplicationEntrypoints extends HashSet { + + private final static boolean DEBUG = false; + + /** + * @param scope governing analyais scope + * @param cha governing class hierarchy + * @throws IllegalArgumentException if cha is null + */ + public AllApplicationEntrypoints(AnalysisScope scope, final IClassHierarchy cha) { + + if (cha == null) { + throw new IllegalArgumentException("cha is null"); + } + for (IClass klass : cha) { + if (!klass.isInterface()) { + if (isApplicationClass(scope, klass)) { + for (Iterator methodIt = klass.getDeclaredMethods().iterator(); methodIt.hasNext();) { + IMethod method = (IMethod) methodIt.next(); + if (!method.isAbstract()) { + add(new ArgumentTypeEntrypoint(method, cha)); + } + } + } + } + } + if (DEBUG) { + System.err.println((getClass() + "Number of EntryPoints:" + size())); + } + + } + + /** + * @return true iff klass is loaded by the application loader. + */ + private boolean isApplicationClass(AnalysisScope scope, IClass klass) { + return scope.getApplicationLoader().equals(klass.getClassLoader().getReference()); + } } \ No newline at end of file diff --git a/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/impl/ArgumentTypeEntrypoint.java b/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/impl/ArgumentTypeEntrypoint.java index 6d0ff8c16..8d513d863 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/impl/ArgumentTypeEntrypoint.java +++ b/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/impl/ArgumentTypeEntrypoint.java @@ -1,113 +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.ipa.callgraph.impl; - -import java.util.Collection; -import java.util.Iterator; -import java.util.Set; - -import com.ibm.wala.classLoader.ArrayClass; -import com.ibm.wala.classLoader.IClass; -import com.ibm.wala.classLoader.IMethod; -import com.ibm.wala.ipa.callgraph.Entrypoint; -import com.ibm.wala.ipa.cha.IClassHierarchy; -import com.ibm.wala.types.TypeReference; - -/** - * An entrypoint which chooses some valid (non-interface) concrete type for each argument, if one is available. - */ -public class ArgumentTypeEntrypoint extends Entrypoint { - - final private TypeReference[][] paramTypes; - - private final IClassHierarchy cha; - - /** - * @throws IllegalArgumentException if method == null - */ - protected TypeReference[][] makeParameterTypes(IMethod method) throws IllegalArgumentException { - if (method == null) { - throw new IllegalArgumentException("method == null"); - } - TypeReference[][] result = new TypeReference[method.getNumberOfParameters()][]; - for (int i = 0; i < result.length; i++) { - TypeReference t = method.getParameterType(i); - if (!t.isPrimitiveType()) { - IClass klass = cha.lookupClass(t); - if (klass == null) { - t = null; - } else if (!klass.isInterface() && klass.isAbstract()) { - // yes, I've seen classes that are marked as "abstract interface" :) - t = chooseAConcreteSubClass(klass); - } else if (klass.isInterface()) { - t = chooseAnImplementor(klass); - } else if (klass.isArrayClass()) { - ArrayClass arrayKlass = (ArrayClass) klass; - IClass innermost = arrayKlass.getInnermostElementClass(); - if (innermost != null && innermost.isInterface()) { - TypeReference impl = chooseAnImplementor(innermost); - if (impl == null) { - t = null; - } else { - t = TypeReference.findOrCreateArrayOf(impl); - for (int dim = 1; dim < arrayKlass.getDimensionality(); dim++) { - t = TypeReference.findOrCreateArrayOf(t); - } - } - } - } - } - - result[i] = (t == null) ? new TypeReference[0] : new TypeReference[] { t }; - } - return result; - } - - private TypeReference chooseAnImplementor(IClass iface) { - Set implementors = cha.getImplementors(iface.getReference()); - if (!implementors.isEmpty()) { - return ((IClass) implementors.iterator().next()).getReference(); - } else { - return null; - } - } - - private TypeReference chooseAConcreteSubClass(IClass klass) { - Collection subclasses = cha.computeSubClasses(klass.getReference()); - for (Iterator it = subclasses.iterator(); it.hasNext();) { - IClass c = (IClass) it.next(); - if (!c.isAbstract()) { - return c.getReference(); - } - } - return null; - } - - public ArgumentTypeEntrypoint(IMethod method, IClassHierarchy cha) { - super(method); - this.cha = cha; - paramTypes = makeParameterTypes(method); - } - - @Override - public TypeReference[] getParameterTypes(int i) { - return paramTypes[i]; - } - - /* - * @see com.ibm.wala.ipa.callgraph.Entrypoint#getNumberOfParameters() - */ - @Override - public int getNumberOfParameters() { - return paramTypes.length; - } - +/******************************************************************************* + * 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.ipa.callgraph.impl; + +import java.util.Collection; +import java.util.Iterator; +import java.util.Set; + +import com.ibm.wala.classLoader.ArrayClass; +import com.ibm.wala.classLoader.IClass; +import com.ibm.wala.classLoader.IMethod; +import com.ibm.wala.ipa.callgraph.Entrypoint; +import com.ibm.wala.ipa.cha.IClassHierarchy; +import com.ibm.wala.types.TypeReference; + +/** + * An entrypoint which chooses some valid (non-interface) concrete type for each argument, if one is available. + */ +public class ArgumentTypeEntrypoint extends Entrypoint { + + final private TypeReference[][] paramTypes; + + private final IClassHierarchy cha; + + /** + * @throws IllegalArgumentException if method == null + */ + protected TypeReference[][] makeParameterTypes(IMethod method) throws IllegalArgumentException { + if (method == null) { + throw new IllegalArgumentException("method == null"); + } + TypeReference[][] result = new TypeReference[method.getNumberOfParameters()][]; + for (int i = 0; i < result.length; i++) { + TypeReference t = method.getParameterType(i); + if (!t.isPrimitiveType()) { + IClass klass = cha.lookupClass(t); + if (klass == null) { + t = null; + } else if (!klass.isInterface() && klass.isAbstract()) { + // yes, I've seen classes that are marked as "abstract interface" :) + t = chooseAConcreteSubClass(klass); + } else if (klass.isInterface()) { + t = chooseAnImplementor(klass); + } else if (klass.isArrayClass()) { + ArrayClass arrayKlass = (ArrayClass) klass; + IClass innermost = arrayKlass.getInnermostElementClass(); + if (innermost != null && innermost.isInterface()) { + TypeReference impl = chooseAnImplementor(innermost); + if (impl == null) { + t = null; + } else { + t = TypeReference.findOrCreateArrayOf(impl); + for (int dim = 1; dim < arrayKlass.getDimensionality(); dim++) { + t = TypeReference.findOrCreateArrayOf(t); + } + } + } + } + } + + result[i] = (t == null) ? new TypeReference[0] : new TypeReference[] { t }; + } + return result; + } + + private TypeReference chooseAnImplementor(IClass iface) { + Set implementors = cha.getImplementors(iface.getReference()); + if (!implementors.isEmpty()) { + return ((IClass) implementors.iterator().next()).getReference(); + } else { + return null; + } + } + + private TypeReference chooseAConcreteSubClass(IClass klass) { + Collection subclasses = cha.computeSubClasses(klass.getReference()); + for (Iterator it = subclasses.iterator(); it.hasNext();) { + IClass c = (IClass) it.next(); + if (!c.isAbstract()) { + return c.getReference(); + } + } + return null; + } + + public ArgumentTypeEntrypoint(IMethod method, IClassHierarchy cha) { + super(method); + this.cha = cha; + paramTypes = makeParameterTypes(method); + } + + @Override + public TypeReference[] getParameterTypes(int i) { + return paramTypes[i]; + } + + /* + * @see com.ibm.wala.ipa.callgraph.Entrypoint#getNumberOfParameters() + */ + @Override + public int getNumberOfParameters() { + return paramTypes.length; + } + } \ No newline at end of file diff --git a/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/impl/BasicCallGraph.java b/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/impl/BasicCallGraph.java index 634b8d4a1..f2c1f6ad9 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/impl/BasicCallGraph.java +++ b/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/impl/BasicCallGraph.java @@ -1,388 +1,388 @@ -/******************************************************************************* - * 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.ipa.callgraph.impl; - -import java.util.Collection; -import java.util.Collections; -import java.util.Iterator; -import java.util.Map; -import java.util.Set; - -import com.ibm.wala.analysis.reflection.JavaTypeContext; -import com.ibm.wala.classLoader.CallSiteReference; -import com.ibm.wala.classLoader.IMethod; -import com.ibm.wala.ipa.callgraph.CGNode; -import com.ibm.wala.ipa.callgraph.CallGraph; -import com.ibm.wala.ipa.callgraph.Context; -import com.ibm.wala.ipa.callgraph.propagation.ReceiverInstanceContext; -import com.ibm.wala.ipa.callgraph.propagation.SSAContextInterpreter; -import com.ibm.wala.ipa.cha.IClassHierarchy; -import com.ibm.wala.shrikeBT.IInvokeInstruction; -import com.ibm.wala.types.MethodReference; -import com.ibm.wala.util.CancelException; -import com.ibm.wala.util.collections.HashMapFactory; -import com.ibm.wala.util.collections.HashSetFactory; -import com.ibm.wala.util.collections.NonNullSingletonIterator; -import com.ibm.wala.util.debug.Assertions; -import com.ibm.wala.util.debug.UnimplementedError; -import com.ibm.wala.util.graph.AbstractNumberedGraph; -import com.ibm.wala.util.graph.NumberedNodeManager; -import com.ibm.wala.util.graph.impl.DelegatingNumberedNodeManager; -import com.ibm.wala.util.graph.impl.NodeWithNumber; -import com.ibm.wala.util.graph.traverse.DFS; - -/** - * Basic data structure support for a call graph. - */ -public abstract class BasicCallGraph extends AbstractNumberedGraph implements CallGraph { - - private static final boolean DEBUG = false; - - private final DelegatingNumberedNodeManager nodeManager = new DelegatingNumberedNodeManager(); - - /** - * A fake root node for the graph - */ - private CGNode fakeRoot; - - /** - * A node which handles all calls to class initializers - */ - private CGNode fakeWorldClinit; - - /** - * An object that handles context interpreter functions - */ - private SSAContextInterpreter interpreter; - - /** - * Set of nodes that are entrypoints for this analysis - */ - private final Set entrypointNodes = HashSetFactory.make(); - - /** - * A mapping from Key to NodeImpls in the graph. Note that each node is created on demand. This Map does not include the root - * node. - */ - final private Map nodes = HashMapFactory.make(); - - /** - * A mapping from MethodReference to Set of nodes that represent this methodReference. - * - * TODO: rhs of mapping doesn't have to be a set if it's a singleton; could be a node instead. - * - * TODO: this is a bit redundant with the nodes Map. Restructure these data structures for space efficiency. - */ - final private Map> mr2Nodes = HashMapFactory.make(); - - public BasicCallGraph() { - super(); - } - - @SuppressWarnings("deprecation") - public void init() throws CancelException { - fakeRoot = makeFakeRootNode(); - Key k = new Key(fakeRoot.getMethod(), fakeRoot.getContext()); - registerNode(k, fakeRoot); - fakeWorldClinit = makeFakeWorldClinitNode(); - if (fakeWorldClinit != null) { - k = new Key(fakeWorldClinit.getMethod(), fakeWorldClinit.getContext()); - registerNode(k, fakeWorldClinit); - - // add a call from fakeRoot to fakeWorldClinit - CallSiteReference site = CallSiteReference.make(1, fakeWorldClinit.getMethod().getReference(), - IInvokeInstruction.Dispatch.STATIC); - // note that the result of addInvocation is a different site, with a different program counter! - site = ((AbstractRootMethod) fakeRoot.getMethod()).addInvocation(null, site).getCallSite(); - fakeRoot.addTarget(site, fakeWorldClinit); - } - } - - protected abstract CGNode makeFakeRootNode() throws CancelException; - - protected abstract CGNode makeFakeWorldClinitNode() throws CancelException; - - /** - * Use with extreme care. - * - * @throws CancelException TODO - */ - public abstract CGNode findOrCreateNode(IMethod method, Context C) throws CancelException; - - protected void registerNode(Key K, CGNode N) { - nodes.put(K, N); - addNode(N); - Set s = findOrCreateMr2Nodes(K.m); - s.add(N); - if (DEBUG) { - System.err.println(("registered Node: " + N + " for key " + K)); - System.err.println(("now size = " + getNumberOfNodes())); - } - } - - private Set findOrCreateMr2Nodes(IMethod method) { - Set result = mr2Nodes.get(method.getReference()); - if (result == null) { - result = HashSetFactory.make(3); - mr2Nodes.put(method.getReference(), result); - } - return result; - } - - protected NodeImpl getNode(Key K) { - return (NodeImpl) nodes.get(K); - } - - public CGNode getFakeRootNode() { - return fakeRoot; - } - - public CGNode getFakeWorldClinitNode() { - return fakeWorldClinit; - } - - /** - * record that a node is an entrypoint - */ - public void registerEntrypoint(CGNode node) { - entrypointNodes.add(node); - } - - /** - * Note: not all successors of the root node are entrypoints - */ - public Collection getEntrypointNodes() { - return entrypointNodes; - } - - /** - * A class that represents the a normal node in a call graph. - */ - public abstract class NodeImpl extends NodeWithNumber implements CGNode { - - /** - * The method this node represents. - */ - protected final IMethod method; - - /** - * The context this node represents. - */ - private final Context context; - - protected NodeImpl(IMethod method, Context C) { - this.method = method; - this.context = C; - if (method != null && !method.isSynthetic() && method.isAbstract()) { - assert !method.isAbstract() : "Abstract method " + method; - } - assert C != null; - } - - public IMethod getMethod() { - return method; - } - - /** - * @see java.lang.Object#equals(Object) - */ - @Override - public abstract boolean equals(Object obj); - - /** - * @see java.lang.Object#hashCode() - */ - @Override - public abstract int hashCode(); - - /** - * @see java.lang.Object#toString() - */ - @Override - public String toString() { - return "Node: " + method.toString() + " Context: " + context.toString(); - } - - public Context getContext() { - return context; - } - - public abstract boolean addTarget(CallSiteReference reference, CGNode target); - - public IClassHierarchy getClassHierarchy() { - return method.getClassHierarchy(); - } - } - - @Override - public String toString() { - StringBuffer result = new StringBuffer(""); - for (Iterator i = DFS.iterateDiscoverTime(this, new NonNullSingletonIterator(getFakeRootNode())); i.hasNext();) { - CGNode n = (CGNode) i.next(); - result.append(n + "\n"); - if (n.getMethod() != null) { - for (Iterator sites = n.iterateCallSites(); sites.hasNext();) { - CallSiteReference site = (CallSiteReference) sites.next(); - Iterator targets = getPossibleTargets(n, site).iterator(); - if (targets.hasNext()) { - result.append(" - " + site + "\n"); - } - for (; targets.hasNext();) { - CGNode target = (CGNode) targets.next(); - result.append(" -> " + target + "\n"); - } - } - } - } - return result.toString(); - } - - @Override - public void removeNodeAndEdges(CGNode N) throws UnimplementedError { - Assertions.UNREACHABLE(); - } - - /** - * @return NodeImpl, or null if none found - */ - public CGNode getNode(IMethod method, Context C) { - Key key = new Key(method, C); - return getNode(key); - } - - protected final static class Key { - private final IMethod m; - - private final Context C; - - public Key(IMethod m, Context C) { - assert m != null : "null method"; - assert C != null : "null context"; - this.m = m; - this.C = C; - } - - @Override - public int hashCode() { - return 17 * m.hashCode() + C.hashCode(); - } - - @Override - public boolean equals(Object o) { - assert o instanceof Key; - Key other = (Key) o; - return (m.equals(other.m) && C.equals(other.C)); - } - - @Override - public String toString() { - return "{" + m + "," + C + "}"; - } - - } - - public Set getNodes(MethodReference m) { - IMethod im = getClassHierarchy().resolveMethod(m); - if (im == null) { - return Collections.emptySet(); - } - Set result = mr2Nodes.get(im.getReference()); - Set empty = Collections.emptySet(); - return (result == null) ? empty : result; - } - - /** - * @param node a call graph node we want information about - * @return an object that knows how to interpret information about the node - */ - protected SSAContextInterpreter getInterpreter(CGNode node) { - if (interpreter == null) { - throw new IllegalStateException("must register an interpreter for this call graph"); - } - return interpreter; - } - - /** - * We override this since this class supports remove() on nodes, but the superclass doesn't. - * - * @see com.ibm.wala.util.graph.Graph#getNumberOfNodes() - */ - @Override - public int getNumberOfNodes() { - return nodes.size(); - } - - /** - * We override this since this class supports remove() on nodes, but the superclass doesn't. - * - * @see com.ibm.wala.util.graph.Graph#iterator() - */ - @Override - public Iterator iterator() { - return nodes.values().iterator(); - } - - /** - * This implementation is necessary because the underlying SparseNumberedGraph may not support node membership tests. - * - * @throws IllegalArgumentException if N is null - * - */ - @Override - public boolean containsNode(CGNode N) { - if (N == null) { - throw new IllegalArgumentException("N is null"); - } - return getNode(N.getMethod(), N.getContext()) != null; - } - - public void setInterpreter(SSAContextInterpreter interpreter) { - this.interpreter = interpreter; - } - - @Override - protected NumberedNodeManager getNodeManager() { - return nodeManager; - } - - public void summarizeByPackage() { - Map packages = HashMapFactory.make(); - for(CGNode n : this) { - String nm = n.getMethod().getDeclaringClass().getName().toString() + "/" + n.getMethod().getName() + "/" + n.getContext().getClass().toString(); - - if (n.getContext() instanceof ReceiverInstanceContext) { - nm = nm + "/" + ((ReceiverInstanceContext)n.getContext()).getReceiver().getConcreteType().getName(); - } else if (n.getContext() instanceof JavaTypeContext) { - nm = nm + "/" + ((JavaTypeContext)n.getContext()).getType().getTypeReference().getName(); - } - - do { - if (packages.containsKey(nm)) { - packages.put(nm, 1 + packages.get(nm)); - } else { - packages.put(nm, 1); - } - - if (nm.indexOf('/') < 0) { - break; - } - - nm = nm.substring(0, nm.lastIndexOf('/')); - } while (true); - } - - System.err.println("dump of CG"); - for(Map.Entry e : packages.entrySet()) { - System.err.println(e.getValue().intValue() + " " + e.getKey()); - } - } - -} +/******************************************************************************* + * 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.ipa.callgraph.impl; + +import java.util.Collection; +import java.util.Collections; +import java.util.Iterator; +import java.util.Map; +import java.util.Set; + +import com.ibm.wala.analysis.reflection.JavaTypeContext; +import com.ibm.wala.classLoader.CallSiteReference; +import com.ibm.wala.classLoader.IMethod; +import com.ibm.wala.ipa.callgraph.CGNode; +import com.ibm.wala.ipa.callgraph.CallGraph; +import com.ibm.wala.ipa.callgraph.Context; +import com.ibm.wala.ipa.callgraph.propagation.ReceiverInstanceContext; +import com.ibm.wala.ipa.callgraph.propagation.SSAContextInterpreter; +import com.ibm.wala.ipa.cha.IClassHierarchy; +import com.ibm.wala.shrikeBT.IInvokeInstruction; +import com.ibm.wala.types.MethodReference; +import com.ibm.wala.util.CancelException; +import com.ibm.wala.util.collections.HashMapFactory; +import com.ibm.wala.util.collections.HashSetFactory; +import com.ibm.wala.util.collections.NonNullSingletonIterator; +import com.ibm.wala.util.debug.Assertions; +import com.ibm.wala.util.debug.UnimplementedError; +import com.ibm.wala.util.graph.AbstractNumberedGraph; +import com.ibm.wala.util.graph.NumberedNodeManager; +import com.ibm.wala.util.graph.impl.DelegatingNumberedNodeManager; +import com.ibm.wala.util.graph.impl.NodeWithNumber; +import com.ibm.wala.util.graph.traverse.DFS; + +/** + * Basic data structure support for a call graph. + */ +public abstract class BasicCallGraph extends AbstractNumberedGraph implements CallGraph { + + private static final boolean DEBUG = false; + + private final DelegatingNumberedNodeManager nodeManager = new DelegatingNumberedNodeManager(); + + /** + * A fake root node for the graph + */ + private CGNode fakeRoot; + + /** + * A node which handles all calls to class initializers + */ + private CGNode fakeWorldClinit; + + /** + * An object that handles context interpreter functions + */ + private SSAContextInterpreter interpreter; + + /** + * Set of nodes that are entrypoints for this analysis + */ + private final Set entrypointNodes = HashSetFactory.make(); + + /** + * A mapping from Key to NodeImpls in the graph. Note that each node is created on demand. This Map does not include the root + * node. + */ + final private Map nodes = HashMapFactory.make(); + + /** + * A mapping from MethodReference to Set of nodes that represent this methodReference. + * + * TODO: rhs of mapping doesn't have to be a set if it's a singleton; could be a node instead. + * + * TODO: this is a bit redundant with the nodes Map. Restructure these data structures for space efficiency. + */ + final private Map> mr2Nodes = HashMapFactory.make(); + + public BasicCallGraph() { + super(); + } + + @SuppressWarnings("deprecation") + public void init() throws CancelException { + fakeRoot = makeFakeRootNode(); + Key k = new Key(fakeRoot.getMethod(), fakeRoot.getContext()); + registerNode(k, fakeRoot); + fakeWorldClinit = makeFakeWorldClinitNode(); + if (fakeWorldClinit != null) { + k = new Key(fakeWorldClinit.getMethod(), fakeWorldClinit.getContext()); + registerNode(k, fakeWorldClinit); + + // add a call from fakeRoot to fakeWorldClinit + CallSiteReference site = CallSiteReference.make(1, fakeWorldClinit.getMethod().getReference(), + IInvokeInstruction.Dispatch.STATIC); + // note that the result of addInvocation is a different site, with a different program counter! + site = ((AbstractRootMethod) fakeRoot.getMethod()).addInvocation(null, site).getCallSite(); + fakeRoot.addTarget(site, fakeWorldClinit); + } + } + + protected abstract CGNode makeFakeRootNode() throws CancelException; + + protected abstract CGNode makeFakeWorldClinitNode() throws CancelException; + + /** + * Use with extreme care. + * + * @throws CancelException TODO + */ + public abstract CGNode findOrCreateNode(IMethod method, Context C) throws CancelException; + + protected void registerNode(Key K, CGNode N) { + nodes.put(K, N); + addNode(N); + Set s = findOrCreateMr2Nodes(K.m); + s.add(N); + if (DEBUG) { + System.err.println(("registered Node: " + N + " for key " + K)); + System.err.println(("now size = " + getNumberOfNodes())); + } + } + + private Set findOrCreateMr2Nodes(IMethod method) { + Set result = mr2Nodes.get(method.getReference()); + if (result == null) { + result = HashSetFactory.make(3); + mr2Nodes.put(method.getReference(), result); + } + return result; + } + + protected NodeImpl getNode(Key K) { + return (NodeImpl) nodes.get(K); + } + + public CGNode getFakeRootNode() { + return fakeRoot; + } + + public CGNode getFakeWorldClinitNode() { + return fakeWorldClinit; + } + + /** + * record that a node is an entrypoint + */ + public void registerEntrypoint(CGNode node) { + entrypointNodes.add(node); + } + + /** + * Note: not all successors of the root node are entrypoints + */ + public Collection getEntrypointNodes() { + return entrypointNodes; + } + + /** + * A class that represents the a normal node in a call graph. + */ + public abstract class NodeImpl extends NodeWithNumber implements CGNode { + + /** + * The method this node represents. + */ + protected final IMethod method; + + /** + * The context this node represents. + */ + private final Context context; + + protected NodeImpl(IMethod method, Context C) { + this.method = method; + this.context = C; + if (method != null && !method.isSynthetic() && method.isAbstract()) { + assert !method.isAbstract() : "Abstract method " + method; + } + assert C != null; + } + + public IMethod getMethod() { + return method; + } + + /** + * @see java.lang.Object#equals(Object) + */ + @Override + public abstract boolean equals(Object obj); + + /** + * @see java.lang.Object#hashCode() + */ + @Override + public abstract int hashCode(); + + /** + * @see java.lang.Object#toString() + */ + @Override + public String toString() { + return "Node: " + method.toString() + " Context: " + context.toString(); + } + + public Context getContext() { + return context; + } + + public abstract boolean addTarget(CallSiteReference reference, CGNode target); + + public IClassHierarchy getClassHierarchy() { + return method.getClassHierarchy(); + } + } + + @Override + public String toString() { + StringBuffer result = new StringBuffer(""); + for (Iterator i = DFS.iterateDiscoverTime(this, new NonNullSingletonIterator(getFakeRootNode())); i.hasNext();) { + CGNode n = (CGNode) i.next(); + result.append(n + "\n"); + if (n.getMethod() != null) { + for (Iterator sites = n.iterateCallSites(); sites.hasNext();) { + CallSiteReference site = (CallSiteReference) sites.next(); + Iterator targets = getPossibleTargets(n, site).iterator(); + if (targets.hasNext()) { + result.append(" - " + site + "\n"); + } + for (; targets.hasNext();) { + CGNode target = (CGNode) targets.next(); + result.append(" -> " + target + "\n"); + } + } + } + } + return result.toString(); + } + + @Override + public void removeNodeAndEdges(CGNode N) throws UnimplementedError { + Assertions.UNREACHABLE(); + } + + /** + * @return NodeImpl, or null if none found + */ + public CGNode getNode(IMethod method, Context C) { + Key key = new Key(method, C); + return getNode(key); + } + + protected final static class Key { + private final IMethod m; + + private final Context C; + + public Key(IMethod m, Context C) { + assert m != null : "null method"; + assert C != null : "null context"; + this.m = m; + this.C = C; + } + + @Override + public int hashCode() { + return 17 * m.hashCode() + C.hashCode(); + } + + @Override + public boolean equals(Object o) { + assert o instanceof Key; + Key other = (Key) o; + return (m.equals(other.m) && C.equals(other.C)); + } + + @Override + public String toString() { + return "{" + m + "," + C + "}"; + } + + } + + public Set getNodes(MethodReference m) { + IMethod im = getClassHierarchy().resolveMethod(m); + if (im == null) { + return Collections.emptySet(); + } + Set result = mr2Nodes.get(im.getReference()); + Set empty = Collections.emptySet(); + return (result == null) ? empty : result; + } + + /** + * @param node a call graph node we want information about + * @return an object that knows how to interpret information about the node + */ + protected SSAContextInterpreter getInterpreter(CGNode node) { + if (interpreter == null) { + throw new IllegalStateException("must register an interpreter for this call graph"); + } + return interpreter; + } + + /** + * We override this since this class supports remove() on nodes, but the superclass doesn't. + * + * @see com.ibm.wala.util.graph.Graph#getNumberOfNodes() + */ + @Override + public int getNumberOfNodes() { + return nodes.size(); + } + + /** + * We override this since this class supports remove() on nodes, but the superclass doesn't. + * + * @see com.ibm.wala.util.graph.Graph#iterator() + */ + @Override + public Iterator iterator() { + return nodes.values().iterator(); + } + + /** + * This implementation is necessary because the underlying SparseNumberedGraph may not support node membership tests. + * + * @throws IllegalArgumentException if N is null + * + */ + @Override + public boolean containsNode(CGNode N) { + if (N == null) { + throw new IllegalArgumentException("N is null"); + } + return getNode(N.getMethod(), N.getContext()) != null; + } + + public void setInterpreter(SSAContextInterpreter interpreter) { + this.interpreter = interpreter; + } + + @Override + protected NumberedNodeManager getNodeManager() { + return nodeManager; + } + + public void summarizeByPackage() { + Map packages = HashMapFactory.make(); + for(CGNode n : this) { + String nm = n.getMethod().getDeclaringClass().getName().toString() + "/" + n.getMethod().getName() + "/" + n.getContext().getClass().toString(); + + if (n.getContext() instanceof ReceiverInstanceContext) { + nm = nm + "/" + ((ReceiverInstanceContext)n.getContext()).getReceiver().getConcreteType().getName(); + } else if (n.getContext() instanceof JavaTypeContext) { + nm = nm + "/" + ((JavaTypeContext)n.getContext()).getType().getTypeReference().getName(); + } + + do { + if (packages.containsKey(nm)) { + packages.put(nm, 1 + packages.get(nm)); + } else { + packages.put(nm, 1); + } + + if (nm.indexOf('/') < 0) { + break; + } + + nm = nm.substring(0, nm.lastIndexOf('/')); + } while (true); + } + + System.err.println("dump of CG"); + for(Map.Entry e : packages.entrySet()) { + System.err.println(e.getValue().intValue() + " " + e.getKey()); + } + } + +} diff --git a/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/impl/ClassHierarchyClassTargetSelector.java b/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/impl/ClassHierarchyClassTargetSelector.java index 01c8f8d5b..1628b87cd 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/impl/ClassHierarchyClassTargetSelector.java +++ b/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/impl/ClassHierarchyClassTargetSelector.java @@ -1,46 +1,46 @@ -/******************************************************************************* - * Copyright (c) 2002 - 2006 IBM Corporation. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * IBM Corporation - initial API and implementation - *******************************************************************************/ -package com.ibm.wala.ipa.callgraph.impl; - -import com.ibm.wala.classLoader.IClass; -import com.ibm.wala.classLoader.NewSiteReference; -import com.ibm.wala.ipa.callgraph.CGNode; -import com.ibm.wala.ipa.callgraph.ClassTargetSelector; -import com.ibm.wala.ipa.cha.IClassHierarchy; - -/** - * A {@link ClassTargetSelector} that simply looks up the declared type of a {@link NewSiteReference} in the appropriate class hierarchy. - */ -public class ClassHierarchyClassTargetSelector implements ClassTargetSelector { - - private final IClassHierarchy cha; - - /** - * @param cha governing class hierarchy - */ - public ClassHierarchyClassTargetSelector(IClassHierarchy cha) { - this.cha = cha; - } - - public IClass getAllocatedTarget(CGNode caller, NewSiteReference site) { - if (site == null) { - throw new IllegalArgumentException("site is null"); - } - IClass klass = cha.lookupClass(site.getDeclaredType()); - if (klass == null) { - return null; - } else if (klass.isAbstract()) { - return null; - } else { - return klass; - } - } +/******************************************************************************* + * 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.ipa.callgraph.impl; + +import com.ibm.wala.classLoader.IClass; +import com.ibm.wala.classLoader.NewSiteReference; +import com.ibm.wala.ipa.callgraph.CGNode; +import com.ibm.wala.ipa.callgraph.ClassTargetSelector; +import com.ibm.wala.ipa.cha.IClassHierarchy; + +/** + * A {@link ClassTargetSelector} that simply looks up the declared type of a {@link NewSiteReference} in the appropriate class hierarchy. + */ +public class ClassHierarchyClassTargetSelector implements ClassTargetSelector { + + private final IClassHierarchy cha; + + /** + * @param cha governing class hierarchy + */ + public ClassHierarchyClassTargetSelector(IClassHierarchy cha) { + this.cha = cha; + } + + public IClass getAllocatedTarget(CGNode caller, NewSiteReference site) { + if (site == null) { + throw new IllegalArgumentException("site is null"); + } + IClass klass = cha.lookupClass(site.getDeclaredType()); + if (klass == null) { + return null; + } else if (klass.isAbstract()) { + return null; + } else { + return klass; + } + } } \ No newline at end of file diff --git a/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/impl/ClassHierarchyMethodTargetSelector.java b/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/impl/ClassHierarchyMethodTargetSelector.java index f20005a07..9bbb497f7 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/impl/ClassHierarchyMethodTargetSelector.java +++ b/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/impl/ClassHierarchyMethodTargetSelector.java @@ -1,86 +1,86 @@ -/******************************************************************************* - * Copyright (c) 2002 - 2006 IBM Corporation. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * IBM Corporation - initial API and implementation - *******************************************************************************/ -package com.ibm.wala.ipa.callgraph.impl; - -import com.ibm.wala.classLoader.CallSiteReference; -import com.ibm.wala.classLoader.IClass; -import com.ibm.wala.classLoader.IMethod; -import com.ibm.wala.ipa.callgraph.CGNode; -import com.ibm.wala.ipa.callgraph.MethodTargetSelector; -import com.ibm.wala.ipa.cha.IClassHierarchy; -import com.ibm.wala.types.MethodReference; -import com.ibm.wala.types.TypeReference; - -/** - * A {@link MethodTargetSelector} that simply looks up the declared type, name and descriptor of a {@link CallSiteReference} in the - * appropriate class hierarchy. - */ -public class ClassHierarchyMethodTargetSelector implements MethodTargetSelector { - - /** - * Governing class hierarchy - */ - private final IClassHierarchy classHierarchy; - - /** - * Initialization. The class hierarchy is needed for lookups and the warnings are used when the lookups fails (which should never - * happen). - * - * @param cha The class hierarchy to use. - */ - public ClassHierarchyMethodTargetSelector(IClassHierarchy cha) { - classHierarchy = cha; - } - - /** - * This target selector searches the class hierarchy for the method matching the signature of the call that is appropriate for the - * receiver type. - * - * @throws IllegalArgumentException if call is null - */ - public IMethod getCalleeTarget(CGNode caller, CallSiteReference call, IClass receiver) { - - if (call == null) { - throw new IllegalArgumentException("call is null"); - } - IClass klass; - TypeReference targetType = call.getDeclaredTarget().getDeclaringClass(); - - // java virtual calls - if (call.isDispatch()) { - assert receiver != null : "null receiver for " + call; - klass = receiver; - - // java static calls - } else if (call.isFixed()) { - klass = classHierarchy.lookupClass(targetType); - if (klass == null) { - return null; - } - // anything else - } else { - return null; - } - - return classHierarchy.resolveMethod(klass, call.getDeclaredTarget().getSelector()); - } - - public boolean mightReturnSyntheticMethod(CGNode caller, CallSiteReference site) { - return false; - } - - /* - * @see com.ibm.wala.ipa.callgraph.MethodTargetSelector#mightReturnSyntheticMethod(com.ibm.wala.types.MethodReference) - */ - public boolean mightReturnSyntheticMethod(MethodReference declaredTarget) { - return false; - } -} +/******************************************************************************* + * 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.ipa.callgraph.impl; + +import com.ibm.wala.classLoader.CallSiteReference; +import com.ibm.wala.classLoader.IClass; +import com.ibm.wala.classLoader.IMethod; +import com.ibm.wala.ipa.callgraph.CGNode; +import com.ibm.wala.ipa.callgraph.MethodTargetSelector; +import com.ibm.wala.ipa.cha.IClassHierarchy; +import com.ibm.wala.types.MethodReference; +import com.ibm.wala.types.TypeReference; + +/** + * A {@link MethodTargetSelector} that simply looks up the declared type, name and descriptor of a {@link CallSiteReference} in the + * appropriate class hierarchy. + */ +public class ClassHierarchyMethodTargetSelector implements MethodTargetSelector { + + /** + * Governing class hierarchy + */ + private final IClassHierarchy classHierarchy; + + /** + * Initialization. The class hierarchy is needed for lookups and the warnings are used when the lookups fails (which should never + * happen). + * + * @param cha The class hierarchy to use. + */ + public ClassHierarchyMethodTargetSelector(IClassHierarchy cha) { + classHierarchy = cha; + } + + /** + * This target selector searches the class hierarchy for the method matching the signature of the call that is appropriate for the + * receiver type. + * + * @throws IllegalArgumentException if call is null + */ + public IMethod getCalleeTarget(CGNode caller, CallSiteReference call, IClass receiver) { + + if (call == null) { + throw new IllegalArgumentException("call is null"); + } + IClass klass; + TypeReference targetType = call.getDeclaredTarget().getDeclaringClass(); + + // java virtual calls + if (call.isDispatch()) { + assert receiver != null : "null receiver for " + call; + klass = receiver; + + // java static calls + } else if (call.isFixed()) { + klass = classHierarchy.lookupClass(targetType); + if (klass == null) { + return null; + } + // anything else + } else { + return null; + } + + return classHierarchy.resolveMethod(klass, call.getDeclaredTarget().getSelector()); + } + + public boolean mightReturnSyntheticMethod(CGNode caller, CallSiteReference site) { + return false; + } + + /* + * @see com.ibm.wala.ipa.callgraph.MethodTargetSelector#mightReturnSyntheticMethod(com.ibm.wala.types.MethodReference) + */ + public boolean mightReturnSyntheticMethod(MethodReference declaredTarget) { + return false; + } +} diff --git a/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/impl/ComposedEntrypoints.java b/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/impl/ComposedEntrypoints.java index 95d1949a7..51c52fb93 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/impl/ComposedEntrypoints.java +++ b/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/impl/ComposedEntrypoints.java @@ -1,46 +1,46 @@ -/******************************************************************************* - * Copyright (c) 2002 - 2006 IBM Corporation. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * IBM Corporation - initial API and implementation - *******************************************************************************/ - -package com.ibm.wala.ipa.callgraph.impl; - -import java.util.Iterator; -import java.util.Set; - -import com.ibm.wala.ipa.callgraph.Entrypoint; -import com.ibm.wala.util.collections.HashSetFactory; - -/** - * This class represents the union of two sets of {@link Entrypoint}s. - */ -public class ComposedEntrypoints implements Iterable { - - final private Set entrypoints = HashSetFactory.make(); - - public ComposedEntrypoints(Iterable A, Iterable B) { - if (A == null) { - throw new IllegalArgumentException("A is null"); - } - if (B == null) { - throw new IllegalArgumentException("B is null"); - } - for (Iterator it = A.iterator(); it.hasNext(); ) { - entrypoints.add(it.next()); - } - for (Iterator it = B.iterator(); it.hasNext(); ) { - entrypoints.add(it.next()); - } - } - - public Iterator iterator() { - return entrypoints.iterator(); - } - -} +/******************************************************************************* + * 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.ipa.callgraph.impl; + +import java.util.Iterator; +import java.util.Set; + +import com.ibm.wala.ipa.callgraph.Entrypoint; +import com.ibm.wala.util.collections.HashSetFactory; + +/** + * This class represents the union of two sets of {@link Entrypoint}s. + */ +public class ComposedEntrypoints implements Iterable { + + final private Set entrypoints = HashSetFactory.make(); + + public ComposedEntrypoints(Iterable A, Iterable B) { + if (A == null) { + throw new IllegalArgumentException("A is null"); + } + if (B == null) { + throw new IllegalArgumentException("B is null"); + } + for (Iterator it = A.iterator(); it.hasNext(); ) { + entrypoints.add(it.next()); + } + for (Iterator it = B.iterator(); it.hasNext(); ) { + entrypoints.add(it.next()); + } + } + + public Iterator iterator() { + return entrypoints.iterator(); + } + +} diff --git a/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/impl/ContextInsensitiveSelector.java b/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/impl/ContextInsensitiveSelector.java index d9bac12fa..e0e9ebc46 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/impl/ContextInsensitiveSelector.java +++ b/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/impl/ContextInsensitiveSelector.java @@ -1,36 +1,36 @@ -/******************************************************************************* - * 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.ipa.callgraph.impl; - -import com.ibm.wala.classLoader.CallSiteReference; -import com.ibm.wala.classLoader.IMethod; -import com.ibm.wala.ipa.callgraph.CGNode; -import com.ibm.wala.ipa.callgraph.Context; -import com.ibm.wala.ipa.callgraph.ContextSelector; -import com.ibm.wala.ipa.callgraph.propagation.InstanceKey; -import com.ibm.wala.util.intset.EmptyIntSet; -import com.ibm.wala.util.intset.IntSet; - -/** - * A basic context selector that ignores context. - */ -public class ContextInsensitiveSelector implements ContextSelector { - - public Context getCalleeTarget(CGNode caller, CallSiteReference site, IMethod callee, InstanceKey[] receiver) { - return Everywhere.EVERYWHERE; - } - - public IntSet getRelevantParameters(CGNode caller, CallSiteReference site) { - return EmptyIntSet.instance; - } - -} +/******************************************************************************* + * 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.ipa.callgraph.impl; + +import com.ibm.wala.classLoader.CallSiteReference; +import com.ibm.wala.classLoader.IMethod; +import com.ibm.wala.ipa.callgraph.CGNode; +import com.ibm.wala.ipa.callgraph.Context; +import com.ibm.wala.ipa.callgraph.ContextSelector; +import com.ibm.wala.ipa.callgraph.propagation.InstanceKey; +import com.ibm.wala.util.intset.EmptyIntSet; +import com.ibm.wala.util.intset.IntSet; + +/** + * A basic context selector that ignores context. + */ +public class ContextInsensitiveSelector implements ContextSelector { + + public Context getCalleeTarget(CGNode caller, CallSiteReference site, IMethod callee, InstanceKey[] receiver) { + return Everywhere.EVERYWHERE; + } + + public IntSet getRelevantParameters(CGNode caller, CallSiteReference site) { + return EmptyIntSet.instance; + } + +} diff --git a/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/impl/DefaultContextSelector.java b/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/impl/DefaultContextSelector.java index 06c6e7140..ca321ea66 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/impl/DefaultContextSelector.java +++ b/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/impl/DefaultContextSelector.java @@ -1,53 +1,53 @@ -/******************************************************************************* - * Copyright (c) 2002 - 2006 IBM Corporation. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * IBM Corporation - initial API and implementation - *******************************************************************************/ -package com.ibm.wala.ipa.callgraph.impl; - -import com.ibm.wala.analysis.reflection.ReflectionContextSelector; -import com.ibm.wala.classLoader.CallSiteReference; -import com.ibm.wala.classLoader.IMethod; -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.ContextSelector; -import com.ibm.wala.ipa.callgraph.propagation.CloneContextSelector; -import com.ibm.wala.ipa.callgraph.propagation.InstanceKey; -import com.ibm.wala.ipa.cha.IClassHierarchy; -import com.ibm.wala.util.intset.IntSet; - -/** - * Default object to control context-insensitive context selection, This includes reflection logic. - */ -public class DefaultContextSelector implements ContextSelector { - - private final ContextSelector delegate; - - public DefaultContextSelector(AnalysisOptions options, IClassHierarchy cha) { - if (options == null) { - throw new IllegalArgumentException("null options"); - } - ContextInsensitiveSelector ci = new ContextInsensitiveSelector(); - ContextSelector r = ReflectionContextSelector.createReflectionContextSelector(options); - ContextSelector s = new DelegatingContextSelector(r, ci); - delegate = new DelegatingContextSelector(new CloneContextSelector(cha), s); - } - - public Context getCalleeTarget(CGNode caller, CallSiteReference site, IMethod callee, InstanceKey[] receiver) { - if (caller == null) { - throw new IllegalArgumentException("null caller"); - } - return delegate.getCalleeTarget(caller, site, callee, receiver); - } - - public IntSet getRelevantParameters(CGNode caller, CallSiteReference site) { - return delegate.getRelevantParameters(caller, site); - } - +/******************************************************************************* + * 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.ipa.callgraph.impl; + +import com.ibm.wala.analysis.reflection.ReflectionContextSelector; +import com.ibm.wala.classLoader.CallSiteReference; +import com.ibm.wala.classLoader.IMethod; +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.ContextSelector; +import com.ibm.wala.ipa.callgraph.propagation.CloneContextSelector; +import com.ibm.wala.ipa.callgraph.propagation.InstanceKey; +import com.ibm.wala.ipa.cha.IClassHierarchy; +import com.ibm.wala.util.intset.IntSet; + +/** + * Default object to control context-insensitive context selection, This includes reflection logic. + */ +public class DefaultContextSelector implements ContextSelector { + + private final ContextSelector delegate; + + public DefaultContextSelector(AnalysisOptions options, IClassHierarchy cha) { + if (options == null) { + throw new IllegalArgumentException("null options"); + } + ContextInsensitiveSelector ci = new ContextInsensitiveSelector(); + ContextSelector r = ReflectionContextSelector.createReflectionContextSelector(options); + ContextSelector s = new DelegatingContextSelector(r, ci); + delegate = new DelegatingContextSelector(new CloneContextSelector(cha), s); + } + + public Context getCalleeTarget(CGNode caller, CallSiteReference site, IMethod callee, InstanceKey[] receiver) { + if (caller == null) { + throw new IllegalArgumentException("null caller"); + } + return delegate.getCalleeTarget(caller, site, callee, receiver); + } + + public IntSet getRelevantParameters(CGNode caller, CallSiteReference site) { + return delegate.getRelevantParameters(caller, site); + } + } \ No newline at end of file diff --git a/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/impl/DefaultEntrypoint.java b/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/impl/DefaultEntrypoint.java index b4030f234..f9580fc93 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/impl/DefaultEntrypoint.java +++ b/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/impl/DefaultEntrypoint.java @@ -1,109 +1,109 @@ -/******************************************************************************* - * 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.ipa.callgraph.impl; - -import java.util.Arrays; - -import com.ibm.wala.classLoader.IMethod; -import com.ibm.wala.ipa.callgraph.Entrypoint; -import com.ibm.wala.ipa.cha.IClassHierarchy; -import com.ibm.wala.types.MethodReference; -import com.ibm.wala.types.TypeReference; - -/** - * An entrypoint whose parameter types are the declared types. - */ -public class DefaultEntrypoint extends Entrypoint { - private final TypeReference[][] paramTypes; - - private final IClassHierarchy cha; - - public DefaultEntrypoint(IMethod method, IClassHierarchy cha) { - - super(method); - if (method == null) { - throw new IllegalArgumentException("method is null"); - } - this.cha = cha; - paramTypes = makeParameterTypes(method); - assert paramTypes != null : method.toString(); - } - - public DefaultEntrypoint(MethodReference method, IClassHierarchy cha) { - super(method, cha); - if (method == null) { - throw new IllegalArgumentException("method is null"); - } - this.cha = cha; - paramTypes = makeParameterTypes(getMethod()); - assert paramTypes != null : method.toString(); - } - - protected TypeReference[][] makeParameterTypes(IMethod method) { - TypeReference[][] result = new TypeReference[method.getNumberOfParameters()][]; - for (int i = 0; i < result.length; i++) { - result[i] = makeParameterTypes(method, i); - } - - return result; - } - - protected TypeReference[] makeParameterTypes(IMethod method, int i) { - return new TypeReference[] { method.getParameterType(i) }; - } - - /* - * @see com.ibm.wala.ipa.callgraph.Entrypoint#getParameterTypes(int) - */ - @Override - public TypeReference[] getParameterTypes(int i) { - return paramTypes[i]; - } - - public void setParameterTypes(int i, TypeReference[] types) { - paramTypes[i] = types; - } - - /* - * @see com.ibm.wala.ipa.callgraph.Entrypoint#getNumberOfParameters() - */ - @Override - public int getNumberOfParameters() { - return paramTypes.length; - } - - public IClassHierarchy getCha() { - return cha; - } - - @Override - public int hashCode() { - final int prime = 31; - int result = super.hashCode(); - result = prime * result + Arrays.hashCode(paramTypes); - return result; - } - - @Override - public boolean equals(Object obj) { - if (this == obj) - return true; - if (!super.equals(obj)) - return false; - if (getClass() != obj.getClass()) - return false; - final DefaultEntrypoint other = (DefaultEntrypoint) obj; - if (!Arrays.equals(paramTypes, other.paramTypes)) - return false; - return true; - } -} +/******************************************************************************* + * 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.ipa.callgraph.impl; + +import java.util.Arrays; + +import com.ibm.wala.classLoader.IMethod; +import com.ibm.wala.ipa.callgraph.Entrypoint; +import com.ibm.wala.ipa.cha.IClassHierarchy; +import com.ibm.wala.types.MethodReference; +import com.ibm.wala.types.TypeReference; + +/** + * An entrypoint whose parameter types are the declared types. + */ +public class DefaultEntrypoint extends Entrypoint { + private final TypeReference[][] paramTypes; + + private final IClassHierarchy cha; + + public DefaultEntrypoint(IMethod method, IClassHierarchy cha) { + + super(method); + if (method == null) { + throw new IllegalArgumentException("method is null"); + } + this.cha = cha; + paramTypes = makeParameterTypes(method); + assert paramTypes != null : method.toString(); + } + + public DefaultEntrypoint(MethodReference method, IClassHierarchy cha) { + super(method, cha); + if (method == null) { + throw new IllegalArgumentException("method is null"); + } + this.cha = cha; + paramTypes = makeParameterTypes(getMethod()); + assert paramTypes != null : method.toString(); + } + + protected TypeReference[][] makeParameterTypes(IMethod method) { + TypeReference[][] result = new TypeReference[method.getNumberOfParameters()][]; + for (int i = 0; i < result.length; i++) { + result[i] = makeParameterTypes(method, i); + } + + return result; + } + + protected TypeReference[] makeParameterTypes(IMethod method, int i) { + return new TypeReference[] { method.getParameterType(i) }; + } + + /* + * @see com.ibm.wala.ipa.callgraph.Entrypoint#getParameterTypes(int) + */ + @Override + public TypeReference[] getParameterTypes(int i) { + return paramTypes[i]; + } + + public void setParameterTypes(int i, TypeReference[] types) { + paramTypes[i] = types; + } + + /* + * @see com.ibm.wala.ipa.callgraph.Entrypoint#getNumberOfParameters() + */ + @Override + public int getNumberOfParameters() { + return paramTypes.length; + } + + public IClassHierarchy getCha() { + return cha; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = super.hashCode(); + result = prime * result + Arrays.hashCode(paramTypes); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (!super.equals(obj)) + return false; + if (getClass() != obj.getClass()) + return false; + final DefaultEntrypoint other = (DefaultEntrypoint) obj; + if (!Arrays.equals(paramTypes, other.paramTypes)) + return false; + return true; + } +} diff --git a/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/impl/DelegatingContextSelector.java b/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/impl/DelegatingContextSelector.java index b4a8eba48..0ba236096 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/impl/DelegatingContextSelector.java +++ b/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/impl/DelegatingContextSelector.java @@ -1,66 +1,66 @@ -/******************************************************************************* - * Copyright (c) 2002 - 2006 IBM Corporation. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * IBM Corporation - initial API and implementation - *******************************************************************************/ -package com.ibm.wala.ipa.callgraph.impl; - -import com.ibm.wala.classLoader.CallSiteReference; -import com.ibm.wala.classLoader.IMethod; -import com.ibm.wala.ipa.callgraph.CGNode; -import com.ibm.wala.ipa.callgraph.Context; -import com.ibm.wala.ipa.callgraph.ContextSelector; -import com.ibm.wala.ipa.callgraph.propagation.InstanceKey; -import com.ibm.wala.util.intset.IntSet; - -/** - * A context selector that first checks with A, then defaults to B. - */ -public class DelegatingContextSelector implements ContextSelector { - - private static final boolean DEBUG = false; - - private final ContextSelector A; - private final ContextSelector B; - - public DelegatingContextSelector(ContextSelector A, ContextSelector B) { - this.A = A; - this.B = B; - if (A == null) { - throw new IllegalArgumentException("null A"); - } - if (B == null) { - throw new IllegalArgumentException("null B"); - } - } - - public Context getCalleeTarget(CGNode caller, CallSiteReference site, IMethod callee, InstanceKey[] receiver) { - if (DEBUG) { - System.err.println(("getCalleeTarget " + caller + " " + site + " " + callee)); - } - if (A != null) { - Context C = A.getCalleeTarget(caller, site, callee, receiver); - if (C != null) { - if (DEBUG) { - System.err.println(("Case A " + A.getClass() + " " + C)); - } - return C; - } - } - Context C = B.getCalleeTarget(caller, site, callee, receiver); - if (DEBUG) { - System.err.println(("Case B " + B.getClass() + " " + C)); - } - return C; - } - - public IntSet getRelevantParameters(CGNode caller, CallSiteReference site) { - return A.getRelevantParameters(caller, site).union(B.getRelevantParameters(caller, site)); - } - +/******************************************************************************* + * 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.ipa.callgraph.impl; + +import com.ibm.wala.classLoader.CallSiteReference; +import com.ibm.wala.classLoader.IMethod; +import com.ibm.wala.ipa.callgraph.CGNode; +import com.ibm.wala.ipa.callgraph.Context; +import com.ibm.wala.ipa.callgraph.ContextSelector; +import com.ibm.wala.ipa.callgraph.propagation.InstanceKey; +import com.ibm.wala.util.intset.IntSet; + +/** + * A context selector that first checks with A, then defaults to B. + */ +public class DelegatingContextSelector implements ContextSelector { + + private static final boolean DEBUG = false; + + private final ContextSelector A; + private final ContextSelector B; + + public DelegatingContextSelector(ContextSelector A, ContextSelector B) { + this.A = A; + this.B = B; + if (A == null) { + throw new IllegalArgumentException("null A"); + } + if (B == null) { + throw new IllegalArgumentException("null B"); + } + } + + public Context getCalleeTarget(CGNode caller, CallSiteReference site, IMethod callee, InstanceKey[] receiver) { + if (DEBUG) { + System.err.println(("getCalleeTarget " + caller + " " + site + " " + callee)); + } + if (A != null) { + Context C = A.getCalleeTarget(caller, site, callee, receiver); + if (C != null) { + if (DEBUG) { + System.err.println(("Case A " + A.getClass() + " " + C)); + } + return C; + } + } + Context C = B.getCalleeTarget(caller, site, callee, receiver); + if (DEBUG) { + System.err.println(("Case B " + B.getClass() + " " + C)); + } + return C; + } + + public IntSet getRelevantParameters(CGNode caller, CallSiteReference site) { + return A.getRelevantParameters(caller, site).union(B.getRelevantParameters(caller, site)); + } + } \ No newline at end of file diff --git a/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/impl/Everywhere.java b/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/impl/Everywhere.java index 48c0e90f5..ee67917f2 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/impl/Everywhere.java +++ b/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/impl/Everywhere.java @@ -1,51 +1,51 @@ -/******************************************************************************* - * Copyright (c) 2002 - 2006 IBM Corporation. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * IBM Corporation - initial API and implementation - *******************************************************************************/ -package com.ibm.wala.ipa.callgraph.impl; - -import com.ibm.wala.ipa.callgraph.Context; -import com.ibm.wala.ipa.callgraph.ContextItem; -import com.ibm.wala.ipa.callgraph.ContextKey; - -/** - * An object that represent the context everywhere; used for context-insensitive analysis - */ -public class Everywhere implements Context { - - public static final Everywhere EVERYWHERE = new Everywhere(); - - private Everywhere() { - } - - /** - * This context gives no information. - */ - public ContextItem get(ContextKey name) { - return null; - } - - @Override - public String toString() { - return "Everywhere"; - } - - /** - * Don't use default hashCode (java.lang.Object) as it's nondeterministic. - */ - @Override - public int hashCode() { - return 9851; - } - - @Override - public boolean equals(Object obj) { - return this == obj; - } -} +/******************************************************************************* + * 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.ipa.callgraph.impl; + +import com.ibm.wala.ipa.callgraph.Context; +import com.ibm.wala.ipa.callgraph.ContextItem; +import com.ibm.wala.ipa.callgraph.ContextKey; + +/** + * An object that represent the context everywhere; used for context-insensitive analysis + */ +public class Everywhere implements Context { + + public static final Everywhere EVERYWHERE = new Everywhere(); + + private Everywhere() { + } + + /** + * This context gives no information. + */ + public ContextItem get(ContextKey name) { + return null; + } + + @Override + public String toString() { + return "Everywhere"; + } + + /** + * Don't use default hashCode (java.lang.Object) as it's nondeterministic. + */ + @Override + public int hashCode() { + return 9851; + } + + @Override + public boolean equals(Object obj) { + return this == obj; + } +} diff --git a/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/impl/ExplicitCallGraph.java b/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/impl/ExplicitCallGraph.java index 1bd3a5f06..62d25d789 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/impl/ExplicitCallGraph.java +++ b/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/impl/ExplicitCallGraph.java @@ -1,475 +1,475 @@ -/******************************************************************************* - * 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.ipa.callgraph.impl; - -import java.util.Collections; -import java.util.HashSet; -import java.util.Iterator; -import java.util.Set; - -import com.ibm.wala.cfg.ControlFlowGraph; -import com.ibm.wala.classLoader.CallSiteReference; -import com.ibm.wala.classLoader.IMethod; -import com.ibm.wala.classLoader.NewSiteReference; -import com.ibm.wala.ipa.callgraph.AnalysisCache; -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.cha.IClassHierarchy; -import com.ibm.wala.shrikeBT.BytecodeConstants; -import com.ibm.wala.ssa.DefUse; -import com.ibm.wala.ssa.IR; -import com.ibm.wala.ssa.ISSABasicBlock; -import com.ibm.wala.ssa.SSAInstruction; -import com.ibm.wala.util.CancelException; -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.HashSetFactory; -import com.ibm.wala.util.collections.IntMapIterator; -import com.ibm.wala.util.collections.SparseVector; -import com.ibm.wala.util.debug.Assertions; -import com.ibm.wala.util.functions.IntFunction; -import com.ibm.wala.util.graph.NumberedEdgeManager; -import com.ibm.wala.util.intset.BasicNaturalRelation; -import com.ibm.wala.util.intset.IBinaryNaturalRelation; -import com.ibm.wala.util.intset.IntIterator; -import com.ibm.wala.util.intset.IntSet; -import com.ibm.wala.util.intset.MutableIntSet; -import com.ibm.wala.util.intset.MutableSharedBitVectorIntSet; -import com.ibm.wala.util.intset.SparseIntSet; - -/** - * A call graph which explicitly holds the target for each call site in each node. - */ -public class ExplicitCallGraph extends BasicCallGraph implements BytecodeConstants { - - protected final IClassHierarchy cha; - - protected final AnalysisOptions options; - - private final AnalysisCache cache; - - private final long maxNumberOfNodes; - - /** - * special object to track call graph edges - */ - private final ExplicitEdgeManager edgeManager = makeEdgeManger(); - - public ExplicitCallGraph(IClassHierarchy cha, AnalysisOptions options, AnalysisCache cache) { - super(); - if (options == null) { - throw new IllegalArgumentException("null options"); - } - if (cache == null) { - throw new IllegalArgumentException("null cache"); - } - this.cha = cha; - this.options = options; - this.cache = cache; - this.maxNumberOfNodes = options.getMaxNumberOfNodes(); - - } - - /** - * subclasses may wish to override! - */ - protected ExplicitNode makeNode(IMethod method, Context context) { - return new ExplicitNode(method, context); - } - - /** - * subclasses may wish to override! - * - * @throws CancelException - */ - @Override - protected CGNode makeFakeRootNode() throws CancelException { - return findOrCreateNode(new FakeRootMethod(cha, options, cache), Everywhere.EVERYWHERE); - } - - /** - * subclasses may wish to override! - * - * @throws CancelException - */ - @Override - protected CGNode makeFakeWorldClinitNode() throws CancelException { - return findOrCreateNode(new FakeWorldClinitMethod(cha, options, cache), Everywhere.EVERYWHERE); - } - - /** - */ - @Override - public CGNode findOrCreateNode(IMethod method, Context context) throws CancelException { - if (method == null) { - throw new IllegalArgumentException("null method"); - } - if (context == null) { - throw new IllegalArgumentException("null context"); - } - Key k = new Key(method, context); - NodeImpl result = getNode(k); - if (result == null) { - if (maxNumberOfNodes == -1 || getNumberOfNodes() < maxNumberOfNodes) { - result = makeNode(method, context); - registerNode(k, result); - } else { - throw CancelException.make("Too many nodes"); - } - } - return result; - } - - public class ExplicitNode extends NodeImpl { - - /** - * A Mapping from call site program counter (int) -> Object, where Object is a CGNode if we've discovered exactly one target for - * the site, or an IntSet of node numbers if we've discovered more than one target for the site. - */ - protected final SparseVector targets = new SparseVector(); - - private final MutableSharedBitVectorIntSet allTargets = new MutableSharedBitVectorIntSet(); - - /** - * @param method - */ - protected ExplicitNode(IMethod method, Context C) { - super(method, C); - } - - protected Set getPossibleTargets(CallSiteReference site) { - Object result = targets.get(site.getProgramCounter()); - - if (result == null) { - return Collections.emptySet(); - } else if (result instanceof CGNode) { - Set s = Collections.singleton((CGNode) result); - return s; - } else { - IntSet s = (IntSet) result; - HashSet h = HashSetFactory.make(s.size()); - for (IntIterator it = s.intIterator(); it.hasNext();) { - h.add(getCallGraph().getNode(it.next())); - } - return h; - } - } - - protected IntSet getPossibleTargetNumbers(CallSiteReference site) { - Object t = targets.get(site.getProgramCounter()); - - if (t == null) { - return null; - } else if (t instanceof CGNode) { - return SparseIntSet.singleton(getCallGraph().getNumber((CGNode) t)); - } else { - return (IntSet) t; - } - } - - /* - * @see com.ibm.wala.ipa.callgraph.CGNode#getPossibleSites(com.ibm.wala.ipa.callgraph.CGNode) - */ - protected Iterator getPossibleSites(final CGNode to) { - final int n = getCallGraph().getNumber(to); - return new FilterIterator(iterateCallSites(), new Filter() { - public boolean accepts(Object o) { - IntSet s = getPossibleTargetNumbers((CallSiteReference) o); - return s == null ? false : s.contains(n); - } - }); - } - - protected int getNumberOfTargets(CallSiteReference site) { - Object result = targets.get(site.getProgramCounter()); - - if (result == null) { - return 0; - } else if (result instanceof CGNode) { - return 1; - } else { - return ((IntSet) result).size(); - } - } - - @Override - public boolean addTarget(CallSiteReference site, CGNode tNode) { - return addTarget(site.getProgramCounter(), tNode); - } - - protected boolean addTarget(int pc, CGNode tNode) { - allTargets.add(getCallGraph().getNumber(tNode)); - Object S = targets.get(pc); - if (S == null) { - S = tNode; - targets.set(pc, S); - getCallGraph().addEdge(this, tNode); - return true; - } else { - if (S instanceof CGNode) { - if (S.equals(tNode)) { - return false; - } else { - MutableSharedBitVectorIntSet s = new MutableSharedBitVectorIntSet(); - s.add(getCallGraph().getNumber((CGNode) S)); - s.add(getCallGraph().getNumber(tNode)); - getCallGraph().addEdge(this, tNode); - targets.set(pc, s); - return true; - } - } else { - MutableIntSet s = (MutableIntSet) S; - int n = getCallGraph().getNumber(tNode); - if (!s.contains(n)) { - s.add(n); - getCallGraph().addEdge(this, tNode); - return true; - } else { - return false; - } - } - } - } - - /* - * @see com.ibm.wala.ipa.callgraph.impl.BasicCallGraph.NodeImpl#removeTarget(com.ibm.wala.ipa.callgraph.CGNode) - */ - public void removeTarget(CGNode target) { - allTargets.remove(getCallGraph().getNumber(target)); - for (IntIterator it = targets.safeIterateIndices(); it.hasNext();) { - int pc = it.next(); - Object value = targets.get(pc); - if (value instanceof CGNode) { - if (value.equals(target)) { - targets.remove(pc); - } - } else { - MutableIntSet s = (MutableIntSet) value; - int n = getCallGraph().getNumber(target); - if (s.size() > 2) { - s.remove(n); - } else { - assert s.size() == 2; - if (s.contains(n)) { - s.remove(n); - int i = s.intIterator().next(); - targets.set(pc, getCallGraph().getNode(i)); - } - } - } - } - } - - @Override - public boolean equals(Object obj) { - // we can use object equality since these objects are canonical as created - // by the governing ExplicitCallGraph - return this == obj; - } - - @Override - public int hashCode() { - // TODO: cache? - return getMethod().hashCode() * 8681 + getContext().hashCode(); - } - - protected MutableSharedBitVectorIntSet getAllTargetNumbers() { - return allTargets; - } - - public void clearAllTargets() { - targets.clear(); - allTargets.clear(); - } - - public IR getIR() { - return getCallGraph().getInterpreter(this).getIR(this); - } - - public DefUse getDU() { - return getCallGraph().getInterpreter(this).getDU(this); - } - - public ExplicitCallGraph getCallGraph() { - return ExplicitCallGraph.this; - } - - public Iterator iterateCallSites() { - return getCallGraph().getInterpreter(this).iterateCallSites(this); - } - - public Iterator iterateNewSites() { - return getCallGraph().getInterpreter(this).iterateNewSites(this); - } - - public ControlFlowGraph getCFG() { - return getCallGraph().getInterpreter(this).getCFG(this); - } - } - - /* - * @see com.ibm.wala.ipa.callgraph.CallGraph#getClassHierarchy() - */ - public IClassHierarchy getClassHierarchy() { - return cha; - } - - protected class ExplicitEdgeManager implements NumberedEdgeManager { - - final IntFunction toNode = new IntFunction() { - public CGNode apply(int i) { - CGNode result = getNode(i); - // if (Assertions.verifyAssertions && result == null) { - // Assertions.UNREACHABLE("uh oh " + i); - // } - return result; - } - }; - - /** - * for each y, the {x | (x,y) is an edge) - */ - final IBinaryNaturalRelation predecessors = new BasicNaturalRelation(new byte[] { BasicNaturalRelation.SIMPLE_SPACE_STINGY }, - BasicNaturalRelation.SIMPLE); - - public IntSet getSuccNodeNumbers(CGNode node) { - ExplicitNode n = (ExplicitNode) node; - return n.getAllTargetNumbers(); - } - - public IntSet getPredNodeNumbers(CGNode node) { - ExplicitNode n = (ExplicitNode) node; - int y = getNumber(n); - return predecessors.getRelated(y); - } - - public Iterator getPredNodes(CGNode N) { - IntSet s = getPredNodeNumbers(N); - if (s == null) { - return EmptyIterator.instance(); - } else { - return new IntMapIterator(s.intIterator(), toNode); - } - } - - public int getPredNodeCount(CGNode N) { - ExplicitNode n = (ExplicitNode) N; - int y = getNumber(n); - return predecessors.getRelatedCount(y); - } - - public Iterator getSuccNodes(CGNode N) { - ExplicitNode n = (ExplicitNode) N; - return new IntMapIterator(n.getAllTargetNumbers().intIterator(), toNode); - } - - public int getSuccNodeCount(CGNode N) { - ExplicitNode n = (ExplicitNode) N; - return n.getAllTargetNumbers().size(); - } - - public void addEdge(CGNode src, CGNode dst) { - // we assume that this is called from ExplicitNode.addTarget(). - // so we only have to track the inverse edge. - int x = getNumber(src); - int y = getNumber(dst); - predecessors.add(y, x); - } - - public void removeEdge(CGNode src, CGNode dst) { - int x = getNumber(src); - int y = getNumber(dst); - predecessors.remove(y, x); - } - - protected void addEdge(int x, int y) { - // we only have to track the inverse edge. - predecessors.add(y, x); - } - - public void removeAllIncidentEdges(CGNode node) { - Assertions.UNREACHABLE(); - } - - public void removeIncomingEdges(CGNode node) { - Assertions.UNREACHABLE(); - - } - - public void removeOutgoingEdges(CGNode node) { - Assertions.UNREACHABLE(); - - } - - public boolean hasEdge(CGNode src, CGNode dst) { - int x = getNumber(src); - int y = getNumber(dst); - return predecessors.contains(y, x); - } - } - - /** - * @return Returns the edgeManger. - */ - @Override - public NumberedEdgeManager getEdgeManager() { - return edgeManager; - } - - protected ExplicitEdgeManager makeEdgeManger() { - return new ExplicitEdgeManager(); - } - - public int getNumberOfTargets(CGNode node, CallSiteReference site) { - if (!containsNode(node)) { - throw new IllegalArgumentException("node not in callgraph " + node); - } - assert (node instanceof ExplicitNode); - ExplicitNode n = (ExplicitNode) node; - return n.getNumberOfTargets(site); - } - - public Iterator getPossibleSites(CGNode src, CGNode target) { - if (!containsNode(src)) { - throw new IllegalArgumentException("node not in callgraph " + src); - } - if (!containsNode(target)) { - throw new IllegalArgumentException("node not in callgraph " + target); - } - assert (src instanceof ExplicitNode); - ExplicitNode n = (ExplicitNode) src; - return n.getPossibleSites(target); - } - - public Set getPossibleTargets(CGNode node, CallSiteReference site) { - if (!containsNode(node)) { - throw new IllegalArgumentException("node not in callgraph " + node); - } - assert (node instanceof ExplicitNode); - ExplicitNode n = (ExplicitNode) node; - return n.getPossibleTargets(site); - } - - public IntSet getPossibleTargetNumbers(CGNode node, CallSiteReference site) { - if (!containsNode(node)) { - throw new IllegalArgumentException("node not in callgraph " + node); - } - assert (node instanceof ExplicitNode); - ExplicitNode n = (ExplicitNode) node; - return n.getPossibleTargetNumbers(site); - } - - public AnalysisCache getAnalysisCache() { - return cache; - } -} +/******************************************************************************* + * 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.ipa.callgraph.impl; + +import java.util.Collections; +import java.util.HashSet; +import java.util.Iterator; +import java.util.Set; + +import com.ibm.wala.cfg.ControlFlowGraph; +import com.ibm.wala.classLoader.CallSiteReference; +import com.ibm.wala.classLoader.IMethod; +import com.ibm.wala.classLoader.NewSiteReference; +import com.ibm.wala.ipa.callgraph.AnalysisCache; +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.cha.IClassHierarchy; +import com.ibm.wala.shrikeBT.BytecodeConstants; +import com.ibm.wala.ssa.DefUse; +import com.ibm.wala.ssa.IR; +import com.ibm.wala.ssa.ISSABasicBlock; +import com.ibm.wala.ssa.SSAInstruction; +import com.ibm.wala.util.CancelException; +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.HashSetFactory; +import com.ibm.wala.util.collections.IntMapIterator; +import com.ibm.wala.util.collections.SparseVector; +import com.ibm.wala.util.debug.Assertions; +import com.ibm.wala.util.functions.IntFunction; +import com.ibm.wala.util.graph.NumberedEdgeManager; +import com.ibm.wala.util.intset.BasicNaturalRelation; +import com.ibm.wala.util.intset.IBinaryNaturalRelation; +import com.ibm.wala.util.intset.IntIterator; +import com.ibm.wala.util.intset.IntSet; +import com.ibm.wala.util.intset.MutableIntSet; +import com.ibm.wala.util.intset.MutableSharedBitVectorIntSet; +import com.ibm.wala.util.intset.SparseIntSet; + +/** + * A call graph which explicitly holds the target for each call site in each node. + */ +public class ExplicitCallGraph extends BasicCallGraph implements BytecodeConstants { + + protected final IClassHierarchy cha; + + protected final AnalysisOptions options; + + private final AnalysisCache cache; + + private final long maxNumberOfNodes; + + /** + * special object to track call graph edges + */ + private final ExplicitEdgeManager edgeManager = makeEdgeManger(); + + public ExplicitCallGraph(IClassHierarchy cha, AnalysisOptions options, AnalysisCache cache) { + super(); + if (options == null) { + throw new IllegalArgumentException("null options"); + } + if (cache == null) { + throw new IllegalArgumentException("null cache"); + } + this.cha = cha; + this.options = options; + this.cache = cache; + this.maxNumberOfNodes = options.getMaxNumberOfNodes(); + + } + + /** + * subclasses may wish to override! + */ + protected ExplicitNode makeNode(IMethod method, Context context) { + return new ExplicitNode(method, context); + } + + /** + * subclasses may wish to override! + * + * @throws CancelException + */ + @Override + protected CGNode makeFakeRootNode() throws CancelException { + return findOrCreateNode(new FakeRootMethod(cha, options, cache), Everywhere.EVERYWHERE); + } + + /** + * subclasses may wish to override! + * + * @throws CancelException + */ + @Override + protected CGNode makeFakeWorldClinitNode() throws CancelException { + return findOrCreateNode(new FakeWorldClinitMethod(cha, options, cache), Everywhere.EVERYWHERE); + } + + /** + */ + @Override + public CGNode findOrCreateNode(IMethod method, Context context) throws CancelException { + if (method == null) { + throw new IllegalArgumentException("null method"); + } + if (context == null) { + throw new IllegalArgumentException("null context"); + } + Key k = new Key(method, context); + NodeImpl result = getNode(k); + if (result == null) { + if (maxNumberOfNodes == -1 || getNumberOfNodes() < maxNumberOfNodes) { + result = makeNode(method, context); + registerNode(k, result); + } else { + throw CancelException.make("Too many nodes"); + } + } + return result; + } + + public class ExplicitNode extends NodeImpl { + + /** + * A Mapping from call site program counter (int) -> Object, where Object is a CGNode if we've discovered exactly one target for + * the site, or an IntSet of node numbers if we've discovered more than one target for the site. + */ + protected final SparseVector targets = new SparseVector(); + + private final MutableSharedBitVectorIntSet allTargets = new MutableSharedBitVectorIntSet(); + + /** + * @param method + */ + protected ExplicitNode(IMethod method, Context C) { + super(method, C); + } + + protected Set getPossibleTargets(CallSiteReference site) { + Object result = targets.get(site.getProgramCounter()); + + if (result == null) { + return Collections.emptySet(); + } else if (result instanceof CGNode) { + Set s = Collections.singleton((CGNode) result); + return s; + } else { + IntSet s = (IntSet) result; + HashSet h = HashSetFactory.make(s.size()); + for (IntIterator it = s.intIterator(); it.hasNext();) { + h.add(getCallGraph().getNode(it.next())); + } + return h; + } + } + + protected IntSet getPossibleTargetNumbers(CallSiteReference site) { + Object t = targets.get(site.getProgramCounter()); + + if (t == null) { + return null; + } else if (t instanceof CGNode) { + return SparseIntSet.singleton(getCallGraph().getNumber((CGNode) t)); + } else { + return (IntSet) t; + } + } + + /* + * @see com.ibm.wala.ipa.callgraph.CGNode#getPossibleSites(com.ibm.wala.ipa.callgraph.CGNode) + */ + protected Iterator getPossibleSites(final CGNode to) { + final int n = getCallGraph().getNumber(to); + return new FilterIterator(iterateCallSites(), new Filter() { + public boolean accepts(Object o) { + IntSet s = getPossibleTargetNumbers((CallSiteReference) o); + return s == null ? false : s.contains(n); + } + }); + } + + protected int getNumberOfTargets(CallSiteReference site) { + Object result = targets.get(site.getProgramCounter()); + + if (result == null) { + return 0; + } else if (result instanceof CGNode) { + return 1; + } else { + return ((IntSet) result).size(); + } + } + + @Override + public boolean addTarget(CallSiteReference site, CGNode tNode) { + return addTarget(site.getProgramCounter(), tNode); + } + + protected boolean addTarget(int pc, CGNode tNode) { + allTargets.add(getCallGraph().getNumber(tNode)); + Object S = targets.get(pc); + if (S == null) { + S = tNode; + targets.set(pc, S); + getCallGraph().addEdge(this, tNode); + return true; + } else { + if (S instanceof CGNode) { + if (S.equals(tNode)) { + return false; + } else { + MutableSharedBitVectorIntSet s = new MutableSharedBitVectorIntSet(); + s.add(getCallGraph().getNumber((CGNode) S)); + s.add(getCallGraph().getNumber(tNode)); + getCallGraph().addEdge(this, tNode); + targets.set(pc, s); + return true; + } + } else { + MutableIntSet s = (MutableIntSet) S; + int n = getCallGraph().getNumber(tNode); + if (!s.contains(n)) { + s.add(n); + getCallGraph().addEdge(this, tNode); + return true; + } else { + return false; + } + } + } + } + + /* + * @see com.ibm.wala.ipa.callgraph.impl.BasicCallGraph.NodeImpl#removeTarget(com.ibm.wala.ipa.callgraph.CGNode) + */ + public void removeTarget(CGNode target) { + allTargets.remove(getCallGraph().getNumber(target)); + for (IntIterator it = targets.safeIterateIndices(); it.hasNext();) { + int pc = it.next(); + Object value = targets.get(pc); + if (value instanceof CGNode) { + if (value.equals(target)) { + targets.remove(pc); + } + } else { + MutableIntSet s = (MutableIntSet) value; + int n = getCallGraph().getNumber(target); + if (s.size() > 2) { + s.remove(n); + } else { + assert s.size() == 2; + if (s.contains(n)) { + s.remove(n); + int i = s.intIterator().next(); + targets.set(pc, getCallGraph().getNode(i)); + } + } + } + } + } + + @Override + public boolean equals(Object obj) { + // we can use object equality since these objects are canonical as created + // by the governing ExplicitCallGraph + return this == obj; + } + + @Override + public int hashCode() { + // TODO: cache? + return getMethod().hashCode() * 8681 + getContext().hashCode(); + } + + protected MutableSharedBitVectorIntSet getAllTargetNumbers() { + return allTargets; + } + + public void clearAllTargets() { + targets.clear(); + allTargets.clear(); + } + + public IR getIR() { + return getCallGraph().getInterpreter(this).getIR(this); + } + + public DefUse getDU() { + return getCallGraph().getInterpreter(this).getDU(this); + } + + public ExplicitCallGraph getCallGraph() { + return ExplicitCallGraph.this; + } + + public Iterator iterateCallSites() { + return getCallGraph().getInterpreter(this).iterateCallSites(this); + } + + public Iterator iterateNewSites() { + return getCallGraph().getInterpreter(this).iterateNewSites(this); + } + + public ControlFlowGraph getCFG() { + return getCallGraph().getInterpreter(this).getCFG(this); + } + } + + /* + * @see com.ibm.wala.ipa.callgraph.CallGraph#getClassHierarchy() + */ + public IClassHierarchy getClassHierarchy() { + return cha; + } + + protected class ExplicitEdgeManager implements NumberedEdgeManager { + + final IntFunction toNode = new IntFunction() { + public CGNode apply(int i) { + CGNode result = getNode(i); + // if (Assertions.verifyAssertions && result == null) { + // Assertions.UNREACHABLE("uh oh " + i); + // } + return result; + } + }; + + /** + * for each y, the {x | (x,y) is an edge) + */ + final IBinaryNaturalRelation predecessors = new BasicNaturalRelation(new byte[] { BasicNaturalRelation.SIMPLE_SPACE_STINGY }, + BasicNaturalRelation.SIMPLE); + + public IntSet getSuccNodeNumbers(CGNode node) { + ExplicitNode n = (ExplicitNode) node; + return n.getAllTargetNumbers(); + } + + public IntSet getPredNodeNumbers(CGNode node) { + ExplicitNode n = (ExplicitNode) node; + int y = getNumber(n); + return predecessors.getRelated(y); + } + + public Iterator getPredNodes(CGNode N) { + IntSet s = getPredNodeNumbers(N); + if (s == null) { + return EmptyIterator.instance(); + } else { + return new IntMapIterator(s.intIterator(), toNode); + } + } + + public int getPredNodeCount(CGNode N) { + ExplicitNode n = (ExplicitNode) N; + int y = getNumber(n); + return predecessors.getRelatedCount(y); + } + + public Iterator getSuccNodes(CGNode N) { + ExplicitNode n = (ExplicitNode) N; + return new IntMapIterator(n.getAllTargetNumbers().intIterator(), toNode); + } + + public int getSuccNodeCount(CGNode N) { + ExplicitNode n = (ExplicitNode) N; + return n.getAllTargetNumbers().size(); + } + + public void addEdge(CGNode src, CGNode dst) { + // we assume that this is called from ExplicitNode.addTarget(). + // so we only have to track the inverse edge. + int x = getNumber(src); + int y = getNumber(dst); + predecessors.add(y, x); + } + + public void removeEdge(CGNode src, CGNode dst) { + int x = getNumber(src); + int y = getNumber(dst); + predecessors.remove(y, x); + } + + protected void addEdge(int x, int y) { + // we only have to track the inverse edge. + predecessors.add(y, x); + } + + public void removeAllIncidentEdges(CGNode node) { + Assertions.UNREACHABLE(); + } + + public void removeIncomingEdges(CGNode node) { + Assertions.UNREACHABLE(); + + } + + public void removeOutgoingEdges(CGNode node) { + Assertions.UNREACHABLE(); + + } + + public boolean hasEdge(CGNode src, CGNode dst) { + int x = getNumber(src); + int y = getNumber(dst); + return predecessors.contains(y, x); + } + } + + /** + * @return Returns the edgeManger. + */ + @Override + public NumberedEdgeManager getEdgeManager() { + return edgeManager; + } + + protected ExplicitEdgeManager makeEdgeManger() { + return new ExplicitEdgeManager(); + } + + public int getNumberOfTargets(CGNode node, CallSiteReference site) { + if (!containsNode(node)) { + throw new IllegalArgumentException("node not in callgraph " + node); + } + assert (node instanceof ExplicitNode); + ExplicitNode n = (ExplicitNode) node; + return n.getNumberOfTargets(site); + } + + public Iterator getPossibleSites(CGNode src, CGNode target) { + if (!containsNode(src)) { + throw new IllegalArgumentException("node not in callgraph " + src); + } + if (!containsNode(target)) { + throw new IllegalArgumentException("node not in callgraph " + target); + } + assert (src instanceof ExplicitNode); + ExplicitNode n = (ExplicitNode) src; + return n.getPossibleSites(target); + } + + public Set getPossibleTargets(CGNode node, CallSiteReference site) { + if (!containsNode(node)) { + throw new IllegalArgumentException("node not in callgraph " + node); + } + assert (node instanceof ExplicitNode); + ExplicitNode n = (ExplicitNode) node; + return n.getPossibleTargets(site); + } + + public IntSet getPossibleTargetNumbers(CGNode node, CallSiteReference site) { + if (!containsNode(node)) { + throw new IllegalArgumentException("node not in callgraph " + node); + } + assert (node instanceof ExplicitNode); + ExplicitNode n = (ExplicitNode) node; + return n.getPossibleTargetNumbers(site); + } + + public AnalysisCache getAnalysisCache() { + return cache; + } +} diff --git a/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/impl/FakeRootClass.java b/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/impl/FakeRootClass.java index 58e80f5bc..2d14a530d 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/impl/FakeRootClass.java +++ b/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/impl/FakeRootClass.java @@ -1,248 +1,248 @@ -/******************************************************************************* - * 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.ipa.callgraph.impl; - -import java.io.InputStream; -import java.util.Collection; -import java.util.Collections; -import java.util.Map; -import java.util.Set; - -import com.ibm.wala.classLoader.IClass; -import com.ibm.wala.classLoader.IField; -import com.ibm.wala.classLoader.IMethod; -import com.ibm.wala.classLoader.SyntheticClass; -import com.ibm.wala.ipa.cha.IClassHierarchy; -import com.ibm.wala.types.ClassLoaderReference; -import com.ibm.wala.types.FieldReference; -import com.ibm.wala.types.Selector; -import com.ibm.wala.types.TypeName; -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.UnimplementedError; -import com.ibm.wala.util.strings.Atom; - -/** - * A synthetic class for the fake root method - */ -public class FakeRootClass extends SyntheticClass { - public static final TypeReference FAKE_ROOT_CLASS = TypeReference.findOrCreate(ClassLoaderReference.Primordial, TypeName - .string2TypeName("Lcom/ibm/wala/FakeRootClass")); - - private Map fakeRootStaticFields = null; - - private Set methods = HashSetFactory.make(); - - public FakeRootClass(IClassHierarchy cha) { - this(FAKE_ROOT_CLASS, cha); - } - - public FakeRootClass(TypeReference typeRef, IClassHierarchy cha) { - super(typeRef, cha); - } - - public void addMethod(IMethod m) { - methods.add(m); - } - - public void addStaticField(final Atom name, final TypeReference fieldType) { - if (fakeRootStaticFields == null) { - fakeRootStaticFields = HashMapFactory.make(2); - } - - fakeRootStaticFields.put(name, new IField() { - public IClassHierarchy getClassHierarchy() { - return FakeRootClass.this.getClassHierarchy(); - } - - public TypeReference getFieldTypeReference() { - return fieldType; - } - - public IClass getDeclaringClass() { - return FakeRootClass.this; - } - - public Atom getName() { - return name; - } - - public boolean isStatic() { - return true; - } - - public boolean isVolatile() { - return false; - } - - public FieldReference getReference() { - return FieldReference.findOrCreate(FAKE_ROOT_CLASS, name, fieldType); - } - - public boolean isFinal() { - return false; - } - - public boolean isPrivate() { - return true; - } - - public boolean isProtected() { - return false; - } - - public boolean isPublic() { - return false; - } - }); - } - - /* - * @see com.ibm.wala.classLoader.IClass#getModifiers() - */ - public int getModifiers() throws UnsupportedOperationException { - throw new UnsupportedOperationException(); - } - - /* - * @see com.ibm.wala.classLoader.IClass#getSuperclass() - */ - public IClass getSuperclass() throws UnsupportedOperationException { - return getClassHierarchy().getRootClass(); - } - - /* - * @see com.ibm.wala.classLoader.IClass#getAllImplementedInterfaces() - */ - public Collection getAllImplementedInterfaces() throws UnsupportedOperationException { - return Collections.emptySet(); - } - - /* - * @see com.ibm.wala.classLoader.IClass#getAllAncestorInterfaces() - */ - public Collection getAllAncestorInterfaces() throws UnsupportedOperationException { - throw new UnsupportedOperationException(); - } - - /* - * @see com.ibm.wala.classLoader.IClass#getMethod(com.ibm.wala.classLoader.Selector) - */ - public IMethod getMethod(Selector selector) throws UnsupportedOperationException { - for (IMethod m : methods) { - if (m.getSelector().equals(selector)) { - return m; - } - } - return null; - } - - /* - * @see com.ibm.wala.classLoader.IClass#getMethod(com.ibm.wala.classLoader.Selector) - */ - public IField getField(Atom name) { - if (fakeRootStaticFields != null) { - return fakeRootStaticFields.get(name); - } else { - return null; - } - } - - /* - * @see com.ibm.wala.classLoader.IClass#getClassInitializer() - */ - public IMethod getClassInitializer() throws UnimplementedError { - Assertions.UNREACHABLE(); - return null; - } - - /* - * @see com.ibm.wala.classLoader.IClass#getDeclaredMethods() - */ - public Collection getDeclaredMethods() throws UnsupportedOperationException { - return Collections.unmodifiableCollection(methods); - } - - /* - * @see com.ibm.wala.classLoader.IClass#getDeclaredInstanceFields() - */ - public Collection getDeclaredInstanceFields() throws UnsupportedOperationException { - return Collections.emptySet(); - } - - /* - * @see com.ibm.wala.classLoader.IClass#getDeclaredStaticFields() - */ - public Collection getDeclaredStaticFields() { - if (fakeRootStaticFields != null) { - return fakeRootStaticFields.values(); - } else { - return Collections.emptySet(); - } - } - - /* - * @see com.ibm.wala.classLoader.IClass#isReferenceType() - */ - public boolean isReferenceType() { - return getReference().isReferenceType(); - } - - /* - * @see com.ibm.wala.classLoader.IClass#getDirectInterfaces() - */ - public Collection getDirectInterfaces() throws UnsupportedOperationException { - throw new UnsupportedOperationException(); - } - - /* - * @see com.ibm.wala.classLoader.IClass#getAllInstanceFields() - */ - public Collection getAllInstanceFields() { - return Collections.emptySet(); - } - - /* - * @see com.ibm.wala.classLoader.IClass#getAllStaticFields() - */ - public Collection getAllStaticFields() { - return getDeclaredStaticFields(); - } - - /* - * @see com.ibm.wala.classLoader.IClass#getAllMethods() - */ - public Collection getAllMethods() { - throw new UnsupportedOperationException(); - } - - /* - * @see com.ibm.wala.classLoader.IClass#getAllFields() - */ - public Collection getAllFields() { - return getDeclaredStaticFields(); - } - - public boolean isPublic() { - return false; - } - - public boolean isPrivate() { - return false; - } - - @Override - public InputStream getSource() { - return null; - } -} +/******************************************************************************* + * 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.ipa.callgraph.impl; + +import java.io.InputStream; +import java.util.Collection; +import java.util.Collections; +import java.util.Map; +import java.util.Set; + +import com.ibm.wala.classLoader.IClass; +import com.ibm.wala.classLoader.IField; +import com.ibm.wala.classLoader.IMethod; +import com.ibm.wala.classLoader.SyntheticClass; +import com.ibm.wala.ipa.cha.IClassHierarchy; +import com.ibm.wala.types.ClassLoaderReference; +import com.ibm.wala.types.FieldReference; +import com.ibm.wala.types.Selector; +import com.ibm.wala.types.TypeName; +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.UnimplementedError; +import com.ibm.wala.util.strings.Atom; + +/** + * A synthetic class for the fake root method + */ +public class FakeRootClass extends SyntheticClass { + public static final TypeReference FAKE_ROOT_CLASS = TypeReference.findOrCreate(ClassLoaderReference.Primordial, TypeName + .string2TypeName("Lcom/ibm/wala/FakeRootClass")); + + private Map fakeRootStaticFields = null; + + private Set methods = HashSetFactory.make(); + + public FakeRootClass(IClassHierarchy cha) { + this(FAKE_ROOT_CLASS, cha); + } + + public FakeRootClass(TypeReference typeRef, IClassHierarchy cha) { + super(typeRef, cha); + } + + public void addMethod(IMethod m) { + methods.add(m); + } + + public void addStaticField(final Atom name, final TypeReference fieldType) { + if (fakeRootStaticFields == null) { + fakeRootStaticFields = HashMapFactory.make(2); + } + + fakeRootStaticFields.put(name, new IField() { + public IClassHierarchy getClassHierarchy() { + return FakeRootClass.this.getClassHierarchy(); + } + + public TypeReference getFieldTypeReference() { + return fieldType; + } + + public IClass getDeclaringClass() { + return FakeRootClass.this; + } + + public Atom getName() { + return name; + } + + public boolean isStatic() { + return true; + } + + public boolean isVolatile() { + return false; + } + + public FieldReference getReference() { + return FieldReference.findOrCreate(FAKE_ROOT_CLASS, name, fieldType); + } + + public boolean isFinal() { + return false; + } + + public boolean isPrivate() { + return true; + } + + public boolean isProtected() { + return false; + } + + public boolean isPublic() { + return false; + } + }); + } + + /* + * @see com.ibm.wala.classLoader.IClass#getModifiers() + */ + public int getModifiers() throws UnsupportedOperationException { + throw new UnsupportedOperationException(); + } + + /* + * @see com.ibm.wala.classLoader.IClass#getSuperclass() + */ + public IClass getSuperclass() throws UnsupportedOperationException { + return getClassHierarchy().getRootClass(); + } + + /* + * @see com.ibm.wala.classLoader.IClass#getAllImplementedInterfaces() + */ + public Collection getAllImplementedInterfaces() throws UnsupportedOperationException { + return Collections.emptySet(); + } + + /* + * @see com.ibm.wala.classLoader.IClass#getAllAncestorInterfaces() + */ + public Collection getAllAncestorInterfaces() throws UnsupportedOperationException { + throw new UnsupportedOperationException(); + } + + /* + * @see com.ibm.wala.classLoader.IClass#getMethod(com.ibm.wala.classLoader.Selector) + */ + public IMethod getMethod(Selector selector) throws UnsupportedOperationException { + for (IMethod m : methods) { + if (m.getSelector().equals(selector)) { + return m; + } + } + return null; + } + + /* + * @see com.ibm.wala.classLoader.IClass#getMethod(com.ibm.wala.classLoader.Selector) + */ + public IField getField(Atom name) { + if (fakeRootStaticFields != null) { + return fakeRootStaticFields.get(name); + } else { + return null; + } + } + + /* + * @see com.ibm.wala.classLoader.IClass#getClassInitializer() + */ + public IMethod getClassInitializer() throws UnimplementedError { + Assertions.UNREACHABLE(); + return null; + } + + /* + * @see com.ibm.wala.classLoader.IClass#getDeclaredMethods() + */ + public Collection getDeclaredMethods() throws UnsupportedOperationException { + return Collections.unmodifiableCollection(methods); + } + + /* + * @see com.ibm.wala.classLoader.IClass#getDeclaredInstanceFields() + */ + public Collection getDeclaredInstanceFields() throws UnsupportedOperationException { + return Collections.emptySet(); + } + + /* + * @see com.ibm.wala.classLoader.IClass#getDeclaredStaticFields() + */ + public Collection getDeclaredStaticFields() { + if (fakeRootStaticFields != null) { + return fakeRootStaticFields.values(); + } else { + return Collections.emptySet(); + } + } + + /* + * @see com.ibm.wala.classLoader.IClass#isReferenceType() + */ + public boolean isReferenceType() { + return getReference().isReferenceType(); + } + + /* + * @see com.ibm.wala.classLoader.IClass#getDirectInterfaces() + */ + public Collection getDirectInterfaces() throws UnsupportedOperationException { + throw new UnsupportedOperationException(); + } + + /* + * @see com.ibm.wala.classLoader.IClass#getAllInstanceFields() + */ + public Collection getAllInstanceFields() { + return Collections.emptySet(); + } + + /* + * @see com.ibm.wala.classLoader.IClass#getAllStaticFields() + */ + public Collection getAllStaticFields() { + return getDeclaredStaticFields(); + } + + /* + * @see com.ibm.wala.classLoader.IClass#getAllMethods() + */ + public Collection getAllMethods() { + throw new UnsupportedOperationException(); + } + + /* + * @see com.ibm.wala.classLoader.IClass#getAllFields() + */ + public Collection getAllFields() { + return getDeclaredStaticFields(); + } + + public boolean isPublic() { + return false; + } + + public boolean isPrivate() { + return false; + } + + @Override + public InputStream getSource() { + return null; + } +} diff --git a/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/impl/FakeRootMethod.java b/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/impl/FakeRootMethod.java index 933d91f14..7d069beea 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/impl/FakeRootMethod.java +++ b/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/impl/FakeRootMethod.java @@ -1,67 +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.ipa.callgraph.impl; - -import com.ibm.wala.cfg.IBasicBlock; -import com.ibm.wala.classLoader.IMethod; -import com.ibm.wala.ipa.callgraph.AnalysisCache; -import com.ibm.wala.ipa.callgraph.AnalysisOptions; -import com.ibm.wala.ipa.cha.IClassHierarchy; -import com.ibm.wala.types.Descriptor; -import com.ibm.wala.types.MemberReference; -import com.ibm.wala.types.MethodReference; -import com.ibm.wala.types.TypeName; -import com.ibm.wala.types.TypeReference; -import com.ibm.wala.util.strings.Atom; - -/** - * A synthetic method that models the fake root node. - */ -public class FakeRootMethod extends AbstractRootMethod { - - public static final Atom name = Atom.findOrCreateAsciiAtom("fakeRootMethod"); - - public static final Descriptor descr = Descriptor.findOrCreate(new TypeName[0], TypeReference.VoidName); - - public static final MethodReference rootMethod = MethodReference.findOrCreate(FakeRootClass.FAKE_ROOT_CLASS, name, descr); - - public FakeRootMethod(final IClassHierarchy cha, AnalysisOptions options, AnalysisCache cache) { - super(rootMethod, cha, options, cache); - } - - /** - * @return true iff m is the fake root method. - * @throws IllegalArgumentException if m is null - */ - public static boolean isFakeRootMethod(MemberReference m) { - if (m == null) { - throw new IllegalArgumentException("m is null"); - } - return m.equals(rootMethod); - } - - /** - * @return true iff block is a basic block in the fake root method - * @throws IllegalArgumentException if block is null - */ - public static boolean isFromFakeRoot(IBasicBlock block) { - if (block == null) { - throw new IllegalArgumentException("block is null"); - } - IMethod m = block.getMethod(); - return FakeRootMethod.isFakeRootMethod(m.getReference()); - } - - public static MethodReference getRootMethod() { - return rootMethod; - } - -} +/******************************************************************************* + * 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.ipa.callgraph.impl; + +import com.ibm.wala.cfg.IBasicBlock; +import com.ibm.wala.classLoader.IMethod; +import com.ibm.wala.ipa.callgraph.AnalysisCache; +import com.ibm.wala.ipa.callgraph.AnalysisOptions; +import com.ibm.wala.ipa.cha.IClassHierarchy; +import com.ibm.wala.types.Descriptor; +import com.ibm.wala.types.MemberReference; +import com.ibm.wala.types.MethodReference; +import com.ibm.wala.types.TypeName; +import com.ibm.wala.types.TypeReference; +import com.ibm.wala.util.strings.Atom; + +/** + * A synthetic method that models the fake root node. + */ +public class FakeRootMethod extends AbstractRootMethod { + + public static final Atom name = Atom.findOrCreateAsciiAtom("fakeRootMethod"); + + public static final Descriptor descr = Descriptor.findOrCreate(new TypeName[0], TypeReference.VoidName); + + public static final MethodReference rootMethod = MethodReference.findOrCreate(FakeRootClass.FAKE_ROOT_CLASS, name, descr); + + public FakeRootMethod(final IClassHierarchy cha, AnalysisOptions options, AnalysisCache cache) { + super(rootMethod, cha, options, cache); + } + + /** + * @return true iff m is the fake root method. + * @throws IllegalArgumentException if m is null + */ + public static boolean isFakeRootMethod(MemberReference m) { + if (m == null) { + throw new IllegalArgumentException("m is null"); + } + return m.equals(rootMethod); + } + + /** + * @return true iff block is a basic block in the fake root method + * @throws IllegalArgumentException if block is null + */ + public static boolean isFromFakeRoot(IBasicBlock block) { + if (block == null) { + throw new IllegalArgumentException("block is null"); + } + IMethod m = block.getMethod(); + return FakeRootMethod.isFakeRootMethod(m.getReference()); + } + + public static MethodReference getRootMethod() { + return rootMethod; + } + +} diff --git a/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/impl/FakeWorldClinitMethod.java b/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/impl/FakeWorldClinitMethod.java index 223eb2c1d..5afe40180 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/impl/FakeWorldClinitMethod.java +++ b/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/impl/FakeWorldClinitMethod.java @@ -1,35 +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.ipa.callgraph.impl; - -import com.ibm.wala.ipa.callgraph.AnalysisCache; -import com.ibm.wala.ipa.callgraph.AnalysisOptions; -import com.ibm.wala.ipa.cha.IClassHierarchy; -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.strings.Atom; - -/** - * A synthetic method that calls all class initializers - */ -public class FakeWorldClinitMethod extends AbstractRootMethod { - - private static final Atom name = Atom.findOrCreateAsciiAtom("fakeWorldClinit"); - - private static final MethodReference worldClinitMethod = MethodReference.findOrCreate(FakeRootClass.FAKE_ROOT_CLASS, name, Descriptor - .findOrCreate(new TypeName[0], TypeReference.VoidName)); - - public FakeWorldClinitMethod(final IClassHierarchy cha, AnalysisOptions options, AnalysisCache cache) { - super(worldClinitMethod, cha, options, cache); - } -} +/******************************************************************************* + * 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.ipa.callgraph.impl; + +import com.ibm.wala.ipa.callgraph.AnalysisCache; +import com.ibm.wala.ipa.callgraph.AnalysisOptions; +import com.ibm.wala.ipa.cha.IClassHierarchy; +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.strings.Atom; + +/** + * A synthetic method that calls all class initializers + */ +public class FakeWorldClinitMethod extends AbstractRootMethod { + + private static final Atom name = Atom.findOrCreateAsciiAtom("fakeWorldClinit"); + + private static final MethodReference worldClinitMethod = MethodReference.findOrCreate(FakeRootClass.FAKE_ROOT_CLASS, name, Descriptor + .findOrCreate(new TypeName[0], TypeReference.VoidName)); + + public FakeWorldClinitMethod(final IClassHierarchy cha, AnalysisOptions options, AnalysisCache cache) { + super(worldClinitMethod, cha, options, cache); + } +} diff --git a/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/impl/PartialCallGraph.java b/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/impl/PartialCallGraph.java index 3c4c29b5e..4895c03c2 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/impl/PartialCallGraph.java +++ b/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/impl/PartialCallGraph.java @@ -1,182 +1,182 @@ -/******************************************************************************* - * Copyright (c) 2002 - 2006 IBM Corporation. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * IBM Corporation - initial API and implementation - *******************************************************************************/ -package com.ibm.wala.ipa.callgraph.impl; - -import java.util.Collection; -import java.util.Iterator; -import java.util.Set; - -import com.ibm.wala.classLoader.CallSiteReference; -import com.ibm.wala.classLoader.IMethod; -import com.ibm.wala.ipa.callgraph.CGNode; -import com.ibm.wala.ipa.callgraph.CallGraph; -import com.ibm.wala.ipa.callgraph.Context; -import com.ibm.wala.ipa.cha.IClassHierarchy; -import com.ibm.wala.types.MethodReference; -import com.ibm.wala.util.collections.Filter; -import com.ibm.wala.util.collections.FilterIterator; -import com.ibm.wala.util.collections.HashSetFactory; -import com.ibm.wala.util.graph.Graph; -import com.ibm.wala.util.graph.GraphSlicer; -import com.ibm.wala.util.graph.impl.DelegatingGraph; -import com.ibm.wala.util.graph.traverse.DFS; -import com.ibm.wala.util.intset.IntSet; -import com.ibm.wala.util.intset.IntSetUtil; -import com.ibm.wala.util.intset.MutableIntSet; - -/** - * a view of a portion of a call graph. - */ -public class PartialCallGraph extends DelegatingGraph implements CallGraph { - - protected final CallGraph cg; - - protected final Collection partialRoots; - - protected PartialCallGraph(CallGraph cg, Collection partialRoots, Graph partialGraph) { - super(partialGraph); - this.cg = cg; - this.partialRoots = partialRoots; - } - - /** - * @param cg the original call graph - * @param partialRoots roots of the new, partial graph - * @param nodes set of nodes that will be included in the new, partial call graph - */ - public static PartialCallGraph make(final CallGraph cg, final Collection partialRoots, final Collection nodes) { - Graph partialGraph = GraphSlicer.prune(cg, new Filter() { - public boolean accepts(CGNode o) { - return nodes.contains(o); - } - }); - - return new PartialCallGraph(cg, partialRoots, partialGraph); - } - - /** - * @param cg the original call graph - * @param partialRoots roots of the new, partial graph - * the result contains only nodes reachable from the partialRoots in the original call graph. - */ - public static PartialCallGraph make(CallGraph cg, Collection partialRoots) { - final Set nodes = DFS.getReachableNodes(cg, partialRoots); - Graph partialGraph = GraphSlicer.prune(cg, new Filter() { - public boolean accepts(CGNode o) { - return nodes.contains(o); - } - }); - - return new PartialCallGraph(cg, partialRoots, partialGraph); - } - - public CGNode getFakeRootNode() throws UnsupportedOperationException { - throw new UnsupportedOperationException(); - } - - public Collection getEntrypointNodes() { - return partialRoots; - } - - public CGNode getNode(IMethod method, Context C) { - CGNode x = cg.getNode(method, C); - if (x == null) { - return null; - } - return (containsNode(x) ? x : null); - } - - public Set getNodes(MethodReference m) { - Set result = HashSetFactory.make(); - for (Iterator xs = cg.getNodes(m).iterator(); xs.hasNext();) { - CGNode x = (CGNode) xs.next(); - if (containsNode(x)) { - result.add(x); - } - } - - return result; - } - - public IClassHierarchy getClassHierarchy() { - return cg.getClassHierarchy(); - } - - public Iterator iterateNodes(IntSet nodes) { - return new FilterIterator(cg.iterateNodes(nodes), new Filter() { - public boolean accepts(Object o) { - return containsNode((CGNode) o); - } - }); - } - - public int getMaxNumber() { - return cg.getMaxNumber(); - } - - public CGNode getNode(int index) { - CGNode n = cg.getNode(index); - return (containsNode(n) ? n : null); - } - - public int getNumber(CGNode n) { - return (containsNode(n) ? cg.getNumber(n) : -1); - } - - public IntSet getSuccNodeNumbers(CGNode node) { - assert containsNode(node); - MutableIntSet x = IntSetUtil.make(); - for (Iterator ns = getSuccNodes(node); ns.hasNext();) { - CGNode succ = (CGNode) ns.next(); - if (containsNode(succ)) { - x.add(getNumber(succ)); - } - } - - return x; - } - - public IntSet getPredNodeNumbers(CGNode node) { - assert containsNode(node); - MutableIntSet x = IntSetUtil.make(); - for (Iterator ns = getPredNodes(node); ns.hasNext();) { - CGNode pred = (CGNode) ns.next(); - if (containsNode(pred)) { - x.add(getNumber(pred)); - } - } - - return x; - } - - public int getNumberOfTargets(CGNode node, CallSiteReference site) { - return (containsNode(node) ? getPossibleTargets(node, site).size() : -1); - } - - public Iterator getPossibleSites(CGNode src, CGNode target) { - return ((containsNode(src) && containsNode(target)) ? cg.getPossibleSites(src, target) : null); - } - - public Set getPossibleTargets(CGNode node, CallSiteReference site) { - if (!containsNode(node)) { - return null; - } - Set result = HashSetFactory.make(); - for (Iterator ns = cg.getPossibleTargets(node, site).iterator(); ns.hasNext();) { - CGNode target = (CGNode) ns.next(); - if (containsNode(target)) { - result.add(target); - } - } - - return result; - } -} +/******************************************************************************* + * 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.ipa.callgraph.impl; + +import java.util.Collection; +import java.util.Iterator; +import java.util.Set; + +import com.ibm.wala.classLoader.CallSiteReference; +import com.ibm.wala.classLoader.IMethod; +import com.ibm.wala.ipa.callgraph.CGNode; +import com.ibm.wala.ipa.callgraph.CallGraph; +import com.ibm.wala.ipa.callgraph.Context; +import com.ibm.wala.ipa.cha.IClassHierarchy; +import com.ibm.wala.types.MethodReference; +import com.ibm.wala.util.collections.Filter; +import com.ibm.wala.util.collections.FilterIterator; +import com.ibm.wala.util.collections.HashSetFactory; +import com.ibm.wala.util.graph.Graph; +import com.ibm.wala.util.graph.GraphSlicer; +import com.ibm.wala.util.graph.impl.DelegatingGraph; +import com.ibm.wala.util.graph.traverse.DFS; +import com.ibm.wala.util.intset.IntSet; +import com.ibm.wala.util.intset.IntSetUtil; +import com.ibm.wala.util.intset.MutableIntSet; + +/** + * a view of a portion of a call graph. + */ +public class PartialCallGraph extends DelegatingGraph implements CallGraph { + + protected final CallGraph cg; + + protected final Collection partialRoots; + + protected PartialCallGraph(CallGraph cg, Collection partialRoots, Graph partialGraph) { + super(partialGraph); + this.cg = cg; + this.partialRoots = partialRoots; + } + + /** + * @param cg the original call graph + * @param partialRoots roots of the new, partial graph + * @param nodes set of nodes that will be included in the new, partial call graph + */ + public static PartialCallGraph make(final CallGraph cg, final Collection partialRoots, final Collection nodes) { + Graph partialGraph = GraphSlicer.prune(cg, new Filter() { + public boolean accepts(CGNode o) { + return nodes.contains(o); + } + }); + + return new PartialCallGraph(cg, partialRoots, partialGraph); + } + + /** + * @param cg the original call graph + * @param partialRoots roots of the new, partial graph + * the result contains only nodes reachable from the partialRoots in the original call graph. + */ + public static PartialCallGraph make(CallGraph cg, Collection partialRoots) { + final Set nodes = DFS.getReachableNodes(cg, partialRoots); + Graph partialGraph = GraphSlicer.prune(cg, new Filter() { + public boolean accepts(CGNode o) { + return nodes.contains(o); + } + }); + + return new PartialCallGraph(cg, partialRoots, partialGraph); + } + + public CGNode getFakeRootNode() throws UnsupportedOperationException { + throw new UnsupportedOperationException(); + } + + public Collection getEntrypointNodes() { + return partialRoots; + } + + public CGNode getNode(IMethod method, Context C) { + CGNode x = cg.getNode(method, C); + if (x == null) { + return null; + } + return (containsNode(x) ? x : null); + } + + public Set getNodes(MethodReference m) { + Set result = HashSetFactory.make(); + for (Iterator xs = cg.getNodes(m).iterator(); xs.hasNext();) { + CGNode x = (CGNode) xs.next(); + if (containsNode(x)) { + result.add(x); + } + } + + return result; + } + + public IClassHierarchy getClassHierarchy() { + return cg.getClassHierarchy(); + } + + public Iterator iterateNodes(IntSet nodes) { + return new FilterIterator(cg.iterateNodes(nodes), new Filter() { + public boolean accepts(Object o) { + return containsNode((CGNode) o); + } + }); + } + + public int getMaxNumber() { + return cg.getMaxNumber(); + } + + public CGNode getNode(int index) { + CGNode n = cg.getNode(index); + return (containsNode(n) ? n : null); + } + + public int getNumber(CGNode n) { + return (containsNode(n) ? cg.getNumber(n) : -1); + } + + public IntSet getSuccNodeNumbers(CGNode node) { + assert containsNode(node); + MutableIntSet x = IntSetUtil.make(); + for (Iterator ns = getSuccNodes(node); ns.hasNext();) { + CGNode succ = (CGNode) ns.next(); + if (containsNode(succ)) { + x.add(getNumber(succ)); + } + } + + return x; + } + + public IntSet getPredNodeNumbers(CGNode node) { + assert containsNode(node); + MutableIntSet x = IntSetUtil.make(); + for (Iterator ns = getPredNodes(node); ns.hasNext();) { + CGNode pred = (CGNode) ns.next(); + if (containsNode(pred)) { + x.add(getNumber(pred)); + } + } + + return x; + } + + public int getNumberOfTargets(CGNode node, CallSiteReference site) { + return (containsNode(node) ? getPossibleTargets(node, site).size() : -1); + } + + public Iterator getPossibleSites(CGNode src, CGNode target) { + return ((containsNode(src) && containsNode(target)) ? cg.getPossibleSites(src, target) : null); + } + + public Set getPossibleTargets(CGNode node, CallSiteReference site) { + if (!containsNode(node)) { + return null; + } + Set result = HashSetFactory.make(); + for (Iterator ns = cg.getPossibleTargets(node, site).iterator(); ns.hasNext();) { + CGNode target = (CGNode) ns.next(); + if (containsNode(target)) { + result.add(target); + } + } + + return result; + } +} diff --git a/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/impl/SetOfClasses.java b/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/impl/SetOfClasses.java index 18acad655..a98f33870 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/impl/SetOfClasses.java +++ b/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/impl/SetOfClasses.java @@ -1,54 +1,54 @@ -/******************************************************************************* - * Copyright (c) 2002 - 2006 IBM Corporation. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * IBM Corporation - initial API and implementation - *******************************************************************************/ -package com.ibm.wala.ipa.callgraph.impl; - -import java.io.Serializable; -import java.util.HashSet; -import java.util.Iterator; -import java.util.Set; - -import com.ibm.wala.classLoader.IClass; -import com.ibm.wala.ipa.cha.IClassHierarchy; -import com.ibm.wala.types.TypeReference; -import com.ibm.wala.util.collections.HashSetFactory; - -/** - * Logically, a set of {@link IClass}. - * - * TODO: why does this not extend {@link Set}? Is there a good reason anymore? - */ -public abstract class SetOfClasses implements Serializable { - - public abstract boolean contains(String klassName); - - public abstract boolean contains(TypeReference klass); - - /** - * Iterate all classes in the given hierarchy that this set contains. - * - * @throws IllegalArgumentException if hierarchy is null - */ - public Iterator iterator(IClassHierarchy hierarchy) { - if (hierarchy == null) { - throw new IllegalArgumentException("hierarchy is null"); - } - HashSet result = HashSetFactory.make(); - for (IClass klass : hierarchy) { - if (contains(klass.getReference())) { - result.add(klass); - } - } - return result.iterator(); - } - - public abstract void add(IClass klass); - -} +/******************************************************************************* + * 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.ipa.callgraph.impl; + +import java.io.Serializable; +import java.util.HashSet; +import java.util.Iterator; +import java.util.Set; + +import com.ibm.wala.classLoader.IClass; +import com.ibm.wala.ipa.cha.IClassHierarchy; +import com.ibm.wala.types.TypeReference; +import com.ibm.wala.util.collections.HashSetFactory; + +/** + * Logically, a set of {@link IClass}. + * + * TODO: why does this not extend {@link Set}? Is there a good reason anymore? + */ +public abstract class SetOfClasses implements Serializable { + + public abstract boolean contains(String klassName); + + public abstract boolean contains(TypeReference klass); + + /** + * Iterate all classes in the given hierarchy that this set contains. + * + * @throws IllegalArgumentException if hierarchy is null + */ + public Iterator iterator(IClassHierarchy hierarchy) { + if (hierarchy == null) { + throw new IllegalArgumentException("hierarchy is null"); + } + HashSet result = HashSetFactory.make(); + for (IClass klass : hierarchy) { + if (contains(klass.getReference())) { + result.add(klass); + } + } + return result.iterator(); + } + + public abstract void add(IClass klass); + +} diff --git a/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/impl/SubtypesEntrypoint.java b/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/impl/SubtypesEntrypoint.java index c08a88237..f9249d5d1 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/impl/SubtypesEntrypoint.java +++ b/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/impl/SubtypesEntrypoint.java @@ -1,63 +1,63 @@ -/******************************************************************************* - * 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.ipa.callgraph.impl; - -import java.util.Collection; -import java.util.Set; - -import com.ibm.wala.classLoader.IClass; -import com.ibm.wala.classLoader.IMethod; -import com.ibm.wala.ipa.cha.IClassHierarchy; -import com.ibm.wala.types.MethodReference; -import com.ibm.wala.types.TypeReference; -import com.ibm.wala.util.collections.HashSetFactory; - -/** - * An entrypoint whose parameter types are cones based on declared types. - */ -public class SubtypesEntrypoint extends DefaultEntrypoint { - - public SubtypesEntrypoint(MethodReference method, IClassHierarchy cha) { - super(method, cha); - } - - public SubtypesEntrypoint(IMethod method, IClassHierarchy cha) { - super(method, cha); - } - - @Override - protected TypeReference[][] makeParameterTypes(IMethod method) { - TypeReference[][] result = new TypeReference[method.getNumberOfParameters()][]; - for (int i = 0; i < result.length; i++) { - result[i] = makeParameterTypes(method, i); - } - - return result; - } - - @Override - protected TypeReference[] makeParameterTypes(IMethod method, int i) { - TypeReference nominal = method.getParameterType(i); - if (nominal.isPrimitiveType() || nominal.isArrayType()) - return new TypeReference[] { nominal }; - else { - IClass nc = getCha().lookupClass(nominal); - Collection subcs = nc.isInterface() ? getCha().getImplementors(nominal) : getCha().computeSubClasses(nominal); - Set subs = HashSetFactory.make(); - for (IClass cs : subcs) { - if (!cs.isAbstract() && !cs.isInterface()) { - subs.add(cs.getReference()); - } - } - return subs.toArray(new TypeReference[subs.size()]); - } - } -} +/******************************************************************************* + * 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.ipa.callgraph.impl; + +import java.util.Collection; +import java.util.Set; + +import com.ibm.wala.classLoader.IClass; +import com.ibm.wala.classLoader.IMethod; +import com.ibm.wala.ipa.cha.IClassHierarchy; +import com.ibm.wala.types.MethodReference; +import com.ibm.wala.types.TypeReference; +import com.ibm.wala.util.collections.HashSetFactory; + +/** + * An entrypoint whose parameter types are cones based on declared types. + */ +public class SubtypesEntrypoint extends DefaultEntrypoint { + + public SubtypesEntrypoint(MethodReference method, IClassHierarchy cha) { + super(method, cha); + } + + public SubtypesEntrypoint(IMethod method, IClassHierarchy cha) { + super(method, cha); + } + + @Override + protected TypeReference[][] makeParameterTypes(IMethod method) { + TypeReference[][] result = new TypeReference[method.getNumberOfParameters()][]; + for (int i = 0; i < result.length; i++) { + result[i] = makeParameterTypes(method, i); + } + + return result; + } + + @Override + protected TypeReference[] makeParameterTypes(IMethod method, int i) { + TypeReference nominal = method.getParameterType(i); + if (nominal.isPrimitiveType() || nominal.isArrayType()) + return new TypeReference[] { nominal }; + else { + IClass nc = getCha().lookupClass(nominal); + Collection subcs = nc.isInterface() ? getCha().getImplementors(nominal) : getCha().computeSubClasses(nominal); + Set subs = HashSetFactory.make(); + for (IClass cs : subcs) { + if (!cs.isAbstract() && !cs.isInterface()) { + subs.add(cs.getReference()); + } + } + return subs.toArray(new TypeReference[subs.size()]); + } + } +} diff --git a/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/impl/Util.java b/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/impl/Util.java index 69bc00205..610b5d471 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/impl/Util.java +++ b/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/impl/Util.java @@ -1,460 +1,460 @@ -/******************************************************************************* - * 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.ipa.callgraph.impl; - -import java.io.InputStream; -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.ipa.callgraph.AnalysisCache; -import com.ibm.wala.ipa.callgraph.AnalysisOptions; -import com.ibm.wala.ipa.callgraph.AnalysisScope; -import com.ibm.wala.ipa.callgraph.CallGraphBuilder; -import com.ibm.wala.ipa.callgraph.ClassTargetSelector; -import com.ibm.wala.ipa.callgraph.ContextSelector; -import com.ibm.wala.ipa.callgraph.Entrypoint; -import com.ibm.wala.ipa.callgraph.MethodTargetSelector; -import com.ibm.wala.ipa.callgraph.propagation.SSAContextInterpreter; -import com.ibm.wala.ipa.callgraph.propagation.SSAPropagationCallGraphBuilder; -import com.ibm.wala.ipa.callgraph.propagation.cfa.ZeroXCFABuilder; -import com.ibm.wala.ipa.callgraph.propagation.cfa.ZeroXContainerCFABuilder; -import com.ibm.wala.ipa.callgraph.propagation.cfa.ZeroXInstanceKeys; -import com.ibm.wala.ipa.callgraph.propagation.rta.BasicRTABuilder; -import com.ibm.wala.ipa.cha.IClassHierarchy; -import com.ibm.wala.ipa.summaries.BypassClassTargetSelector; -import com.ibm.wala.ipa.summaries.BypassMethodTargetSelector; -import com.ibm.wala.ipa.summaries.XMLMethodSummaryReader; -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.collections.HashSetFactory; -import com.ibm.wala.util.debug.Assertions; -import com.ibm.wala.util.graph.Graph; -import com.ibm.wala.util.strings.Atom; - -/** - * Call graph utilities - */ -public class Util { - /** - * TODO: Make these properties? - */ - public static final String nativeSpec = "natives.xml"; - - /** - * Set up an AnalysisOptions object with default selectors, corresponding to class hierarchy lookup - * - * @throws IllegalArgumentException if options is null - */ - public static void addDefaultSelectors(AnalysisOptions options, IClassHierarchy cha) { - if (options == null) { - throw new IllegalArgumentException("options is null"); - } - options.setSelector(new ClassHierarchyMethodTargetSelector(cha)); - options.setSelector(new ClassHierarchyClassTargetSelector(cha)); - } - - /** - * Modify an options object to include bypass logic as specified by a an XML file. - * - * @throws IllegalArgumentException if scope is null - * @throws IllegalArgumentException if cl is null - * @throws IllegalArgumentException if options is null - * @throws IllegalArgumentException if scope is null - */ - public static void addBypassLogic(AnalysisOptions options, AnalysisScope scope, ClassLoader cl, String xmlFile, - IClassHierarchy cha) throws IllegalArgumentException { - if (scope == null) { - throw new IllegalArgumentException("scope is null"); - } - if (options == null) { - throw new IllegalArgumentException("options is null"); - } - if (cl == null) { - throw new IllegalArgumentException("cl is null"); - } - if (cha == null) { - throw new IllegalArgumentException("cha cannot be null"); - } - - InputStream s = cl.getResourceAsStream(xmlFile); - XMLMethodSummaryReader summary = new XMLMethodSummaryReader(s, scope); - - MethodTargetSelector ms = new BypassMethodTargetSelector(options.getMethodTargetSelector(), summary.getSummaries(), summary - .getIgnoredPackages(), cha); - options.setSelector(ms); - - ClassTargetSelector cs = new BypassClassTargetSelector(options.getClassTargetSelector(), summary.getAllocatableClasses(), cha, - cha.getLoader(scope.getLoader(Atom.findOrCreateUnicodeAtom("Synthetic")))); - options.setSelector(cs); - } - - /** - * @param scope - * @param cha - * @return set of all eligible Main classes in the class hierarchy - * @throws IllegalArgumentException if scope is null - */ - public static Iterable makeMainEntrypoints(AnalysisScope scope, IClassHierarchy cha) { - if (scope == null) { - throw new IllegalArgumentException("scope is null"); - } - return makeMainEntrypoints(scope.getApplicationLoader(), cha); - } - - public static Iterable makeMainEntrypoints(ClassLoaderReference clr, IClassHierarchy cha) { - if (cha == null) { - throw new IllegalArgumentException("cha is null"); - } - final Atom mainMethod = Atom.findOrCreateAsciiAtom("main"); - final HashSet result = HashSetFactory.make(); - for (IClass klass : cha) { - if (klass.getClassLoader().getReference().equals(clr)) { - MethodReference mainRef = MethodReference.findOrCreate(klass.getReference(), mainMethod, Descriptor - .findOrCreateUTF8("([Ljava/lang/String;)V")); - IMethod m = klass.getMethod(mainRef.getSelector()); - if (m != null) { - result.add(new DefaultEntrypoint(m, cha)); - } - } - } - return new Iterable() { - public Iterator iterator() { - return result.iterator(); - } - }; - } - - /** - * @return Entrypoints object for a Main J2SE class - */ - public static Iterable makeMainEntrypoints(AnalysisScope scope, final IClassHierarchy cha, String className) { - return makeMainEntrypoints(scope, cha, new String[] { className }); - } - - public static Iterable makeMainEntrypoints(final AnalysisScope scope, final IClassHierarchy cha, - final String[] classNames) { - if (scope == null) { - throw new IllegalArgumentException("scope is null"); - } - return makeMainEntrypoints(scope.getApplicationLoader(), cha, classNames); - } - - /** - * @return Entrypoints for a set of J2SE Main classes - * @throws IllegalArgumentException if classNames == null - * @throws IllegalArgumentException if (classNames != null) and (0 < classNames.length) and (classNames[0] == null) - * @throws IllegalArgumentException if classNames.length == 0 - */ - public static Iterable makeMainEntrypoints(final ClassLoaderReference loaderRef, final IClassHierarchy cha, - final String[] classNames) throws IllegalArgumentException, IllegalArgumentException, IllegalArgumentException { - - if (classNames == null) { - throw new IllegalArgumentException("classNames == null"); - } - if (classNames.length == 0) { - throw new IllegalArgumentException("classNames.length == 0"); - } - if (classNames[0] == null && 0 < classNames.length) { - throw new IllegalArgumentException("(0 < classNames.length) and (classNames[0] == null)"); - } - - for (int i = 0; i < classNames.length; i++) { - if (classNames[i].indexOf("L") != 0) { - throw new IllegalArgumentException("Expected class name to start with L " + classNames[i]); - } - if (classNames[i].indexOf(".") > 0) { - Assertions.productionAssertion(false, "Expected class name formatted with /, not . " + classNames[i]); - } - } - - return new Iterable() { - public Iterator iterator() { - final Atom mainMethod = Atom.findOrCreateAsciiAtom("main"); - return new Iterator() { - private int index = 0; - - public void remove() { - Assertions.UNREACHABLE(); - } - - public boolean hasNext() { - return index < classNames.length; - } - - public Entrypoint next() { - TypeReference T = TypeReference.findOrCreate(loaderRef, TypeName.string2TypeName(classNames[index++])); - MethodReference mainRef = MethodReference.findOrCreate(T, mainMethod, Descriptor - .findOrCreateUTF8("([Ljava/lang/String;)V")); - return new DefaultEntrypoint(mainRef, cha); - } - }; - } - }; - } - - /** - * create a set holding the contents of an {@link Iterator} - */ - public static Set setify(Iterator x) { - if (x == null) { - throw new IllegalArgumentException("Null x"); - } - Set y = HashSetFactory.make(); - while (x.hasNext()) { - y.add(x.next()); - } - return y; - } - - /** - * @param supG - * @param subG - * @throws IllegalArgumentException if subG is null - * @throws IllegalArgumentException if supG is null - */ - public static void checkGraphSubset(Graph supG, Graph subG) { - if (supG == null) { - throw new IllegalArgumentException("supG is null"); - } - if (subG == null) { - throw new IllegalArgumentException("subG is null"); - } - Set nodeDiff = setify(subG.iterator()); - nodeDiff.removeAll(setify(supG.iterator())); - if (!nodeDiff.isEmpty()) { - System.err.println("supergraph: "); - System.err.println(supG.toString()); - System.err.println("subgraph: "); - System.err.println(subG.toString()); - System.err.println("nodeDiff: "); - for (Iterator it = nodeDiff.iterator(); it.hasNext();) { - System.err.println(it.next().toString()); - } - Assertions.productionAssertion(nodeDiff.isEmpty(), "bad superset, see tracefile\n"); - } - - for (Iterator subNodes = subG.iterator(); subNodes.hasNext();) { - T m = subNodes.next(); - - Set succDiff = setify(subG.getSuccNodes(m)); - succDiff.removeAll(setify(supG.getSuccNodes(m))); - if (!succDiff.isEmpty()) { - Assertions.productionAssertion(succDiff.isEmpty(), "bad superset for successors of " + m + ":" + succDiff); - } - - Set predDiff = setify(subG.getPredNodes(m)); - predDiff.removeAll(setify(supG.getPredNodes(m))); - if (!predDiff.isEmpty()) { - System.err.println("supergraph: "); - System.err.println(supG.toString()); - System.err.println("subgraph: "); - System.err.println(subG.toString()); - System.err.println("predDiff: "); - for (Iterator it = predDiff.iterator(); it.hasNext();) { - System.err.println(it.next().toString()); - } - Assertions.UNREACHABLE("bad superset for predecessors of " + m + ":" + predDiff); - } - } - } - - /** - * @return an RTA Call Graph builder. - * - * @param options options that govern call graph construction - * @param cha governing class hierarchy - * @param scope representation of the analysis scope - */ - public static CallGraphBuilder makeRTABuilder(AnalysisOptions options, AnalysisCache cache, IClassHierarchy cha, - AnalysisScope scope) { - - addDefaultSelectors(options, cha); - addDefaultBypassLogic(options, scope, Util.class.getClassLoader(), cha); - - return new BasicRTABuilder(cha, options, cache, null, null); - } - - /** - * @param options options that govern call graph construction - * @param cha governing class hierarchy - * @param scope representation of the analysis scope - * @return a 0-CFA Call Graph Builder. - */ - public static SSAPropagationCallGraphBuilder makeZeroCFABuilder(AnalysisOptions options, AnalysisCache cache, - IClassHierarchy cha, AnalysisScope scope) { - return makeZeroCFABuilder(options, cache, cha, scope, null, null); - } - - /** - * @param options options that govern call graph construction - * @param cha governing class hierarchy - * @param scope representation of the analysis scope - * @param customSelector user-defined context selector, or null if none - * @param customInterpreter user-defined context interpreter, or null if none - * @return a 0-CFA Call Graph Builder. - * @throws IllegalArgumentException if options is null - */ - public static SSAPropagationCallGraphBuilder makeZeroCFABuilder(AnalysisOptions options, AnalysisCache cache, - IClassHierarchy cha, AnalysisScope scope, ContextSelector customSelector, SSAContextInterpreter customInterpreter) { - - if (options == null) { - throw new IllegalArgumentException("options is null"); - } - addDefaultSelectors(options, cha); - addDefaultBypassLogic(options, scope, Util.class.getClassLoader(), cha); - - return ZeroXCFABuilder.make(cha, options, cache, customSelector, customInterpreter, ZeroXInstanceKeys.NONE); - } - - /** - * @return a 0-1-CFA Call Graph Builder. - * - * @param options options that govern call graph construction - * @param cha governing class hierarchy - * @param scope representation of the analysis scope - */ - public static SSAPropagationCallGraphBuilder makeZeroOneCFABuilder(AnalysisOptions options, AnalysisCache cache, - IClassHierarchy cha, AnalysisScope scope) { - return makeZeroOneCFABuilder(options, cache, cha, scope, null, null); - } - - /** - * @param options options that govern call graph construction - * @param cha governing class hierarchy - * @param scope representation of the analysis scope - * @param customSelector user-defined context selector, or null if none - * @param customInterpreter user-defined context interpreter, or null if none - * @return a 0-1-CFA Call Graph Builder. - * @throws IllegalArgumentException if options is null - */ - public static SSAPropagationCallGraphBuilder makeVanillaZeroOneCFABuilder(AnalysisOptions options, AnalysisCache cache, - IClassHierarchy cha, AnalysisScope scope, ContextSelector customSelector, SSAContextInterpreter customInterpreter) { - - if (options == null) { - throw new IllegalArgumentException("options is null"); - } - addDefaultSelectors(options, cha); - addDefaultBypassLogic(options, scope, Util.class.getClassLoader(), cha); - - return ZeroXCFABuilder.make(cha, options, cache, customSelector, customInterpreter, ZeroXInstanceKeys.ALLOCATIONS | ZeroXInstanceKeys.CONSTANT_SPECIFIC); - } - - /** - * @return a 0-1-CFA Call Graph Builder. - * - * @param options options that govern call graph construction - * @param cha governing class hierarchy - * @param scope representation of the analysis scope - */ - public static SSAPropagationCallGraphBuilder makeVanillaZeroOneCFABuilder(AnalysisOptions options, AnalysisCache cache, - IClassHierarchy cha, AnalysisScope scope) { - return makeVanillaZeroOneCFABuilder(options, cache, cha, scope, null, null); - } - - /** - * @param options options that govern call graph construction - * @param cha governing class hierarchy - * @param scope representation of the analysis scope - * @param customSelector user-defined context selector, or null if none - * @param customInterpreter user-defined context interpreter, or null if none - * @return a 0-1-CFA Call Graph Builder. - * @throws IllegalArgumentException if options is null - */ - public static SSAPropagationCallGraphBuilder makeZeroOneCFABuilder(AnalysisOptions options, AnalysisCache cache, - IClassHierarchy cha, AnalysisScope scope, ContextSelector customSelector, SSAContextInterpreter customInterpreter) { - - if (options == null) { - throw new IllegalArgumentException("options is null"); - } - addDefaultSelectors(options, cha); - addDefaultBypassLogic(options, scope, Util.class.getClassLoader(), cha); - - return ZeroXCFABuilder.make(cha, options, cache, customSelector, customInterpreter, ZeroXInstanceKeys.ALLOCATIONS | ZeroXInstanceKeys.SMUSH_MANY | ZeroXInstanceKeys.SMUSH_PRIMITIVE_HOLDERS - | ZeroXInstanceKeys.SMUSH_STRINGS | ZeroXInstanceKeys.SMUSH_THROWABLES); - } - - /** - * @param options options that govern call graph construction - * @param cha governing class hierarchy - * @param scope representation of the analysis scope - * @return a 0-CFA Call Graph Builder augmented with extra logic for containers - * @throws IllegalArgumentException if options is null - */ - public static SSAPropagationCallGraphBuilder makeZeroContainerCFABuilder(AnalysisOptions options, AnalysisCache cache, - IClassHierarchy cha, AnalysisScope scope) { - - if (options == null) { - throw new IllegalArgumentException("options is null"); - } - addDefaultSelectors(options, cha); - addDefaultBypassLogic(options, scope, Util.class.getClassLoader(), cha); - ContextSelector appSelector = null; - SSAContextInterpreter appInterpreter = null; - - return new ZeroXContainerCFABuilder(cha, options, cache, appSelector, appInterpreter, ZeroXInstanceKeys.NONE); - } - - /** - * @param options options that govern call graph construction - * @param cha governing class hierarchy - * @param scope representation of the analysis scope - * @return a 0-1-CFA Call Graph Builder augmented with extra logic for containers - * @throws IllegalArgumentException if options is null - */ - public static SSAPropagationCallGraphBuilder makeZeroOneContainerCFABuilder(AnalysisOptions options, AnalysisCache cache, - IClassHierarchy cha, AnalysisScope scope) { - - if (options == null) { - throw new IllegalArgumentException("options is null"); - } - addDefaultSelectors(options, cha); - addDefaultBypassLogic(options, scope, Util.class.getClassLoader(), cha); - ContextSelector appSelector = null; - SSAContextInterpreter appInterpreter = null; - - return new ZeroXContainerCFABuilder(cha, options, cache, appSelector, appInterpreter, ZeroXInstanceKeys.ALLOCATIONS | ZeroXInstanceKeys.SMUSH_MANY | ZeroXInstanceKeys.SMUSH_PRIMITIVE_HOLDERS - | ZeroXInstanceKeys.SMUSH_STRINGS | ZeroXInstanceKeys.SMUSH_THROWABLES); - } - - /** - * @param options options that govern call graph construction - * @param cha governing class hierarchy - * @param scope representation of the analysis scope - * @return a 0-1-CFA Call Graph Builder augmented with extra logic for containers - * @throws IllegalArgumentException if options is null - */ - public static SSAPropagationCallGraphBuilder makeVanillaZeroOneContainerCFABuilder(AnalysisOptions options, AnalysisCache cache, - IClassHierarchy cha, AnalysisScope scope) { - - if (options == null) { - throw new IllegalArgumentException("options is null"); - } - addDefaultSelectors(options, cha); - addDefaultBypassLogic(options, scope, Util.class.getClassLoader(), cha); - ContextSelector appSelector = null; - SSAContextInterpreter appInterpreter = null; - options.setUseConstantSpecificKeys(true); - - return new ZeroXContainerCFABuilder(cha, options, cache, appSelector, appInterpreter, ZeroXInstanceKeys.ALLOCATIONS); - - } - - public static void addDefaultBypassLogic(AnalysisOptions options, AnalysisScope scope, ClassLoader cl, IClassHierarchy cha) { - addBypassLogic(options, scope, cl, nativeSpec, cha); - } - -} +/******************************************************************************* + * 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.ipa.callgraph.impl; + +import java.io.InputStream; +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.ipa.callgraph.AnalysisCache; +import com.ibm.wala.ipa.callgraph.AnalysisOptions; +import com.ibm.wala.ipa.callgraph.AnalysisScope; +import com.ibm.wala.ipa.callgraph.CallGraphBuilder; +import com.ibm.wala.ipa.callgraph.ClassTargetSelector; +import com.ibm.wala.ipa.callgraph.ContextSelector; +import com.ibm.wala.ipa.callgraph.Entrypoint; +import com.ibm.wala.ipa.callgraph.MethodTargetSelector; +import com.ibm.wala.ipa.callgraph.propagation.SSAContextInterpreter; +import com.ibm.wala.ipa.callgraph.propagation.SSAPropagationCallGraphBuilder; +import com.ibm.wala.ipa.callgraph.propagation.cfa.ZeroXCFABuilder; +import com.ibm.wala.ipa.callgraph.propagation.cfa.ZeroXContainerCFABuilder; +import com.ibm.wala.ipa.callgraph.propagation.cfa.ZeroXInstanceKeys; +import com.ibm.wala.ipa.callgraph.propagation.rta.BasicRTABuilder; +import com.ibm.wala.ipa.cha.IClassHierarchy; +import com.ibm.wala.ipa.summaries.BypassClassTargetSelector; +import com.ibm.wala.ipa.summaries.BypassMethodTargetSelector; +import com.ibm.wala.ipa.summaries.XMLMethodSummaryReader; +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.collections.HashSetFactory; +import com.ibm.wala.util.debug.Assertions; +import com.ibm.wala.util.graph.Graph; +import com.ibm.wala.util.strings.Atom; + +/** + * Call graph utilities + */ +public class Util { + /** + * TODO: Make these properties? + */ + public static final String nativeSpec = "natives.xml"; + + /** + * Set up an AnalysisOptions object with default selectors, corresponding to class hierarchy lookup + * + * @throws IllegalArgumentException if options is null + */ + public static void addDefaultSelectors(AnalysisOptions options, IClassHierarchy cha) { + if (options == null) { + throw new IllegalArgumentException("options is null"); + } + options.setSelector(new ClassHierarchyMethodTargetSelector(cha)); + options.setSelector(new ClassHierarchyClassTargetSelector(cha)); + } + + /** + * Modify an options object to include bypass logic as specified by a an XML file. + * + * @throws IllegalArgumentException if scope is null + * @throws IllegalArgumentException if cl is null + * @throws IllegalArgumentException if options is null + * @throws IllegalArgumentException if scope is null + */ + public static void addBypassLogic(AnalysisOptions options, AnalysisScope scope, ClassLoader cl, String xmlFile, + IClassHierarchy cha) throws IllegalArgumentException { + if (scope == null) { + throw new IllegalArgumentException("scope is null"); + } + if (options == null) { + throw new IllegalArgumentException("options is null"); + } + if (cl == null) { + throw new IllegalArgumentException("cl is null"); + } + if (cha == null) { + throw new IllegalArgumentException("cha cannot be null"); + } + + InputStream s = cl.getResourceAsStream(xmlFile); + XMLMethodSummaryReader summary = new XMLMethodSummaryReader(s, scope); + + MethodTargetSelector ms = new BypassMethodTargetSelector(options.getMethodTargetSelector(), summary.getSummaries(), summary + .getIgnoredPackages(), cha); + options.setSelector(ms); + + ClassTargetSelector cs = new BypassClassTargetSelector(options.getClassTargetSelector(), summary.getAllocatableClasses(), cha, + cha.getLoader(scope.getLoader(Atom.findOrCreateUnicodeAtom("Synthetic")))); + options.setSelector(cs); + } + + /** + * @param scope + * @param cha + * @return set of all eligible Main classes in the class hierarchy + * @throws IllegalArgumentException if scope is null + */ + public static Iterable makeMainEntrypoints(AnalysisScope scope, IClassHierarchy cha) { + if (scope == null) { + throw new IllegalArgumentException("scope is null"); + } + return makeMainEntrypoints(scope.getApplicationLoader(), cha); + } + + public static Iterable makeMainEntrypoints(ClassLoaderReference clr, IClassHierarchy cha) { + if (cha == null) { + throw new IllegalArgumentException("cha is null"); + } + final Atom mainMethod = Atom.findOrCreateAsciiAtom("main"); + final HashSet result = HashSetFactory.make(); + for (IClass klass : cha) { + if (klass.getClassLoader().getReference().equals(clr)) { + MethodReference mainRef = MethodReference.findOrCreate(klass.getReference(), mainMethod, Descriptor + .findOrCreateUTF8("([Ljava/lang/String;)V")); + IMethod m = klass.getMethod(mainRef.getSelector()); + if (m != null) { + result.add(new DefaultEntrypoint(m, cha)); + } + } + } + return new Iterable() { + public Iterator iterator() { + return result.iterator(); + } + }; + } + + /** + * @return Entrypoints object for a Main J2SE class + */ + public static Iterable makeMainEntrypoints(AnalysisScope scope, final IClassHierarchy cha, String className) { + return makeMainEntrypoints(scope, cha, new String[] { className }); + } + + public static Iterable makeMainEntrypoints(final AnalysisScope scope, final IClassHierarchy cha, + final String[] classNames) { + if (scope == null) { + throw new IllegalArgumentException("scope is null"); + } + return makeMainEntrypoints(scope.getApplicationLoader(), cha, classNames); + } + + /** + * @return Entrypoints for a set of J2SE Main classes + * @throws IllegalArgumentException if classNames == null + * @throws IllegalArgumentException if (classNames != null) and (0 < classNames.length) and (classNames[0] == null) + * @throws IllegalArgumentException if classNames.length == 0 + */ + public static Iterable makeMainEntrypoints(final ClassLoaderReference loaderRef, final IClassHierarchy cha, + final String[] classNames) throws IllegalArgumentException, IllegalArgumentException, IllegalArgumentException { + + if (classNames == null) { + throw new IllegalArgumentException("classNames == null"); + } + if (classNames.length == 0) { + throw new IllegalArgumentException("classNames.length == 0"); + } + if (classNames[0] == null && 0 < classNames.length) { + throw new IllegalArgumentException("(0 < classNames.length) and (classNames[0] == null)"); + } + + for (int i = 0; i < classNames.length; i++) { + if (classNames[i].indexOf("L") != 0) { + throw new IllegalArgumentException("Expected class name to start with L " + classNames[i]); + } + if (classNames[i].indexOf(".") > 0) { + Assertions.productionAssertion(false, "Expected class name formatted with /, not . " + classNames[i]); + } + } + + return new Iterable() { + public Iterator iterator() { + final Atom mainMethod = Atom.findOrCreateAsciiAtom("main"); + return new Iterator() { + private int index = 0; + + public void remove() { + Assertions.UNREACHABLE(); + } + + public boolean hasNext() { + return index < classNames.length; + } + + public Entrypoint next() { + TypeReference T = TypeReference.findOrCreate(loaderRef, TypeName.string2TypeName(classNames[index++])); + MethodReference mainRef = MethodReference.findOrCreate(T, mainMethod, Descriptor + .findOrCreateUTF8("([Ljava/lang/String;)V")); + return new DefaultEntrypoint(mainRef, cha); + } + }; + } + }; + } + + /** + * create a set holding the contents of an {@link Iterator} + */ + public static Set setify(Iterator x) { + if (x == null) { + throw new IllegalArgumentException("Null x"); + } + Set y = HashSetFactory.make(); + while (x.hasNext()) { + y.add(x.next()); + } + return y; + } + + /** + * @param supG + * @param subG + * @throws IllegalArgumentException if subG is null + * @throws IllegalArgumentException if supG is null + */ + public static void checkGraphSubset(Graph supG, Graph subG) { + if (supG == null) { + throw new IllegalArgumentException("supG is null"); + } + if (subG == null) { + throw new IllegalArgumentException("subG is null"); + } + Set nodeDiff = setify(subG.iterator()); + nodeDiff.removeAll(setify(supG.iterator())); + if (!nodeDiff.isEmpty()) { + System.err.println("supergraph: "); + System.err.println(supG.toString()); + System.err.println("subgraph: "); + System.err.println(subG.toString()); + System.err.println("nodeDiff: "); + for (Iterator it = nodeDiff.iterator(); it.hasNext();) { + System.err.println(it.next().toString()); + } + Assertions.productionAssertion(nodeDiff.isEmpty(), "bad superset, see tracefile\n"); + } + + for (Iterator subNodes = subG.iterator(); subNodes.hasNext();) { + T m = subNodes.next(); + + Set succDiff = setify(subG.getSuccNodes(m)); + succDiff.removeAll(setify(supG.getSuccNodes(m))); + if (!succDiff.isEmpty()) { + Assertions.productionAssertion(succDiff.isEmpty(), "bad superset for successors of " + m + ":" + succDiff); + } + + Set predDiff = setify(subG.getPredNodes(m)); + predDiff.removeAll(setify(supG.getPredNodes(m))); + if (!predDiff.isEmpty()) { + System.err.println("supergraph: "); + System.err.println(supG.toString()); + System.err.println("subgraph: "); + System.err.println(subG.toString()); + System.err.println("predDiff: "); + for (Iterator it = predDiff.iterator(); it.hasNext();) { + System.err.println(it.next().toString()); + } + Assertions.UNREACHABLE("bad superset for predecessors of " + m + ":" + predDiff); + } + } + } + + /** + * @return an RTA Call Graph builder. + * + * @param options options that govern call graph construction + * @param cha governing class hierarchy + * @param scope representation of the analysis scope + */ + public static CallGraphBuilder makeRTABuilder(AnalysisOptions options, AnalysisCache cache, IClassHierarchy cha, + AnalysisScope scope) { + + addDefaultSelectors(options, cha); + addDefaultBypassLogic(options, scope, Util.class.getClassLoader(), cha); + + return new BasicRTABuilder(cha, options, cache, null, null); + } + + /** + * @param options options that govern call graph construction + * @param cha governing class hierarchy + * @param scope representation of the analysis scope + * @return a 0-CFA Call Graph Builder. + */ + public static SSAPropagationCallGraphBuilder makeZeroCFABuilder(AnalysisOptions options, AnalysisCache cache, + IClassHierarchy cha, AnalysisScope scope) { + return makeZeroCFABuilder(options, cache, cha, scope, null, null); + } + + /** + * @param options options that govern call graph construction + * @param cha governing class hierarchy + * @param scope representation of the analysis scope + * @param customSelector user-defined context selector, or null if none + * @param customInterpreter user-defined context interpreter, or null if none + * @return a 0-CFA Call Graph Builder. + * @throws IllegalArgumentException if options is null + */ + public static SSAPropagationCallGraphBuilder makeZeroCFABuilder(AnalysisOptions options, AnalysisCache cache, + IClassHierarchy cha, AnalysisScope scope, ContextSelector customSelector, SSAContextInterpreter customInterpreter) { + + if (options == null) { + throw new IllegalArgumentException("options is null"); + } + addDefaultSelectors(options, cha); + addDefaultBypassLogic(options, scope, Util.class.getClassLoader(), cha); + + return ZeroXCFABuilder.make(cha, options, cache, customSelector, customInterpreter, ZeroXInstanceKeys.NONE); + } + + /** + * @return a 0-1-CFA Call Graph Builder. + * + * @param options options that govern call graph construction + * @param cha governing class hierarchy + * @param scope representation of the analysis scope + */ + public static SSAPropagationCallGraphBuilder makeZeroOneCFABuilder(AnalysisOptions options, AnalysisCache cache, + IClassHierarchy cha, AnalysisScope scope) { + return makeZeroOneCFABuilder(options, cache, cha, scope, null, null); + } + + /** + * @param options options that govern call graph construction + * @param cha governing class hierarchy + * @param scope representation of the analysis scope + * @param customSelector user-defined context selector, or null if none + * @param customInterpreter user-defined context interpreter, or null if none + * @return a 0-1-CFA Call Graph Builder. + * @throws IllegalArgumentException if options is null + */ + public static SSAPropagationCallGraphBuilder makeVanillaZeroOneCFABuilder(AnalysisOptions options, AnalysisCache cache, + IClassHierarchy cha, AnalysisScope scope, ContextSelector customSelector, SSAContextInterpreter customInterpreter) { + + if (options == null) { + throw new IllegalArgumentException("options is null"); + } + addDefaultSelectors(options, cha); + addDefaultBypassLogic(options, scope, Util.class.getClassLoader(), cha); + + return ZeroXCFABuilder.make(cha, options, cache, customSelector, customInterpreter, ZeroXInstanceKeys.ALLOCATIONS | ZeroXInstanceKeys.CONSTANT_SPECIFIC); + } + + /** + * @return a 0-1-CFA Call Graph Builder. + * + * @param options options that govern call graph construction + * @param cha governing class hierarchy + * @param scope representation of the analysis scope + */ + public static SSAPropagationCallGraphBuilder makeVanillaZeroOneCFABuilder(AnalysisOptions options, AnalysisCache cache, + IClassHierarchy cha, AnalysisScope scope) { + return makeVanillaZeroOneCFABuilder(options, cache, cha, scope, null, null); + } + + /** + * @param options options that govern call graph construction + * @param cha governing class hierarchy + * @param scope representation of the analysis scope + * @param customSelector user-defined context selector, or null if none + * @param customInterpreter user-defined context interpreter, or null if none + * @return a 0-1-CFA Call Graph Builder. + * @throws IllegalArgumentException if options is null + */ + public static SSAPropagationCallGraphBuilder makeZeroOneCFABuilder(AnalysisOptions options, AnalysisCache cache, + IClassHierarchy cha, AnalysisScope scope, ContextSelector customSelector, SSAContextInterpreter customInterpreter) { + + if (options == null) { + throw new IllegalArgumentException("options is null"); + } + addDefaultSelectors(options, cha); + addDefaultBypassLogic(options, scope, Util.class.getClassLoader(), cha); + + return ZeroXCFABuilder.make(cha, options, cache, customSelector, customInterpreter, ZeroXInstanceKeys.ALLOCATIONS | ZeroXInstanceKeys.SMUSH_MANY | ZeroXInstanceKeys.SMUSH_PRIMITIVE_HOLDERS + | ZeroXInstanceKeys.SMUSH_STRINGS | ZeroXInstanceKeys.SMUSH_THROWABLES); + } + + /** + * @param options options that govern call graph construction + * @param cha governing class hierarchy + * @param scope representation of the analysis scope + * @return a 0-CFA Call Graph Builder augmented with extra logic for containers + * @throws IllegalArgumentException if options is null + */ + public static SSAPropagationCallGraphBuilder makeZeroContainerCFABuilder(AnalysisOptions options, AnalysisCache cache, + IClassHierarchy cha, AnalysisScope scope) { + + if (options == null) { + throw new IllegalArgumentException("options is null"); + } + addDefaultSelectors(options, cha); + addDefaultBypassLogic(options, scope, Util.class.getClassLoader(), cha); + ContextSelector appSelector = null; + SSAContextInterpreter appInterpreter = null; + + return new ZeroXContainerCFABuilder(cha, options, cache, appSelector, appInterpreter, ZeroXInstanceKeys.NONE); + } + + /** + * @param options options that govern call graph construction + * @param cha governing class hierarchy + * @param scope representation of the analysis scope + * @return a 0-1-CFA Call Graph Builder augmented with extra logic for containers + * @throws IllegalArgumentException if options is null + */ + public static SSAPropagationCallGraphBuilder makeZeroOneContainerCFABuilder(AnalysisOptions options, AnalysisCache cache, + IClassHierarchy cha, AnalysisScope scope) { + + if (options == null) { + throw new IllegalArgumentException("options is null"); + } + addDefaultSelectors(options, cha); + addDefaultBypassLogic(options, scope, Util.class.getClassLoader(), cha); + ContextSelector appSelector = null; + SSAContextInterpreter appInterpreter = null; + + return new ZeroXContainerCFABuilder(cha, options, cache, appSelector, appInterpreter, ZeroXInstanceKeys.ALLOCATIONS | ZeroXInstanceKeys.SMUSH_MANY | ZeroXInstanceKeys.SMUSH_PRIMITIVE_HOLDERS + | ZeroXInstanceKeys.SMUSH_STRINGS | ZeroXInstanceKeys.SMUSH_THROWABLES); + } + + /** + * @param options options that govern call graph construction + * @param cha governing class hierarchy + * @param scope representation of the analysis scope + * @return a 0-1-CFA Call Graph Builder augmented with extra logic for containers + * @throws IllegalArgumentException if options is null + */ + public static SSAPropagationCallGraphBuilder makeVanillaZeroOneContainerCFABuilder(AnalysisOptions options, AnalysisCache cache, + IClassHierarchy cha, AnalysisScope scope) { + + if (options == null) { + throw new IllegalArgumentException("options is null"); + } + addDefaultSelectors(options, cha); + addDefaultBypassLogic(options, scope, Util.class.getClassLoader(), cha); + ContextSelector appSelector = null; + SSAContextInterpreter appInterpreter = null; + options.setUseConstantSpecificKeys(true); + + return new ZeroXContainerCFABuilder(cha, options, cache, appSelector, appInterpreter, ZeroXInstanceKeys.ALLOCATIONS); + + } + + public static void addDefaultBypassLogic(AnalysisOptions options, AnalysisScope scope, ClassLoader cl, IClassHierarchy cha) { + addBypassLogic(options, scope, cl, nativeSpec, cha); + } + +} diff --git a/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/AbstractFieldPointerKey.java b/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/AbstractFieldPointerKey.java index d0b25d39e..a0c609367 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/AbstractFieldPointerKey.java +++ b/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/AbstractFieldPointerKey.java @@ -1,30 +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.ipa.callgraph.propagation; - -/** - * Common implementation for {@link InstanceFieldPointerKey} implementations. - * - */ -public abstract class AbstractFieldPointerKey extends AbstractPointerKey implements InstanceFieldPointerKey { - final protected InstanceKey instance; - - protected AbstractFieldPointerKey(InstanceKey container) { - if (container == null) { - throw new IllegalArgumentException("container is null"); - } - this.instance = container; - } - - public InstanceKey getInstanceKey() { - return instance; - } -} +/******************************************************************************* + * 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.ipa.callgraph.propagation; + +/** + * Common implementation for {@link InstanceFieldPointerKey} implementations. + * + */ +public abstract class AbstractFieldPointerKey extends AbstractPointerKey implements InstanceFieldPointerKey { + final protected InstanceKey instance; + + protected AbstractFieldPointerKey(InstanceKey container) { + if (container == null) { + throw new IllegalArgumentException("container is null"); + } + this.instance = container; + } + + public InstanceKey getInstanceKey() { + return instance; + } +} diff --git a/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/AbstractLocalPointerKey.java b/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/AbstractLocalPointerKey.java index 3c05c2f50..5966a509d 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/AbstractLocalPointerKey.java +++ b/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/AbstractLocalPointerKey.java @@ -1,23 +1,23 @@ -/******************************************************************************* - * Copyright (c) 2002 - 2006 IBM Corporation. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * IBM Corporation - initial API and implementation - *******************************************************************************/ -package com.ibm.wala.ipa.callgraph.propagation; - -import com.ibm.wala.ipa.callgraph.CGNode; - -/** - * A {@link PointerKey} representing a local variable must carry at least a {@link CGNode}. - * - */ -public abstract class AbstractLocalPointerKey extends AbstractPointerKey { - - abstract public CGNode getNode(); - -} +/******************************************************************************* + * 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.ipa.callgraph.propagation; + +import com.ibm.wala.ipa.callgraph.CGNode; + +/** + * A {@link PointerKey} representing a local variable must carry at least a {@link CGNode}. + * + */ +public abstract class AbstractLocalPointerKey extends AbstractPointerKey { + + abstract public CGNode getNode(); + +} diff --git a/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/AbstractPointerAnalysis.java b/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/AbstractPointerAnalysis.java index 2812788ec..00383947b 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/AbstractPointerAnalysis.java +++ b/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/AbstractPointerAnalysis.java @@ -1,64 +1,64 @@ -/******************************************************************************* - * 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.ipa.callgraph.propagation; - -import java.util.Collection; -import java.util.Collections; - -import com.ibm.wala.analysis.pointers.BasicHeapGraph; -import com.ibm.wala.analysis.pointers.HeapGraph; -import com.ibm.wala.ipa.callgraph.CallGraph; -import com.ibm.wala.util.intset.MutableMapping; -import com.ibm.wala.util.intset.OrdinalSetMapping; - -/** - * Abstract superclass for {@link PointerAnalysis} implementations. - */ -public abstract class AbstractPointerAnalysis implements PointerAnalysis { - - /** - * graph representation of pointer-analysis results - */ - private HeapGraph heapGraph; - /** - * Governing call graph. - */ - private final CallGraph cg; - - /** - * bijection from InstanceKey <=>Integer - */ - protected final MutableMapping instanceKeys; - - protected AbstractPointerAnalysis(CallGraph cg, MutableMapping instanceKeys) { - this.cg = cg; - this.instanceKeys = instanceKeys; - } - - public HeapGraph getHeapGraph() { - if (heapGraph == null) { - heapGraph = new BasicHeapGraph(this, cg); - } - return heapGraph; - } - - protected CallGraph getCallGraph() { - return cg; - } - - public Collection getInstanceKeys() { - return Collections.unmodifiableCollection(instanceKeys.getObjects()); - } - - public OrdinalSetMapping getInstanceKeyMapping() { - return instanceKeys; - } -} +/******************************************************************************* + * 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.ipa.callgraph.propagation; + +import java.util.Collection; +import java.util.Collections; + +import com.ibm.wala.analysis.pointers.BasicHeapGraph; +import com.ibm.wala.analysis.pointers.HeapGraph; +import com.ibm.wala.ipa.callgraph.CallGraph; +import com.ibm.wala.util.intset.MutableMapping; +import com.ibm.wala.util.intset.OrdinalSetMapping; + +/** + * Abstract superclass for {@link PointerAnalysis} implementations. + */ +public abstract class AbstractPointerAnalysis implements PointerAnalysis { + + /** + * graph representation of pointer-analysis results + */ + private HeapGraph heapGraph; + /** + * Governing call graph. + */ + private final CallGraph cg; + + /** + * bijection from InstanceKey <=>Integer + */ + protected final MutableMapping instanceKeys; + + protected AbstractPointerAnalysis(CallGraph cg, MutableMapping instanceKeys) { + this.cg = cg; + this.instanceKeys = instanceKeys; + } + + public HeapGraph getHeapGraph() { + if (heapGraph == null) { + heapGraph = new BasicHeapGraph(this, cg); + } + return heapGraph; + } + + protected CallGraph getCallGraph() { + return cg; + } + + public Collection getInstanceKeys() { + return Collections.unmodifiableCollection(instanceKeys.getObjects()); + } + + public OrdinalSetMapping getInstanceKeyMapping() { + return instanceKeys; + } +} diff --git a/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/AbstractPointerKey.java b/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/AbstractPointerKey.java index e7a98b5c2..c95504576 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/AbstractPointerKey.java +++ b/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/AbstractPointerKey.java @@ -1,23 +1,23 @@ -/******************************************************************************* - * Copyright (c) 2002 - 2006 IBM Corporation. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * IBM Corporation - initial API and implementation - *******************************************************************************/ -package com.ibm.wala.ipa.callgraph.propagation; - -/** - * This class exists to force {@link PointerKey} implementations to implement equals() and hashCode()s. - * - */ -public abstract class AbstractPointerKey implements PointerKey { - @Override - public abstract boolean equals(Object obj); - - @Override - public abstract int hashCode(); -} +/******************************************************************************* + * 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.ipa.callgraph.propagation; + +/** + * This class exists to force {@link PointerKey} implementations to implement equals() and hashCode()s. + * + */ +public abstract class AbstractPointerKey implements PointerKey { + @Override + public abstract boolean equals(Object obj); + + @Override + public abstract int hashCode(); +} diff --git a/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/AbstractPointsToSolver.java b/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/AbstractPointsToSolver.java index a778133f0..33d27dc7a 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/AbstractPointsToSolver.java +++ b/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/AbstractPointsToSolver.java @@ -1,56 +1,56 @@ -/******************************************************************************* - * Copyright (c) 2002 - 2006 IBM Corporation. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * IBM Corporation - initial API and implementation - *******************************************************************************/ -package com.ibm.wala.ipa.callgraph.propagation; - - -import com.ibm.wala.util.CancelException; -import com.ibm.wala.util.MonitorUtil.IProgressMonitor; - - -/** - * abstract base class for solver for pointer analysis - */ -public abstract class AbstractPointsToSolver implements IPointsToSolver { - - protected final static boolean DEBUG = false; - - private final PropagationSystem system; - - private final PropagationCallGraphBuilder builder; - - private final ReflectionHandler reflectionHandler; - - public AbstractPointsToSolver(PropagationSystem system, PropagationCallGraphBuilder builder) { - if (system == null) { - throw new IllegalArgumentException("null system"); - } - this.system = system; - this.builder = builder; - this.reflectionHandler = new ReflectionHandler(builder); - } - - /* - * @see com.ibm.wala.ipa.callgraph.propagation.IPointsToSolver#solve() - */ - public abstract void solve(IProgressMonitor monitor) throws IllegalArgumentException, CancelException; - - protected PropagationCallGraphBuilder getBuilder() { - return builder; - } - - protected ReflectionHandler getReflectionHandler() { - return reflectionHandler; - } - - protected PropagationSystem getSystem() { - return system; - } -} +/******************************************************************************* + * 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.ipa.callgraph.propagation; + + +import com.ibm.wala.util.CancelException; +import com.ibm.wala.util.MonitorUtil.IProgressMonitor; + + +/** + * abstract base class for solver for pointer analysis + */ +public abstract class AbstractPointsToSolver implements IPointsToSolver { + + protected final static boolean DEBUG = false; + + private final PropagationSystem system; + + private final PropagationCallGraphBuilder builder; + + private final ReflectionHandler reflectionHandler; + + public AbstractPointsToSolver(PropagationSystem system, PropagationCallGraphBuilder builder) { + if (system == null) { + throw new IllegalArgumentException("null system"); + } + this.system = system; + this.builder = builder; + this.reflectionHandler = new ReflectionHandler(builder); + } + + /* + * @see com.ibm.wala.ipa.callgraph.propagation.IPointsToSolver#solve() + */ + public abstract void solve(IProgressMonitor monitor) throws IllegalArgumentException, CancelException; + + protected PropagationCallGraphBuilder getBuilder() { + return builder; + } + + protected ReflectionHandler getReflectionHandler() { + return reflectionHandler; + } + + protected PropagationSystem getSystem() { + return system; + } +} diff --git a/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/AbstractTypeInNode.java b/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/AbstractTypeInNode.java index 66fefab5f..708287e02 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/AbstractTypeInNode.java +++ b/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/AbstractTypeInNode.java @@ -1,60 +1,60 @@ -/******************************************************************************* - * 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.ipa.callgraph.propagation; - -import com.ibm.wala.analysis.reflection.InstanceKeyWithNode; -import com.ibm.wala.classLoader.IClass; -import com.ibm.wala.ipa.callgraph.CGNode; -import com.ibm.wala.util.debug.Assertions; - -/** - * Abstract base class for {@link InstanceKey} which represents at least some {@link IClass} in some {@link CGNode} - */ -public abstract class AbstractTypeInNode implements InstanceKeyWithNode { - private final IClass type; - - private final CGNode node; - - public AbstractTypeInNode(CGNode node, IClass type) { - if (node == null) { - throw new IllegalArgumentException("null node"); - } - if (type != null && type.isInterface()) { - Assertions.UNREACHABLE("unexpected type: " + type); - } - this.node = node; - this.type = type; - } - - @Override - public abstract boolean equals(Object obj); - - @Override - public abstract int hashCode(); - - @Override - public abstract String toString(); - - /** - * @return the concrete type allocated - */ - public IClass getConcreteType() { - return type; - } - - /** - * @return the call graph node which contains this allocation - */ - public CGNode getNode() { - return node; - } - -} +/******************************************************************************* + * 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.ipa.callgraph.propagation; + +import com.ibm.wala.analysis.reflection.InstanceKeyWithNode; +import com.ibm.wala.classLoader.IClass; +import com.ibm.wala.ipa.callgraph.CGNode; +import com.ibm.wala.util.debug.Assertions; + +/** + * Abstract base class for {@link InstanceKey} which represents at least some {@link IClass} in some {@link CGNode} + */ +public abstract class AbstractTypeInNode implements InstanceKeyWithNode { + private final IClass type; + + private final CGNode node; + + public AbstractTypeInNode(CGNode node, IClass type) { + if (node == null) { + throw new IllegalArgumentException("null node"); + } + if (type != null && type.isInterface()) { + Assertions.UNREACHABLE("unexpected type: " + type); + } + this.node = node; + this.type = type; + } + + @Override + public abstract boolean equals(Object obj); + + @Override + public abstract int hashCode(); + + @Override + public abstract String toString(); + + /** + * @return the concrete type allocated + */ + public IClass getConcreteType() { + return type; + } + + /** + * @return the call graph node which contains this allocation + */ + public CGNode getNode() { + return node; + } + +} diff --git a/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/AllocationSite.java b/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/AllocationSite.java index e344b9230..967c1e561 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/AllocationSite.java +++ b/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/AllocationSite.java @@ -1,84 +1,84 @@ -/******************************************************************************* - * Copyright (c) 2002 - 2006 IBM Corporation. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * IBM Corporation - initial API and implementation - *******************************************************************************/ -package com.ibm.wala.ipa.callgraph.propagation; - -import com.ibm.wala.classLoader.IClass; -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; - -/** - * An {@link InstanceKey} which represents a {@link NewSiteReference} in some {@link IMethod}. Note that this differs from - * {@link AllocationSiteInNode}, which represents an allocation in a {@link CGNode} that may carry some {@link Context}. This type - * is useful for a context-insensitive heap abstraction. - */ -public class AllocationSite implements InstanceKey { - private final NewSiteReference site; - - private final IMethod method; - - private final IClass concreteType; - - public AllocationSite(IMethod method, NewSiteReference allocation, IClass type) { - this.site = allocation; - this.method = method; - this.concreteType = type; - } - - @Override - public String toString() { - return "SITE{" + getMethod() + ":" + site + "}"; - } - - public NewSiteReference getSite() { - return site; - } - - public IMethod getMethod() { - return method; - } - - public IClass getConcreteType() { - return concreteType; - } - - @Override - public int hashCode() { - final int prime = 31; - int result = 1; - result = prime * result + ((method == null) ? 0 : method.hashCode()); - result = prime * result + ((site == null) ? 0 : site.hashCode()); - return result; - } - - @Override - public boolean equals(Object obj) { - if (this == obj) - return true; - if (obj == null) - return false; - if (getClass() != obj.getClass()) - return false; - final AllocationSite other = (AllocationSite) obj; - if (method == null) { - if (other.method != null) - return false; - } else if (!method.equals(other.method)) - return false; - if (site == null) { - if (other.site != null) - return false; - } else if (!site.equals(other.site)) - return false; - return true; - } -} +/******************************************************************************* + * 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.ipa.callgraph.propagation; + +import com.ibm.wala.classLoader.IClass; +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; + +/** + * An {@link InstanceKey} which represents a {@link NewSiteReference} in some {@link IMethod}. Note that this differs from + * {@link AllocationSiteInNode}, which represents an allocation in a {@link CGNode} that may carry some {@link Context}. This type + * is useful for a context-insensitive heap abstraction. + */ +public class AllocationSite implements InstanceKey { + private final NewSiteReference site; + + private final IMethod method; + + private final IClass concreteType; + + public AllocationSite(IMethod method, NewSiteReference allocation, IClass type) { + this.site = allocation; + this.method = method; + this.concreteType = type; + } + + @Override + public String toString() { + return "SITE{" + getMethod() + ":" + site + "}"; + } + + public NewSiteReference getSite() { + return site; + } + + public IMethod getMethod() { + return method; + } + + public IClass getConcreteType() { + return concreteType; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((method == null) ? 0 : method.hashCode()); + result = prime * result + ((site == null) ? 0 : site.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + final AllocationSite other = (AllocationSite) obj; + if (method == null) { + if (other.method != null) + return false; + } else if (!method.equals(other.method)) + return false; + if (site == null) { + if (other.site != null) + return false; + } else if (!site.equals(other.site)) + return false; + return true; + } +} diff --git a/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/AllocationSiteInNode.java b/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/AllocationSiteInNode.java index f2a302c10..50ba623e0 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/AllocationSiteInNode.java +++ b/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/AllocationSiteInNode.java @@ -1,45 +1,45 @@ -/******************************************************************************* - * Copyright (c) 2002 - 2006 IBM Corporation. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * IBM Corporation - initial API and implementation - *******************************************************************************/ -package com.ibm.wala.ipa.callgraph.propagation; - -import com.ibm.wala.classLoader.IClass; -import com.ibm.wala.classLoader.NewSiteReference; -import com.ibm.wala.ipa.callgraph.CGNode; - -/** - * An {@link InstanceKey} which represents a {@link NewSiteReference} in some {@link CGNode}. - */ -public abstract class AllocationSiteInNode extends AbstractTypeInNode { - private final NewSiteReference site; - - public AllocationSiteInNode(CGNode node, NewSiteReference allocation, IClass type) { - super(node, type); - this.site = allocation; - } - - @Override - public abstract boolean equals(Object obj); - - @Override - public abstract int hashCode(); - - @Override - public String toString() { - return "SITE_IN_NODE{" + getNode().getMethod() + ":" + site + " in " + getNode().getContext() + "}"; - } - - /** - * @return Returns the site. - */ - public NewSiteReference getSite() { - return site; - } -} +/******************************************************************************* + * 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.ipa.callgraph.propagation; + +import com.ibm.wala.classLoader.IClass; +import com.ibm.wala.classLoader.NewSiteReference; +import com.ibm.wala.ipa.callgraph.CGNode; + +/** + * An {@link InstanceKey} which represents a {@link NewSiteReference} in some {@link CGNode}. + */ +public abstract class AllocationSiteInNode extends AbstractTypeInNode { + private final NewSiteReference site; + + public AllocationSiteInNode(CGNode node, NewSiteReference allocation, IClass type) { + super(node, type); + this.site = allocation; + } + + @Override + public abstract boolean equals(Object obj); + + @Override + public abstract int hashCode(); + + @Override + public String toString() { + return "SITE_IN_NODE{" + getNode().getMethod() + ":" + site + " in " + getNode().getContext() + "}"; + } + + /** + * @return Returns the site. + */ + public NewSiteReference getSite() { + return site; + } +} diff --git a/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/AllocationSiteInNodeFactory.java b/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/AllocationSiteInNodeFactory.java index 7257d4cc7..58946c82f 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/AllocationSiteInNodeFactory.java +++ b/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/AllocationSiteInNodeFactory.java @@ -1,123 +1,123 @@ -/******************************************************************************* - * 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.ipa.callgraph.propagation; - -import com.ibm.wala.classLoader.ArrayClass; -import com.ibm.wala.classLoader.IClass; -import com.ibm.wala.classLoader.IMethod; -import com.ibm.wala.classLoader.NewSiteReference; -import com.ibm.wala.classLoader.ProgramCounter; -import com.ibm.wala.ipa.callgraph.AnalysisOptions; -import com.ibm.wala.ipa.callgraph.CGNode; -import com.ibm.wala.ipa.callgraph.propagation.cfa.CallerContext; -import com.ibm.wala.ipa.callgraph.propagation.cfa.ContainerContextSelector; -import com.ibm.wala.ipa.cha.IClassHierarchy; -import com.ibm.wala.ssa.IR; -import com.ibm.wala.ssa.SSANewInstruction; -import com.ibm.wala.types.TypeReference; - -/** - * A factory which tries by default to create {@link InstanceKey}s which are {@link AllocationSiteInNode}s. - * - * Notes: - *
          - *
        • This class checks to avoid creating recursive contexts when {@link CGNode}s are based on {@link ReceiverInstanceContext}, as - * in object-sensitivity. - *
        • Up till recursion, this class will happily create unlimited object sensitivity, so be careful. - *
        • This class resorts to {@link ClassBasedInstanceKeys} for exceptions from PEIs and class objects. - *
        • This class consults the {@link AnalysisOptions} to determine whether to disambiguate individual constants. - *
        - */ -public class AllocationSiteInNodeFactory implements InstanceKeyFactory { - - /** - * Governing call graph construction options - */ - private final AnalysisOptions options; - - /** - * Governing class hierarchy - */ - private final IClassHierarchy cha; - - private final ClassBasedInstanceKeys classBased; - - /** - * @param options Governing call graph construction options - */ - public AllocationSiteInNodeFactory(AnalysisOptions options, IClassHierarchy cha) { - this.options = options; - this.cha = cha; - this.classBased = new ClassBasedInstanceKeys(options, cha); - } - - public InstanceKey getInstanceKeyForAllocation(CGNode node, NewSiteReference allocation) { - IClass type = options.getClassTargetSelector().getAllocatedTarget(node, allocation); - if (type == null) { - return null; - } - - CGNode nodeToUse = node; - - // disallow recursion in contexts. - if (node.getContext() instanceof ReceiverInstanceContext || node.getContext() instanceof CallerContext) { - IMethod m = node.getMethod(); - CGNode n = ContainerContextSelector.findNodeRecursiveMatchingContext(m, node.getContext()); - if (n != null) { - nodeToUse = n; - } - } - - if (type.isArrayClass()) { - // special case for arrays with zero length in their first dimension - IR ir = node.getIR(); - SSANewInstruction newInstruction = ir.getNew(allocation); - int lengthVN = newInstruction.getUse(0); - if (ir.getSymbolTable().isIntegerConstant(lengthVN)) { - Integer c = (Integer) ir.getSymbolTable().getConstantValue(lengthVN); - if (c.intValue() == 0) { - return new ZeroLengthArrayInNode(nodeToUse, allocation, type); - } - } - } - - InstanceKey key = new NormalAllocationInNode(nodeToUse, allocation, type); - - return key; - } - - public InstanceKey getInstanceKeyForMultiNewArray(CGNode node, NewSiteReference allocation, int dim) { - ArrayClass type = (ArrayClass) options.getClassTargetSelector().getAllocatedTarget(node, allocation); - if (type == null) { - return null; - } - InstanceKey key = new MultiNewArrayInNode(node, allocation, type, dim); - - return key; - } - - public InstanceKey getInstanceKeyForConstant(TypeReference type, T S) { - if (options.getUseConstantSpecificKeys()) { - return new ConstantKey(S, cha.lookupClass(type)); - } else { - return new ConcreteTypeKey(cha.lookupClass(type)); - } - } - - public InstanceKey getInstanceKeyForPEI(CGNode node, ProgramCounter pei, TypeReference type) { - return classBased.getInstanceKeyForPEI(node, pei, type); - } - - public InstanceKey getInstanceKeyForClassObject(TypeReference type) { - return classBased.getInstanceKeyForClassObject(type); - } - -} +/******************************************************************************* + * 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.ipa.callgraph.propagation; + +import com.ibm.wala.classLoader.ArrayClass; +import com.ibm.wala.classLoader.IClass; +import com.ibm.wala.classLoader.IMethod; +import com.ibm.wala.classLoader.NewSiteReference; +import com.ibm.wala.classLoader.ProgramCounter; +import com.ibm.wala.ipa.callgraph.AnalysisOptions; +import com.ibm.wala.ipa.callgraph.CGNode; +import com.ibm.wala.ipa.callgraph.propagation.cfa.CallerContext; +import com.ibm.wala.ipa.callgraph.propagation.cfa.ContainerContextSelector; +import com.ibm.wala.ipa.cha.IClassHierarchy; +import com.ibm.wala.ssa.IR; +import com.ibm.wala.ssa.SSANewInstruction; +import com.ibm.wala.types.TypeReference; + +/** + * A factory which tries by default to create {@link InstanceKey}s which are {@link AllocationSiteInNode}s. + * + * Notes: + *
          + *
        • This class checks to avoid creating recursive contexts when {@link CGNode}s are based on {@link ReceiverInstanceContext}, as + * in object-sensitivity. + *
        • Up till recursion, this class will happily create unlimited object sensitivity, so be careful. + *
        • This class resorts to {@link ClassBasedInstanceKeys} for exceptions from PEIs and class objects. + *
        • This class consults the {@link AnalysisOptions} to determine whether to disambiguate individual constants. + *
        + */ +public class AllocationSiteInNodeFactory implements InstanceKeyFactory { + + /** + * Governing call graph construction options + */ + private final AnalysisOptions options; + + /** + * Governing class hierarchy + */ + private final IClassHierarchy cha; + + private final ClassBasedInstanceKeys classBased; + + /** + * @param options Governing call graph construction options + */ + public AllocationSiteInNodeFactory(AnalysisOptions options, IClassHierarchy cha) { + this.options = options; + this.cha = cha; + this.classBased = new ClassBasedInstanceKeys(options, cha); + } + + public InstanceKey getInstanceKeyForAllocation(CGNode node, NewSiteReference allocation) { + IClass type = options.getClassTargetSelector().getAllocatedTarget(node, allocation); + if (type == null) { + return null; + } + + CGNode nodeToUse = node; + + // disallow recursion in contexts. + if (node.getContext() instanceof ReceiverInstanceContext || node.getContext() instanceof CallerContext) { + IMethod m = node.getMethod(); + CGNode n = ContainerContextSelector.findNodeRecursiveMatchingContext(m, node.getContext()); + if (n != null) { + nodeToUse = n; + } + } + + if (type.isArrayClass()) { + // special case for arrays with zero length in their first dimension + IR ir = node.getIR(); + SSANewInstruction newInstruction = ir.getNew(allocation); + int lengthVN = newInstruction.getUse(0); + if (ir.getSymbolTable().isIntegerConstant(lengthVN)) { + Integer c = (Integer) ir.getSymbolTable().getConstantValue(lengthVN); + if (c.intValue() == 0) { + return new ZeroLengthArrayInNode(nodeToUse, allocation, type); + } + } + } + + InstanceKey key = new NormalAllocationInNode(nodeToUse, allocation, type); + + return key; + } + + public InstanceKey getInstanceKeyForMultiNewArray(CGNode node, NewSiteReference allocation, int dim) { + ArrayClass type = (ArrayClass) options.getClassTargetSelector().getAllocatedTarget(node, allocation); + if (type == null) { + return null; + } + InstanceKey key = new MultiNewArrayInNode(node, allocation, type, dim); + + return key; + } + + public InstanceKey getInstanceKeyForConstant(TypeReference type, T S) { + if (options.getUseConstantSpecificKeys()) { + return new ConstantKey(S, cha.lookupClass(type)); + } else { + return new ConcreteTypeKey(cha.lookupClass(type)); + } + } + + public InstanceKey getInstanceKeyForPEI(CGNode node, ProgramCounter pei, TypeReference type) { + return classBased.getInstanceKeyForPEI(node, pei, type); + } + + public InstanceKey getInstanceKeyForClassObject(TypeReference type) { + return classBased.getInstanceKeyForClassObject(type); + } + +} diff --git a/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/ArrayContentsKey.java b/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/ArrayContentsKey.java index e0b563de4..b7a008054 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/ArrayContentsKey.java +++ b/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/ArrayContentsKey.java @@ -1,49 +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.ipa.callgraph.propagation; - -import com.ibm.wala.classLoader.ArrayClass; - -/** - * A {@link PointerKey} which represents the contents of an array instance. - */ -public final class ArrayContentsKey extends AbstractFieldPointerKey implements FilteredPointerKey { - public ArrayContentsKey(InstanceKey instance) { - super(instance); - } - - @Override - public boolean equals(Object obj) { - if (obj instanceof ArrayContentsKey) { - ArrayContentsKey other = (ArrayContentsKey) obj; - return instance.equals(other.instance); - } else { - return false; - } - } - - @Override - public int hashCode() { - return 1061 * instance.hashCode(); - } - - @Override - public String toString() { - return "[" + instance + "[]]"; - } - - /* - * @see com.ibm.wala.ipa.callgraph.propagation.PointerKey#getTypeFilter() - */ - public TypeFilter getTypeFilter() { - return new SingleClassFilter(((ArrayClass) instance.getConcreteType()).getElementClass()); - } -} +/******************************************************************************* + * 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.ipa.callgraph.propagation; + +import com.ibm.wala.classLoader.ArrayClass; + +/** + * A {@link PointerKey} which represents the contents of an array instance. + */ +public final class ArrayContentsKey extends AbstractFieldPointerKey implements FilteredPointerKey { + public ArrayContentsKey(InstanceKey instance) { + super(instance); + } + + @Override + public boolean equals(Object obj) { + if (obj instanceof ArrayContentsKey) { + ArrayContentsKey other = (ArrayContentsKey) obj; + return instance.equals(other.instance); + } else { + return false; + } + } + + @Override + public int hashCode() { + return 1061 * instance.hashCode(); + } + + @Override + public String toString() { + return "[" + instance + "[]]"; + } + + /* + * @see com.ibm.wala.ipa.callgraph.propagation.PointerKey#getTypeFilter() + */ + public TypeFilter getTypeFilter() { + return new SingleClassFilter(((ArrayClass) instance.getConcreteType()).getElementClass()); + } +} diff --git a/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/AssignEquation.java b/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/AssignEquation.java index 4521f6d45..7ef83746e 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/AssignEquation.java +++ b/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/AssignEquation.java @@ -1,39 +1,39 @@ -/******************************************************************************* - * Copyright (c) 2002 - 2006 IBM Corporation. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * IBM Corporation - initial API and implementation - *******************************************************************************/ -package com.ibm.wala.ipa.callgraph.propagation; - -import com.ibm.wala.fixpoint.UnaryOperator; -import com.ibm.wala.fixpoint.UnaryStatement; - -/** - * A specialized equation class introduced for efficiency - */ -public final class AssignEquation extends UnaryStatement { - - AssignEquation(PointsToSetVariable lhs, PointsToSetVariable rhs) { - super(lhs, rhs); - } - - @Override - public UnaryOperator getOperator() { - return PropagationCallGraphBuilder.assignOperator; - } - - @Override - public boolean equals(Object o) { - if (o instanceof AssignEquation) { - AssignEquation other = (AssignEquation) o; - return getLHS().equals(other.getLHS()) && getRightHandSide().equals(other.getRightHandSide()); - } else { - return false; - } - } -} +/******************************************************************************* + * 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.ipa.callgraph.propagation; + +import com.ibm.wala.fixpoint.UnaryOperator; +import com.ibm.wala.fixpoint.UnaryStatement; + +/** + * A specialized equation class introduced for efficiency + */ +public final class AssignEquation extends UnaryStatement { + + AssignEquation(PointsToSetVariable lhs, PointsToSetVariable rhs) { + super(lhs, rhs); + } + + @Override + public UnaryOperator getOperator() { + return PropagationCallGraphBuilder.assignOperator; + } + + @Override + public boolean equals(Object o) { + if (o instanceof AssignEquation) { + AssignEquation other = (AssignEquation) o; + return getLHS().equals(other.getLHS()) && getRightHandSide().equals(other.getRightHandSide()); + } else { + return false; + } + } +} diff --git a/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/AssignOperator.java b/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/AssignOperator.java index f7f1c3ede..1abe64319 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/AssignOperator.java +++ b/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/AssignOperator.java @@ -1,69 +1,69 @@ -/******************************************************************************* - * Copyright (c) 2002 - 2006 IBM Corporation. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * IBM Corporation - initial API and implementation - *******************************************************************************/ -package com.ibm.wala.ipa.callgraph.propagation; - -import com.ibm.wala.fixpoint.UnaryOperator; -import com.ibm.wala.fixpoint.UnaryStatement; - -/** - * Corresponds to: "is a superset of". Used for assignment. - * - * Unary op: := Assign( ) - * - * (Technically, it's a binary op, since it includes lhs as an implicit input; this allows it to compose with other ops that define - * the same lhs, so long as they're all Assign ops) - */ -class AssignOperator extends UnaryOperator implements IPointerOperator { - - @Override - public UnaryStatement makeEquation(PointsToSetVariable lhs, PointsToSetVariable rhs) { - return new AssignEquation(lhs, rhs); - } - - @Override - public byte evaluate(PointsToSetVariable lhs, PointsToSetVariable rhs) { - - if (PropagationCallGraphBuilder.DEBUG_ASSIGN) { - String S = "EVAL Assign " + lhs.getPointerKey() + " " + rhs.getPointerKey(); - S = S + "\nEVAL " + lhs + " " + rhs; - System.err.println(S); - } - boolean changed = lhs.addAll(rhs); - if (PropagationCallGraphBuilder.DEBUG_ASSIGN) { - System.err.println("RESULT " + lhs + (changed ? " (changed)" : "")); - } - - return changed ? CHANGED : NOT_CHANGED; - } - - @Override - public String toString() { - return "Assign"; - } - - @Override - public int hashCode() { - return 9883; - } - - @Override - public final boolean equals(Object o) { - // this is a singleton - return (this == o); - } - - /* - * @see com.ibm.wala.ipa.callgraph.propagation.IPointerOperator#isComplex() - */ - public boolean isComplex() { - return false; - } +/******************************************************************************* + * 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.ipa.callgraph.propagation; + +import com.ibm.wala.fixpoint.UnaryOperator; +import com.ibm.wala.fixpoint.UnaryStatement; + +/** + * Corresponds to: "is a superset of". Used for assignment. + * + * Unary op: := Assign( ) + * + * (Technically, it's a binary op, since it includes lhs as an implicit input; this allows it to compose with other ops that define + * the same lhs, so long as they're all Assign ops) + */ +class AssignOperator extends UnaryOperator implements IPointerOperator { + + @Override + public UnaryStatement makeEquation(PointsToSetVariable lhs, PointsToSetVariable rhs) { + return new AssignEquation(lhs, rhs); + } + + @Override + public byte evaluate(PointsToSetVariable lhs, PointsToSetVariable rhs) { + + if (PropagationCallGraphBuilder.DEBUG_ASSIGN) { + String S = "EVAL Assign " + lhs.getPointerKey() + " " + rhs.getPointerKey(); + S = S + "\nEVAL " + lhs + " " + rhs; + System.err.println(S); + } + boolean changed = lhs.addAll(rhs); + if (PropagationCallGraphBuilder.DEBUG_ASSIGN) { + System.err.println("RESULT " + lhs + (changed ? " (changed)" : "")); + } + + return changed ? CHANGED : NOT_CHANGED; + } + + @Override + public String toString() { + return "Assign"; + } + + @Override + public int hashCode() { + return 9883; + } + + @Override + public final boolean equals(Object o) { + // this is a singleton + return (this == o); + } + + /* + * @see com.ibm.wala.ipa.callgraph.propagation.IPointerOperator#isComplex() + */ + public boolean isComplex() { + return false; + } } \ No newline at end of file diff --git a/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/ClassBasedInstanceKeys.java b/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/ClassBasedInstanceKeys.java index ede8fa88e..5df7c76c6 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/ClassBasedInstanceKeys.java +++ b/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/ClassBasedInstanceKeys.java @@ -1,142 +1,142 @@ -/******************************************************************************* - * Copyright (c) 2002 - 2006 IBM Corporation. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * IBM Corporation - initial API and implementation - *******************************************************************************/ -package com.ibm.wala.ipa.callgraph.propagation; - -import com.ibm.wala.classLoader.ArrayClass; -import com.ibm.wala.classLoader.IClass; -import com.ibm.wala.classLoader.NewSiteReference; -import com.ibm.wala.classLoader.ProgramCounter; -import com.ibm.wala.ipa.callgraph.AnalysisOptions; -import com.ibm.wala.ipa.callgraph.CGNode; -import com.ibm.wala.ipa.cha.IClassHierarchy; -import com.ibm.wala.types.TypeReference; -import com.ibm.wala.util.debug.Assertions; - -/** - * This class provides Instance Key call backs where each instance is in the same equivalence class as all other instances of the - * same concrete type. - */ -public class ClassBasedInstanceKeys implements InstanceKeyFactory { - - private final static boolean DEBUG = false; - - private final AnalysisOptions options; - - private final IClassHierarchy cha; - - public ClassBasedInstanceKeys(AnalysisOptions options, IClassHierarchy cha) { - if (cha == null) { - throw new IllegalArgumentException("null cha"); - } - this.cha = cha; - this.options = options; - } - - public InstanceKey getInstanceKeyForAllocation(CGNode node, NewSiteReference allocation) { - if (allocation == null) { - throw new IllegalArgumentException("allocation is null"); - } - - if (options.getClassTargetSelector() == null) { - throw new IllegalStateException("options did not specify class target selector"); - } - IClass type = options.getClassTargetSelector().getAllocatedTarget(node, allocation); - if (type == null) { - return null; - } - - ConcreteTypeKey key = new ConcreteTypeKey(type); - - return key; - } - - /** - * @see com.ibm.wala.ipa.callgraph.propagation.InstanceKeyFactory#getInstanceKeyForMultiNewArray(com.ibm.wala.ipa.callgraph.CGNode, - * com.ibm.wala.classLoader.NewSiteReference, int) dim == 0 represents the first dimension, e.g., the [Object; instances in - * [[Object; e.g., the [[Object; instances in [[[Object; dim == 1 represents the second dimension, e.g., the [Object - * instances in [[[Object; - */ - public InstanceKey getInstanceKeyForMultiNewArray(CGNode node, NewSiteReference allocation, int dim) { - if (DEBUG) { - System.err.println(("getInstanceKeyForMultiNewArray " + allocation + " " + dim)); - } - ArrayClass type = (ArrayClass) options.getClassTargetSelector().getAllocatedTarget(node, allocation); - assert (type != null); - if (DEBUG) { - System.err.println(("type: " + type)); - } - if (type == null) { - assert type != null : "null type for " + allocation; - } - int i = 0; - while (i <= dim) { - i++; - if (type == null) { - Assertions.UNREACHABLE(); - } - type = (ArrayClass) type.getElementClass(); - if (DEBUG) { - System.err.println(("intermediate: " + i + " " + type)); - } - } - if (DEBUG) { - System.err.println(("final type: " + type)); - } - if (type == null) { - return null; - } - ConcreteTypeKey key = new ConcreteTypeKey(type); - - return key; - } - - public InstanceKey getInstanceKeyForConstant(TypeReference type, T S) { - if (type == null || cha.lookupClass(type) == null) { - return null; - } else { - if (options.getUseConstantSpecificKeys()) { - return new ConstantKey(S, cha.lookupClass(type)); - } else { - return new ConcreteTypeKey(cha.lookupClass(type)); - } - } - } - - /** - * @return a set of ConcreteTypeKeys that represent the exceptions the PEI may throw. - */ - public InstanceKey getInstanceKeyForPEI(CGNode node, ProgramCounter peiLoc, TypeReference type) { - IClass klass = cha.lookupClass(type); - if (klass == null) { - return null; - } - return new ConcreteTypeKey(cha.lookupClass(type)); - } - - public InstanceKey getInstanceKeyForClassObject(TypeReference type) { - IClass klass = cha.lookupClass(type); - if (klass == null) { - return new ConcreteTypeKey(cha.lookupClass(TypeReference.JavaLangClass)); - } else { - // return the IClass itself, wrapped as a constant! - return new ConstantKey(klass, cha.lookupClass(TypeReference.JavaLangClass)); - } - - } - - /** - * @return Returns the class hierarchy. - */ - public IClassHierarchy getClassHierarchy() { - return cha; - } - -} +/******************************************************************************* + * 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.ipa.callgraph.propagation; + +import com.ibm.wala.classLoader.ArrayClass; +import com.ibm.wala.classLoader.IClass; +import com.ibm.wala.classLoader.NewSiteReference; +import com.ibm.wala.classLoader.ProgramCounter; +import com.ibm.wala.ipa.callgraph.AnalysisOptions; +import com.ibm.wala.ipa.callgraph.CGNode; +import com.ibm.wala.ipa.cha.IClassHierarchy; +import com.ibm.wala.types.TypeReference; +import com.ibm.wala.util.debug.Assertions; + +/** + * This class provides Instance Key call backs where each instance is in the same equivalence class as all other instances of the + * same concrete type. + */ +public class ClassBasedInstanceKeys implements InstanceKeyFactory { + + private final static boolean DEBUG = false; + + private final AnalysisOptions options; + + private final IClassHierarchy cha; + + public ClassBasedInstanceKeys(AnalysisOptions options, IClassHierarchy cha) { + if (cha == null) { + throw new IllegalArgumentException("null cha"); + } + this.cha = cha; + this.options = options; + } + + public InstanceKey getInstanceKeyForAllocation(CGNode node, NewSiteReference allocation) { + if (allocation == null) { + throw new IllegalArgumentException("allocation is null"); + } + + if (options.getClassTargetSelector() == null) { + throw new IllegalStateException("options did not specify class target selector"); + } + IClass type = options.getClassTargetSelector().getAllocatedTarget(node, allocation); + if (type == null) { + return null; + } + + ConcreteTypeKey key = new ConcreteTypeKey(type); + + return key; + } + + /** + * @see com.ibm.wala.ipa.callgraph.propagation.InstanceKeyFactory#getInstanceKeyForMultiNewArray(com.ibm.wala.ipa.callgraph.CGNode, + * com.ibm.wala.classLoader.NewSiteReference, int) dim == 0 represents the first dimension, e.g., the [Object; instances in + * [[Object; e.g., the [[Object; instances in [[[Object; dim == 1 represents the second dimension, e.g., the [Object + * instances in [[[Object; + */ + public InstanceKey getInstanceKeyForMultiNewArray(CGNode node, NewSiteReference allocation, int dim) { + if (DEBUG) { + System.err.println(("getInstanceKeyForMultiNewArray " + allocation + " " + dim)); + } + ArrayClass type = (ArrayClass) options.getClassTargetSelector().getAllocatedTarget(node, allocation); + assert (type != null); + if (DEBUG) { + System.err.println(("type: " + type)); + } + if (type == null) { + assert type != null : "null type for " + allocation; + } + int i = 0; + while (i <= dim) { + i++; + if (type == null) { + Assertions.UNREACHABLE(); + } + type = (ArrayClass) type.getElementClass(); + if (DEBUG) { + System.err.println(("intermediate: " + i + " " + type)); + } + } + if (DEBUG) { + System.err.println(("final type: " + type)); + } + if (type == null) { + return null; + } + ConcreteTypeKey key = new ConcreteTypeKey(type); + + return key; + } + + public InstanceKey getInstanceKeyForConstant(TypeReference type, T S) { + if (type == null || cha.lookupClass(type) == null) { + return null; + } else { + if (options.getUseConstantSpecificKeys()) { + return new ConstantKey(S, cha.lookupClass(type)); + } else { + return new ConcreteTypeKey(cha.lookupClass(type)); + } + } + } + + /** + * @return a set of ConcreteTypeKeys that represent the exceptions the PEI may throw. + */ + public InstanceKey getInstanceKeyForPEI(CGNode node, ProgramCounter peiLoc, TypeReference type) { + IClass klass = cha.lookupClass(type); + if (klass == null) { + return null; + } + return new ConcreteTypeKey(cha.lookupClass(type)); + } + + public InstanceKey getInstanceKeyForClassObject(TypeReference type) { + IClass klass = cha.lookupClass(type); + if (klass == null) { + return new ConcreteTypeKey(cha.lookupClass(TypeReference.JavaLangClass)); + } else { + // return the IClass itself, wrapped as a constant! + return new ConstantKey(klass, cha.lookupClass(TypeReference.JavaLangClass)); + } + + } + + /** + * @return Returns the class hierarchy. + */ + public IClassHierarchy getClassHierarchy() { + return cha; + } + +} diff --git a/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/CloneContextSelector.java b/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/CloneContextSelector.java index 7b4a9339b..55e5709a0 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/CloneContextSelector.java +++ b/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/CloneContextSelector.java @@ -1,59 +1,59 @@ -/******************************************************************************* - * 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.ipa.callgraph.propagation; - -import com.ibm.wala.analysis.reflection.CloneInterpreter; -import com.ibm.wala.classLoader.CallSiteReference; -import com.ibm.wala.classLoader.IMethod; -import com.ibm.wala.ipa.callgraph.CGNode; -import com.ibm.wala.ipa.callgraph.Context; -import com.ibm.wala.ipa.callgraph.ContextSelector; -import com.ibm.wala.ipa.cha.IClassHierarchy; -import com.ibm.wala.util.intset.EmptyIntSet; -import com.ibm.wala.util.intset.IntSet; - -/** - * This context selector selects a context based on the concrete type of - * the receiver to a call of java.lang.Object.clone - */ -public class CloneContextSelector implements ContextSelector { - - private final ReceiverTypeContextSelector selector; - - private final IClassHierarchy cha; - - public CloneContextSelector(IClassHierarchy cha) { - this.selector = new ReceiverTypeContextSelector(); - this.cha = cha; - } - - public Context getCalleeTarget(CGNode caller, CallSiteReference site, IMethod callee, InstanceKey[] receiver) { - if (receiver == null) { - return null; - } - if (callee.getReference().equals(CloneInterpreter.CLONE)) { - return selector.getCalleeTarget(caller,site,callee,receiver); - } else { - return null; - } - } - - public IntSet getRelevantParameters(CGNode caller, CallSiteReference site) { - IMethod declaredTarget = cha.resolveMethod(site.getDeclaredTarget()); - if (declaredTarget != null && declaredTarget.getReference().equals(CloneInterpreter.CLONE)) { - return selector.getRelevantParameters(caller, site); - } else { - return EmptyIntSet.instance; - } - } - - -} +/******************************************************************************* + * 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.ipa.callgraph.propagation; + +import com.ibm.wala.analysis.reflection.CloneInterpreter; +import com.ibm.wala.classLoader.CallSiteReference; +import com.ibm.wala.classLoader.IMethod; +import com.ibm.wala.ipa.callgraph.CGNode; +import com.ibm.wala.ipa.callgraph.Context; +import com.ibm.wala.ipa.callgraph.ContextSelector; +import com.ibm.wala.ipa.cha.IClassHierarchy; +import com.ibm.wala.util.intset.EmptyIntSet; +import com.ibm.wala.util.intset.IntSet; + +/** + * This context selector selects a context based on the concrete type of + * the receiver to a call of java.lang.Object.clone + */ +public class CloneContextSelector implements ContextSelector { + + private final ReceiverTypeContextSelector selector; + + private final IClassHierarchy cha; + + public CloneContextSelector(IClassHierarchy cha) { + this.selector = new ReceiverTypeContextSelector(); + this.cha = cha; + } + + public Context getCalleeTarget(CGNode caller, CallSiteReference site, IMethod callee, InstanceKey[] receiver) { + if (receiver == null) { + return null; + } + if (callee.getReference().equals(CloneInterpreter.CLONE)) { + return selector.getCalleeTarget(caller,site,callee,receiver); + } else { + return null; + } + } + + public IntSet getRelevantParameters(CGNode caller, CallSiteReference site) { + IMethod declaredTarget = cha.resolveMethod(site.getDeclaredTarget()); + if (declaredTarget != null && declaredTarget.getReference().equals(CloneInterpreter.CLONE)) { + return selector.getRelevantParameters(caller, site); + } else { + return EmptyIntSet.instance; + } + } + + +} diff --git a/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/ConcreteTypeKey.java b/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/ConcreteTypeKey.java index d3e0b6569..8c41fad67 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/ConcreteTypeKey.java +++ b/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/ConcreteTypeKey.java @@ -1,95 +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.ipa.callgraph.propagation; - -import java.util.Collection; -import java.util.Iterator; - -import com.ibm.wala.classLoader.IClass; -import com.ibm.wala.ipa.cha.IClassHierarchy; -import com.ibm.wala.ssa.IR; -import com.ibm.wala.ssa.SSAInstruction; -import com.ibm.wala.types.TypeReference; -import com.ibm.wala.util.debug.Assertions; - -/** - * An instance key which represents a unique set for each concrete type - */ -public final class ConcreteTypeKey implements InstanceKey { - private final IClass type; - - public ConcreteTypeKey(IClass type) { - if (type == null) { - throw new IllegalArgumentException("type is null"); - } - if (type.isInterface()) { - Assertions.UNREACHABLE("unexpected interface: " + type); - } - this.type = type; - } - - @Override - public boolean equals(Object obj) { - if (obj instanceof ConcreteTypeKey) { - ConcreteTypeKey other = (ConcreteTypeKey) obj; - return type.equals(other.type); - } else { - return false; - } - } - - @Override - public int hashCode() { - return 461 * type.hashCode(); - } - - @Override - public String toString() { - return "[" + type + "]"; - } - - public IClass getType() { - return type; - } - - /* - * @see com.ibm.wala.ipa.callgraph.propagation.InstanceKey#getConcreteType() - */ - public IClass getConcreteType() { - return type; - } - - /** - * @param pei a PEI instruction - * @param cha governing class hierarchy - * @return a set of ConcreteTypeKeys that represent the exceptions the PEI may throw. - * @throws IllegalArgumentException if pei is null - */ - public static InstanceKey[] getInstanceKeysForPEI(SSAInstruction pei, IR ir, IClassHierarchy cha) { - if (pei == null) { - throw new IllegalArgumentException("pei is null"); - } - Collection types = pei.getExceptionTypes(); - // TODO: institute a cache? - if (types == null) { - return null; - } - InstanceKey[] result = new InstanceKey[types.size()]; - int i = 0; - for (Iterator it = types.iterator(); it.hasNext();) { - TypeReference type = (TypeReference) it.next(); - assert type != null; - IClass klass = cha.lookupClass(type); - result[i++] = new ConcreteTypeKey(klass); - } - return result; - } +/******************************************************************************* + * 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.ipa.callgraph.propagation; + +import java.util.Collection; +import java.util.Iterator; + +import com.ibm.wala.classLoader.IClass; +import com.ibm.wala.ipa.cha.IClassHierarchy; +import com.ibm.wala.ssa.IR; +import com.ibm.wala.ssa.SSAInstruction; +import com.ibm.wala.types.TypeReference; +import com.ibm.wala.util.debug.Assertions; + +/** + * An instance key which represents a unique set for each concrete type + */ +public final class ConcreteTypeKey implements InstanceKey { + private final IClass type; + + public ConcreteTypeKey(IClass type) { + if (type == null) { + throw new IllegalArgumentException("type is null"); + } + if (type.isInterface()) { + Assertions.UNREACHABLE("unexpected interface: " + type); + } + this.type = type; + } + + @Override + public boolean equals(Object obj) { + if (obj instanceof ConcreteTypeKey) { + ConcreteTypeKey other = (ConcreteTypeKey) obj; + return type.equals(other.type); + } else { + return false; + } + } + + @Override + public int hashCode() { + return 461 * type.hashCode(); + } + + @Override + public String toString() { + return "[" + type + "]"; + } + + public IClass getType() { + return type; + } + + /* + * @see com.ibm.wala.ipa.callgraph.propagation.InstanceKey#getConcreteType() + */ + public IClass getConcreteType() { + return type; + } + + /** + * @param pei a PEI instruction + * @param cha governing class hierarchy + * @return a set of ConcreteTypeKeys that represent the exceptions the PEI may throw. + * @throws IllegalArgumentException if pei is null + */ + public static InstanceKey[] getInstanceKeysForPEI(SSAInstruction pei, IR ir, IClassHierarchy cha) { + if (pei == null) { + throw new IllegalArgumentException("pei is null"); + } + Collection types = pei.getExceptionTypes(); + // TODO: institute a cache? + if (types == null) { + return null; + } + InstanceKey[] result = new InstanceKey[types.size()]; + int i = 0; + for (Iterator it = types.iterator(); it.hasNext();) { + TypeReference type = (TypeReference) it.next(); + assert type != null; + IClass klass = cha.lookupClass(type); + result[i++] = new ConcreteTypeKey(klass); + } + return result; + } } \ No newline at end of file diff --git a/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/ConstantKey.java b/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/ConstantKey.java index 70e9b3868..a43232220 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/ConstantKey.java +++ b/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/ConstantKey.java @@ -1,61 +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.ipa.callgraph.propagation; - -import com.ibm.wala.classLoader.IClass; - -/** - * An instance key which represents a unique, constant object - */ -public final class ConstantKey implements InstanceKey { - private final T value; - - private final IClass valueClass; - - public ConstantKey(T value, IClass valueClass) { - this.value = value; - this.valueClass = valueClass; - } - - @Override - public boolean equals(Object obj) { - if (obj instanceof ConstantKey) { - ConstantKey other = (ConstantKey) obj; - return value == null ? other.value == null : value.equals(other.value); - } else { - return false; - } - } - - @Override - public int hashCode() { - return value == null ? 65535 : 1877 * value.hashCode(); - } - - @Override - public String toString() { - if (value == null) - return "[ConstantKey:null]"; - else - return "[ConstantKey:" + value + ":" + value.getClass() + "]"; - } - - /* - * @see com.ibm.wala.ipa.callgraph.propagation.InstanceKey#getConcreteType() - */ - public IClass getConcreteType() { - return valueClass; - } - - public T getValue() { - return value; - } -} +/******************************************************************************* + * 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.ipa.callgraph.propagation; + +import com.ibm.wala.classLoader.IClass; + +/** + * An instance key which represents a unique, constant object + */ +public final class ConstantKey implements InstanceKey { + private final T value; + + private final IClass valueClass; + + public ConstantKey(T value, IClass valueClass) { + this.value = value; + this.valueClass = valueClass; + } + + @Override + public boolean equals(Object obj) { + if (obj instanceof ConstantKey) { + ConstantKey other = (ConstantKey) obj; + return value == null ? other.value == null : value.equals(other.value); + } else { + return false; + } + } + + @Override + public int hashCode() { + return value == null ? 65535 : 1877 * value.hashCode(); + } + + @Override + public String toString() { + if (value == null) + return "[ConstantKey:null]"; + else + return "[ConstantKey:" + value + ":" + value.getClass() + "]"; + } + + /* + * @see com.ibm.wala.ipa.callgraph.propagation.InstanceKey#getConcreteType() + */ + public IClass getConcreteType() { + return valueClass; + } + + public T getValue() { + return value; + } +} diff --git a/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/ContainerUtil.java b/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/ContainerUtil.java index 5ae0edf91..662c82555 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/ContainerUtil.java +++ b/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/ContainerUtil.java @@ -1,77 +1,77 @@ -/******************************************************************************* - * Copyright (c) 2002 - 2006 IBM Corporation. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * IBM Corporation - initial API and implementation - *******************************************************************************/ -package com.ibm.wala.ipa.callgraph.propagation; - -import java.util.Collection; - -import com.ibm.wala.classLoader.ArrayClass; -import com.ibm.wala.classLoader.IClass; -import com.ibm.wala.types.ClassLoaderReference; -import com.ibm.wala.types.TypeName; -import com.ibm.wala.types.TypeReference; -import com.ibm.wala.util.collections.HashSetFactory; - -/** - * Utilities for container class analysis - */ -public class ContainerUtil { - - private final static TypeName FreezableListName = TypeName.string2TypeName("Lcom/sun/corba/se/internal/ior/FreezableList"); - - public final static TypeReference FreezableList = TypeReference.findOrCreate(ClassLoaderReference.Primordial, FreezableListName); - - private final static TypeName JarAttributesName = TypeName.string2TypeName("Ljava/util/jar/Attributes"); - - public final static TypeReference JarAttributes = TypeReference.findOrCreate(ClassLoaderReference.Primordial, JarAttributesName); - - private final static Collection miscContainers = HashSetFactory.make(); - static { - miscContainers.add(FreezableList); - miscContainers.add(JarAttributes); - } - - /** - * @return true iff C is a container class from java.util - * @throws IllegalArgumentException if C is null - */ - public static boolean isContainer(IClass c) { - if (c == null) { - throw new IllegalArgumentException("c is null"); - } - if (ClassLoaderReference.Primordial.equals(c.getClassLoader().getReference()) - && TypeReference.JavaUtilCollection.getName().getPackage().equals(c.getReference().getName().getPackage())) { - IClass collection = c.getClassHierarchy().lookupClass(TypeReference.JavaUtilCollection); - IClass map = c.getClassHierarchy().lookupClass(TypeReference.JavaUtilMap); - if (c.isInterface()) { - assert collection != null; - assert map != null; - Collection s; - s = c.getAllImplementedInterfaces(); - if (s.contains(collection) || s.contains(map)) { - return true; - } - } else { - if (c.getClassHierarchy().implementsInterface(c, collection) || c.getClassHierarchy().implementsInterface(c, map)) { - return true; - } - } - } - if (miscContainers.contains(c.getReference())) { - return true; - } - - if (c.isArrayClass() && ((ArrayClass) c).getElementClass() != null - && ((ArrayClass) c).getElementClass().getReference().isReferenceType()) { - return true; - } - return false; - } -} +/******************************************************************************* + * 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.ipa.callgraph.propagation; + +import java.util.Collection; + +import com.ibm.wala.classLoader.ArrayClass; +import com.ibm.wala.classLoader.IClass; +import com.ibm.wala.types.ClassLoaderReference; +import com.ibm.wala.types.TypeName; +import com.ibm.wala.types.TypeReference; +import com.ibm.wala.util.collections.HashSetFactory; + +/** + * Utilities for container class analysis + */ +public class ContainerUtil { + + private final static TypeName FreezableListName = TypeName.string2TypeName("Lcom/sun/corba/se/internal/ior/FreezableList"); + + public final static TypeReference FreezableList = TypeReference.findOrCreate(ClassLoaderReference.Primordial, FreezableListName); + + private final static TypeName JarAttributesName = TypeName.string2TypeName("Ljava/util/jar/Attributes"); + + public final static TypeReference JarAttributes = TypeReference.findOrCreate(ClassLoaderReference.Primordial, JarAttributesName); + + private final static Collection miscContainers = HashSetFactory.make(); + static { + miscContainers.add(FreezableList); + miscContainers.add(JarAttributes); + } + + /** + * @return true iff C is a container class from java.util + * @throws IllegalArgumentException if C is null + */ + public static boolean isContainer(IClass c) { + if (c == null) { + throw new IllegalArgumentException("c is null"); + } + if (ClassLoaderReference.Primordial.equals(c.getClassLoader().getReference()) + && TypeReference.JavaUtilCollection.getName().getPackage().equals(c.getReference().getName().getPackage())) { + IClass collection = c.getClassHierarchy().lookupClass(TypeReference.JavaUtilCollection); + IClass map = c.getClassHierarchy().lookupClass(TypeReference.JavaUtilMap); + if (c.isInterface()) { + assert collection != null; + assert map != null; + Collection s; + s = c.getAllImplementedInterfaces(); + if (s.contains(collection) || s.contains(map)) { + return true; + } + } else { + if (c.getClassHierarchy().implementsInterface(c, collection) || c.getClassHierarchy().implementsInterface(c, map)) { + return true; + } + } + } + if (miscContainers.contains(c.getReference())) { + return true; + } + + if (c.isArrayClass() && ((ArrayClass) c).getElementClass() != null + && ((ArrayClass) c).getElementClass().getReference().isReferenceType()) { + return true; + } + return false; + } +} diff --git a/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/FilteredPointerKey.java b/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/FilteredPointerKey.java index 57c35bf29..f9b0ac47d 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/FilteredPointerKey.java +++ b/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/FilteredPointerKey.java @@ -1,290 +1,290 @@ -/******************************************************************************* - * 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.ipa.callgraph.propagation; - -import com.ibm.wala.classLoader.IClass; -import com.ibm.wala.classLoader.IMethod; -import com.ibm.wala.ipa.callgraph.ContextItem; -import com.ibm.wala.util.intset.IntSet; -import com.ibm.wala.util.intset.IntSetAction; -import com.ibm.wala.util.intset.IntSetUtil; -import com.ibm.wala.util.intset.MutableIntSet; - -/** - * A {@link PointerKey} which carries a type filter, used during pointer analysis - */ -public interface FilteredPointerKey extends PointerKey { - - public interface TypeFilter extends ContextItem { - - boolean addFiltered(PropagationSystem system, PointsToSetVariable L, PointsToSetVariable R); - - boolean addInverseFiltered(PropagationSystem system, PointsToSetVariable L, PointsToSetVariable R); - - boolean isRootFilter(); - - } - - public class SingleClassFilter implements TypeFilter { - private final IClass concreteType; - - public SingleClassFilter(IClass concreteType) { - this.concreteType = concreteType; - } - - @Override - public String toString() { - return "SingleClassFilter: " + concreteType; - } - - public IClass getConcreteType() { - return concreteType; - } - - @Override - public int hashCode() { - return concreteType.hashCode(); - } - - @Override - public boolean equals(Object o) { - return (o instanceof SingleClassFilter) && ((SingleClassFilter) o).getConcreteType().equals(concreteType); - } - - public boolean addFiltered(PropagationSystem system, PointsToSetVariable L, PointsToSetVariable R) { - IntSet f = system.getInstanceKeysForClass(concreteType); - return (f == null) ? false : L.addAllInIntersection(R, f); - } - - public boolean addInverseFiltered(PropagationSystem system, PointsToSetVariable L, PointsToSetVariable R) { - IntSet f = system.getInstanceKeysForClass(concreteType); - - // SJF: this is horribly inefficient. we really don't want to do - // diffs in here. TODO: fix it. probably keep not(f) cached and - // use addAllInIntersection - return (f == null) ? L.addAll(R) : L.addAll(IntSetUtil.diff(R.getValue(), f)); - } - - public boolean isRootFilter() { - return concreteType.equals(concreteType.getClassHierarchy().getRootClass()); - } - } - - public class MultipleClassesFilter implements TypeFilter { - private final IClass[] concreteType; - - public MultipleClassesFilter(IClass[] concreteType) { - this.concreteType = concreteType; - } - - @Override - public String toString() { - return "SingleClassFilter: " + concreteType; - } - - public IClass[] getConcreteTypes() { - return concreteType; - } - - @Override - public int hashCode() { - return concreteType[0].hashCode(); - } - - @Override - public boolean equals(Object o) { - if (! (o instanceof MultipleClassesFilter)) { - return false; - } - - MultipleClassesFilter f = (MultipleClassesFilter)o; - - if (concreteType.length != f.concreteType.length) { - return false; - } - - for(int i = 0; i < concreteType.length; i++) { - if (! (concreteType[i].equals(f.concreteType[i]))) { - return false; - } - } - - return true; - } - - private IntSet bits(PropagationSystem system) { - IntSet f = null; - for(IClass cls : concreteType) { - if (f == null) { - f = system.getInstanceKeysForClass(cls); - } else { - f = f.union(system.getInstanceKeysForClass(cls)); - } - } - return f; - } - - public boolean addFiltered(PropagationSystem system, PointsToSetVariable L, PointsToSetVariable R) { - IntSet f = bits(system); - return (f == null) ? false : L.addAllInIntersection(R, f); - } - - public boolean addInverseFiltered(PropagationSystem system, PointsToSetVariable L, PointsToSetVariable R) { - IntSet f = bits(system); - - // SJF: this is horribly inefficient. we really don't want to do - // diffs in here. TODO: fix it. probably keep not(f) cached and - // use addAllInIntersection - return (f == null) ? L.addAll(R) : L.addAll(IntSetUtil.diff(R.getValue(), f)); - } - - public boolean isRootFilter() { - return concreteType.length == 1 && concreteType[0].getClassHierarchy().getRootClass().equals(concreteType[0]); - } - } - - public class SingleInstanceFilter implements TypeFilter { - private final InstanceKey concreteType; - - public SingleInstanceFilter(InstanceKey concreteType) { - this.concreteType = concreteType; - } - - @Override - public String toString() { - return "SingleInstanceFilter: " + concreteType + " (" + concreteType.getClass() + ")"; - } - - public InstanceKey getInstance() { - return concreteType; - } - - @Override - public int hashCode() { - return concreteType.hashCode(); - } - - @Override - public boolean equals(Object o) { - return (o instanceof SingleInstanceFilter) && ((SingleInstanceFilter) o).getInstance().equals(concreteType); - } - - public boolean addFiltered(PropagationSystem system, PointsToSetVariable L, PointsToSetVariable R) { - int idx = system.findOrCreateIndexForInstanceKey(concreteType); - if (R.contains(idx)) { - if (!L.contains(idx)) { - L.add(idx); - return true; - } - } - - return false; - } - - public boolean addInverseFiltered(PropagationSystem system, PointsToSetVariable L, PointsToSetVariable R) { - int idx = system.findOrCreateIndexForInstanceKey(concreteType); - if (!R.contains(idx) || L.contains(idx)) { - return L.addAll(R); - } else { - MutableIntSet copy = IntSetUtil.makeMutableCopy(R.getValue()); - copy.remove(idx); - return L.addAll(copy); - } - } - - public boolean isRootFilter() { - return false; - } - } - - public class TargetMethodFilter implements TypeFilter { - private final IMethod targetMethod; - - public TargetMethodFilter(IMethod targetMethod) { - this.targetMethod = targetMethod; - } - - @Override - public String toString() { - return "TargetMethodFilter: " + targetMethod; - } - - public IMethod getMethod() { - return targetMethod; - } - - @Override - public int hashCode() { - return targetMethod.hashCode(); - } - - @Override - public boolean equals(Object o) { - return (o instanceof TargetMethodFilter) && ((TargetMethodFilter) o).getMethod().equals(targetMethod); - } - - private class UpdateAction implements IntSetAction { - private boolean result = false; - - private final PointsToSetVariable L; - - private final PropagationSystem system; - - private final boolean sense; - - private UpdateAction(PropagationSystem system, PointsToSetVariable L, boolean sense) { - this.L = L; - this.sense = sense; - this.system = system; - } - - public void act(int i) { - InstanceKey I = system.getInstanceKey(i); - IClass C = I.getConcreteType(); - if ((C.getMethod(targetMethod.getSelector()) == targetMethod) == sense) { - if (!L.contains(i)) { - result = true; - L.add(i); - } - } - } - } - - public boolean addFiltered(PropagationSystem system, PointsToSetVariable L, PointsToSetVariable R) { - if (R.getValue() == null) { - return false; - } else { - UpdateAction act = new UpdateAction(system, L, true); - R.getValue().foreach(act); - return act.result; - } - } - - public boolean addInverseFiltered(PropagationSystem system, PointsToSetVariable L, PointsToSetVariable R) { - if (R.getValue() == null) { - return false; - } else { - UpdateAction act = new UpdateAction(system, L, false); - R.getValue().foreach(act); - return act.result; - } - } - - public boolean isRootFilter() { - return false; - } - } - - /** - * @return the class which should govern filtering of instances to which this pointer points, or null if no filtering needed - */ - public TypeFilter getTypeFilter(); -} +/******************************************************************************* + * 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.ipa.callgraph.propagation; + +import com.ibm.wala.classLoader.IClass; +import com.ibm.wala.classLoader.IMethod; +import com.ibm.wala.ipa.callgraph.ContextItem; +import com.ibm.wala.util.intset.IntSet; +import com.ibm.wala.util.intset.IntSetAction; +import com.ibm.wala.util.intset.IntSetUtil; +import com.ibm.wala.util.intset.MutableIntSet; + +/** + * A {@link PointerKey} which carries a type filter, used during pointer analysis + */ +public interface FilteredPointerKey extends PointerKey { + + public interface TypeFilter extends ContextItem { + + boolean addFiltered(PropagationSystem system, PointsToSetVariable L, PointsToSetVariable R); + + boolean addInverseFiltered(PropagationSystem system, PointsToSetVariable L, PointsToSetVariable R); + + boolean isRootFilter(); + + } + + public class SingleClassFilter implements TypeFilter { + private final IClass concreteType; + + public SingleClassFilter(IClass concreteType) { + this.concreteType = concreteType; + } + + @Override + public String toString() { + return "SingleClassFilter: " + concreteType; + } + + public IClass getConcreteType() { + return concreteType; + } + + @Override + public int hashCode() { + return concreteType.hashCode(); + } + + @Override + public boolean equals(Object o) { + return (o instanceof SingleClassFilter) && ((SingleClassFilter) o).getConcreteType().equals(concreteType); + } + + public boolean addFiltered(PropagationSystem system, PointsToSetVariable L, PointsToSetVariable R) { + IntSet f = system.getInstanceKeysForClass(concreteType); + return (f == null) ? false : L.addAllInIntersection(R, f); + } + + public boolean addInverseFiltered(PropagationSystem system, PointsToSetVariable L, PointsToSetVariable R) { + IntSet f = system.getInstanceKeysForClass(concreteType); + + // SJF: this is horribly inefficient. we really don't want to do + // diffs in here. TODO: fix it. probably keep not(f) cached and + // use addAllInIntersection + return (f == null) ? L.addAll(R) : L.addAll(IntSetUtil.diff(R.getValue(), f)); + } + + public boolean isRootFilter() { + return concreteType.equals(concreteType.getClassHierarchy().getRootClass()); + } + } + + public class MultipleClassesFilter implements TypeFilter { + private final IClass[] concreteType; + + public MultipleClassesFilter(IClass[] concreteType) { + this.concreteType = concreteType; + } + + @Override + public String toString() { + return "SingleClassFilter: " + concreteType; + } + + public IClass[] getConcreteTypes() { + return concreteType; + } + + @Override + public int hashCode() { + return concreteType[0].hashCode(); + } + + @Override + public boolean equals(Object o) { + if (! (o instanceof MultipleClassesFilter)) { + return false; + } + + MultipleClassesFilter f = (MultipleClassesFilter)o; + + if (concreteType.length != f.concreteType.length) { + return false; + } + + for(int i = 0; i < concreteType.length; i++) { + if (! (concreteType[i].equals(f.concreteType[i]))) { + return false; + } + } + + return true; + } + + private IntSet bits(PropagationSystem system) { + IntSet f = null; + for(IClass cls : concreteType) { + if (f == null) { + f = system.getInstanceKeysForClass(cls); + } else { + f = f.union(system.getInstanceKeysForClass(cls)); + } + } + return f; + } + + public boolean addFiltered(PropagationSystem system, PointsToSetVariable L, PointsToSetVariable R) { + IntSet f = bits(system); + return (f == null) ? false : L.addAllInIntersection(R, f); + } + + public boolean addInverseFiltered(PropagationSystem system, PointsToSetVariable L, PointsToSetVariable R) { + IntSet f = bits(system); + + // SJF: this is horribly inefficient. we really don't want to do + // diffs in here. TODO: fix it. probably keep not(f) cached and + // use addAllInIntersection + return (f == null) ? L.addAll(R) : L.addAll(IntSetUtil.diff(R.getValue(), f)); + } + + public boolean isRootFilter() { + return concreteType.length == 1 && concreteType[0].getClassHierarchy().getRootClass().equals(concreteType[0]); + } + } + + public class SingleInstanceFilter implements TypeFilter { + private final InstanceKey concreteType; + + public SingleInstanceFilter(InstanceKey concreteType) { + this.concreteType = concreteType; + } + + @Override + public String toString() { + return "SingleInstanceFilter: " + concreteType + " (" + concreteType.getClass() + ")"; + } + + public InstanceKey getInstance() { + return concreteType; + } + + @Override + public int hashCode() { + return concreteType.hashCode(); + } + + @Override + public boolean equals(Object o) { + return (o instanceof SingleInstanceFilter) && ((SingleInstanceFilter) o).getInstance().equals(concreteType); + } + + public boolean addFiltered(PropagationSystem system, PointsToSetVariable L, PointsToSetVariable R) { + int idx = system.findOrCreateIndexForInstanceKey(concreteType); + if (R.contains(idx)) { + if (!L.contains(idx)) { + L.add(idx); + return true; + } + } + + return false; + } + + public boolean addInverseFiltered(PropagationSystem system, PointsToSetVariable L, PointsToSetVariable R) { + int idx = system.findOrCreateIndexForInstanceKey(concreteType); + if (!R.contains(idx) || L.contains(idx)) { + return L.addAll(R); + } else { + MutableIntSet copy = IntSetUtil.makeMutableCopy(R.getValue()); + copy.remove(idx); + return L.addAll(copy); + } + } + + public boolean isRootFilter() { + return false; + } + } + + public class TargetMethodFilter implements TypeFilter { + private final IMethod targetMethod; + + public TargetMethodFilter(IMethod targetMethod) { + this.targetMethod = targetMethod; + } + + @Override + public String toString() { + return "TargetMethodFilter: " + targetMethod; + } + + public IMethod getMethod() { + return targetMethod; + } + + @Override + public int hashCode() { + return targetMethod.hashCode(); + } + + @Override + public boolean equals(Object o) { + return (o instanceof TargetMethodFilter) && ((TargetMethodFilter) o).getMethod().equals(targetMethod); + } + + private class UpdateAction implements IntSetAction { + private boolean result = false; + + private final PointsToSetVariable L; + + private final PropagationSystem system; + + private final boolean sense; + + private UpdateAction(PropagationSystem system, PointsToSetVariable L, boolean sense) { + this.L = L; + this.sense = sense; + this.system = system; + } + + public void act(int i) { + InstanceKey I = system.getInstanceKey(i); + IClass C = I.getConcreteType(); + if ((C.getMethod(targetMethod.getSelector()) == targetMethod) == sense) { + if (!L.contains(i)) { + result = true; + L.add(i); + } + } + } + } + + public boolean addFiltered(PropagationSystem system, PointsToSetVariable L, PointsToSetVariable R) { + if (R.getValue() == null) { + return false; + } else { + UpdateAction act = new UpdateAction(system, L, true); + R.getValue().foreach(act); + return act.result; + } + } + + public boolean addInverseFiltered(PropagationSystem system, PointsToSetVariable L, PointsToSetVariable R) { + if (R.getValue() == null) { + return false; + } else { + UpdateAction act = new UpdateAction(system, L, false); + R.getValue().foreach(act); + return act.result; + } + } + + public boolean isRootFilter() { + return false; + } + } + + /** + * @return the class which should govern filtering of instances to which this pointer points, or null if no filtering needed + */ + public TypeFilter getTypeFilter(); +} diff --git a/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/HeapModel.java b/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/HeapModel.java index ead4f5f43..e49168e2f 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/HeapModel.java +++ b/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/HeapModel.java @@ -1,33 +1,33 @@ -/******************************************************************************* - * Copyright (c) 2002 - 2006 IBM Corporation. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * IBM Corporation - initial API and implementation - *******************************************************************************/ -package com.ibm.wala.ipa.callgraph.propagation; - -import java.util.Iterator; - -import com.ibm.wala.ipa.cha.IClassHierarchy; - - -/** - * A {@link HeapModel} embodies how a pointer analysis abstracts heap locations. - */ -public interface HeapModel extends InstanceKeyFactory, PointerKeyFactory { - - /** - * @return an Iterator of all PointerKeys that are modeled. - */ - Iterator iteratePointerKeys(); - - /** - * @return the governing class hierarchy for this heap model - */ - IClassHierarchy getClassHierarchy(); - -} +/******************************************************************************* + * 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.ipa.callgraph.propagation; + +import java.util.Iterator; + +import com.ibm.wala.ipa.cha.IClassHierarchy; + + +/** + * A {@link HeapModel} embodies how a pointer analysis abstracts heap locations. + */ +public interface HeapModel extends InstanceKeyFactory, PointerKeyFactory { + + /** + * @return an Iterator of all PointerKeys that are modeled. + */ + Iterator iteratePointerKeys(); + + /** + * @return the governing class hierarchy for this heap model + */ + IClassHierarchy getClassHierarchy(); + +} diff --git a/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/IPointerOperator.java b/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/IPointerOperator.java index 8745d281f..9ea5e43b8 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/IPointerOperator.java +++ b/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/IPointerOperator.java @@ -1,23 +1,23 @@ -/******************************************************************************* - * Copyright (c) 2002 - 2006 IBM Corporation. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * IBM Corporation - initial API and implementation - *******************************************************************************/ -package com.ibm.wala.ipa.callgraph.propagation; - -/** - * An operator in pointer analysis constraints - */ -public interface IPointerOperator { - - /** - * Is the operator complex; i.e., might it give rise to new constraints? - */ - boolean isComplex(); - +/******************************************************************************* + * 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.ipa.callgraph.propagation; + +/** + * An operator in pointer analysis constraints + */ +public interface IPointerOperator { + + /** + * Is the operator complex; i.e., might it give rise to new constraints? + */ + boolean isComplex(); + } \ No newline at end of file diff --git a/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/IPointsToSolver.java b/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/IPointsToSolver.java index f3f8fc1cf..5e8f25877 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/IPointsToSolver.java +++ b/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/IPointsToSolver.java @@ -1,23 +1,23 @@ -/******************************************************************************* - * Copyright (c) 2002 - 2006 IBM Corporation. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * IBM Corporation - initial API and implementation - *******************************************************************************/ -package com.ibm.wala.ipa.callgraph.propagation; - - -import com.ibm.wala.util.CancelException; -import com.ibm.wala.util.MonitorUtil.IProgressMonitor; - -/** - * Basic interface for a pointer analysis solver. - */ -public interface IPointsToSolver { - - public void solve(IProgressMonitor monitor) throws IllegalArgumentException, CancelException; -} +/******************************************************************************* + * 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.ipa.callgraph.propagation; + + +import com.ibm.wala.util.CancelException; +import com.ibm.wala.util.MonitorUtil.IProgressMonitor; + +/** + * Basic interface for a pointer analysis solver. + */ +public interface IPointsToSolver { + + public void solve(IProgressMonitor monitor) throws IllegalArgumentException, CancelException; +} diff --git a/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/InstanceFieldKey.java b/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/InstanceFieldKey.java index 95c8f87ca..7401d9e36 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/InstanceFieldKey.java +++ b/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/InstanceFieldKey.java @@ -1,62 +1,62 @@ -/******************************************************************************* - * 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.ipa.callgraph.propagation; - -import com.ibm.wala.classLoader.IField; - -/** - * An pointer key which represents a unique set for a field associated with a set of instances. - */ -public class InstanceFieldKey extends AbstractFieldPointerKey { - private final IField field; - - public InstanceFieldKey(InstanceKey instance, IField field) { - - super(instance); - if (field == null) { - throw new IllegalArgumentException("field is null"); - } - if (instance == null) { - throw new IllegalArgumentException("instance is null"); - } - this.field = field; - } - - @Override - public boolean equals(Object obj) { - if (obj instanceof InstanceFieldKey) { - if (obj.getClass().equals(getClass())) { - InstanceFieldKey other = (InstanceFieldKey) obj; - boolean result = field.equals(other.field) && instance.equals(other.instance); - return result; - } else { - return false; - } - } else { - return false; - } - } - - @Override - public int hashCode() { - return 6229 * field.hashCode() + instance.hashCode(); - } - - @Override - public String toString() { - return "[" + instance + "," + field + "]"; - } - - public IField getField() { - return field; - } -} +/******************************************************************************* + * 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.ipa.callgraph.propagation; + +import com.ibm.wala.classLoader.IField; + +/** + * An pointer key which represents a unique set for a field associated with a set of instances. + */ +public class InstanceFieldKey extends AbstractFieldPointerKey { + private final IField field; + + public InstanceFieldKey(InstanceKey instance, IField field) { + + super(instance); + if (field == null) { + throw new IllegalArgumentException("field is null"); + } + if (instance == null) { + throw new IllegalArgumentException("instance is null"); + } + this.field = field; + } + + @Override + public boolean equals(Object obj) { + if (obj instanceof InstanceFieldKey) { + if (obj.getClass().equals(getClass())) { + InstanceFieldKey other = (InstanceFieldKey) obj; + boolean result = field.equals(other.field) && instance.equals(other.instance); + return result; + } else { + return false; + } + } else { + return false; + } + } + + @Override + public int hashCode() { + return 6229 * field.hashCode() + instance.hashCode(); + } + + @Override + public String toString() { + return "[" + instance + "," + field + "]"; + } + + public IField getField() { + return field; + } +} diff --git a/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/InstanceFieldKeyWithFilter.java b/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/InstanceFieldKeyWithFilter.java index b22ffb0d2..62d1e18f1 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/InstanceFieldKeyWithFilter.java +++ b/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/InstanceFieldKeyWithFilter.java @@ -1,50 +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.ipa.callgraph.propagation; - -import com.ibm.wala.classLoader.IClass; -import com.ibm.wala.classLoader.IField; -import com.ibm.wala.ipa.cha.IClassHierarchy; -import com.ibm.wala.types.TypeReference; - -/** - * an instance field pointer key key that carries a type filter - */ -public class InstanceFieldKeyWithFilter extends InstanceFieldKey implements FilteredPointerKey { - - private final IClass filter; - - public InstanceFieldKeyWithFilter(IClassHierarchy cha, InstanceKey instance, IField field) { - - super(instance, field); - if (field == null) { - throw new IllegalArgumentException("field is null"); - } - if (cha == null) { - throw new IllegalArgumentException("cha is null"); - } - IClass fieldType = cha.lookupClass(field.getFieldTypeReference()); - if (fieldType == null) { - // TODO: assertions.unreachable() - this.filter = cha.lookupClass(TypeReference.JavaLangObject); - } else { - this.filter = fieldType; - } - } - - /* - * @see com.ibm.wala.ipa.callgraph.propagation.PointerKey#getTypeFilter() - */ - public TypeFilter getTypeFilter() { - return new SingleClassFilter(filter); - } - -} +/******************************************************************************* + * 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.ipa.callgraph.propagation; + +import com.ibm.wala.classLoader.IClass; +import com.ibm.wala.classLoader.IField; +import com.ibm.wala.ipa.cha.IClassHierarchy; +import com.ibm.wala.types.TypeReference; + +/** + * an instance field pointer key key that carries a type filter + */ +public class InstanceFieldKeyWithFilter extends InstanceFieldKey implements FilteredPointerKey { + + private final IClass filter; + + public InstanceFieldKeyWithFilter(IClassHierarchy cha, InstanceKey instance, IField field) { + + super(instance, field); + if (field == null) { + throw new IllegalArgumentException("field is null"); + } + if (cha == null) { + throw new IllegalArgumentException("cha is null"); + } + IClass fieldType = cha.lookupClass(field.getFieldTypeReference()); + if (fieldType == null) { + // TODO: assertions.unreachable() + this.filter = cha.lookupClass(TypeReference.JavaLangObject); + } else { + this.filter = fieldType; + } + } + + /* + * @see com.ibm.wala.ipa.callgraph.propagation.PointerKey#getTypeFilter() + */ + public TypeFilter getTypeFilter() { + return new SingleClassFilter(filter); + } + +} diff --git a/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/InstanceFieldPointerKey.java b/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/InstanceFieldPointerKey.java index c191b20de..ab9306b9d 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/InstanceFieldPointerKey.java +++ b/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/InstanceFieldPointerKey.java @@ -1,20 +1,20 @@ -/******************************************************************************* - * 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.ipa.callgraph.propagation; - -public interface InstanceFieldPointerKey extends PointerKey { - - /** - * @return the instance key which is the "container" for this pointer - */ - InstanceKey getInstanceKey(); - -} +/******************************************************************************* + * 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.ipa.callgraph.propagation; + +public interface InstanceFieldPointerKey extends PointerKey { + + /** + * @return the instance key which is the "container" for this pointer + */ + InstanceKey getInstanceKey(); + +} diff --git a/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/InstanceKey.java b/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/InstanceKey.java index 1f2ef36d9..082765f60 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/InstanceKey.java +++ b/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/InstanceKey.java @@ -1,36 +1,36 @@ -/******************************************************************************* - * 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.ipa.callgraph.propagation; - -import com.ibm.wala.classLoader.IClass; -import com.ibm.wala.ipa.callgraph.ContextItem; - -/** - * An InstanceKey serves as the representative for an equivalence class of - * objects in the heap, that can be pointed to. - * - * For example, for 0-CFA, an InstanceKey would embody an ... we model - * all instances of a particular class - * - * For 0-1-CFA, an InstanceKey could be , representing a - * particular allocation statement in a particular method. - */ -public interface InstanceKey extends ContextItem { - - /** - * For now, we assert that each InstanceKey represents a set of classes which - * are all of the same concrete type (modulo the fact that all arrays of - * references are considered concrete type []Object;) - */ - IClass getConcreteType(); - -} - +/******************************************************************************* + * 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.ipa.callgraph.propagation; + +import com.ibm.wala.classLoader.IClass; +import com.ibm.wala.ipa.callgraph.ContextItem; + +/** + * An InstanceKey serves as the representative for an equivalence class of + * objects in the heap, that can be pointed to. + * + * For example, for 0-CFA, an InstanceKey would embody an ... we model + * all instances of a particular class + * + * For 0-1-CFA, an InstanceKey could be , representing a + * particular allocation statement in a particular method. + */ +public interface InstanceKey extends ContextItem { + + /** + * For now, we assert that each InstanceKey represents a set of classes which + * are all of the same concrete type (modulo the fact that all arrays of + * references are considered concrete type []Object;) + */ + IClass getConcreteType(); + +} + diff --git a/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/InstanceKeyFactory.java b/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/InstanceKeyFactory.java index e55f7e2d3..77a1229d0 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/InstanceKeyFactory.java +++ b/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/InstanceKeyFactory.java @@ -1,52 +1,52 @@ -/******************************************************************************* - * 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.ipa.callgraph.propagation; - -import com.ibm.wala.classLoader.NewSiteReference; -import com.ibm.wala.classLoader.ProgramCounter; -import com.ibm.wala.ipa.callgraph.CGNode; -import com.ibm.wala.types.TypeReference; - -/** - * An object that abstracts how to model instances in the heap. - */ -public interface InstanceKeyFactory { - /** - * @return the instance key that represents a particular allocation - */ - public abstract InstanceKey getInstanceKeyForAllocation(CGNode node, NewSiteReference allocation); - - /** - * @return the instance key that represents the array allocated as the dim_th - * dimension at a particular allocation - */ - public abstract InstanceKey getInstanceKeyForMultiNewArray(CGNode node, NewSiteReference allocation, int dim); - - /** - * @return the instance key that represents a constant with value S, when considered as a particular type - */ - public abstract InstanceKey getInstanceKeyForConstant(TypeReference type, T S); - - /** - * @param node - * @param instr - * @param type - * @return the instance key that represents the exception of type _type_ - * thrown by a particular PEI. - */ - public abstract InstanceKey getInstanceKeyForPEI(CGNode node, ProgramCounter instr, TypeReference type); - - /** - * @return the instance key that represents the class object of type _type_. - */ - public abstract InstanceKey getInstanceKeyForClassObject(TypeReference type); - -} +/******************************************************************************* + * 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.ipa.callgraph.propagation; + +import com.ibm.wala.classLoader.NewSiteReference; +import com.ibm.wala.classLoader.ProgramCounter; +import com.ibm.wala.ipa.callgraph.CGNode; +import com.ibm.wala.types.TypeReference; + +/** + * An object that abstracts how to model instances in the heap. + */ +public interface InstanceKeyFactory { + /** + * @return the instance key that represents a particular allocation + */ + public abstract InstanceKey getInstanceKeyForAllocation(CGNode node, NewSiteReference allocation); + + /** + * @return the instance key that represents the array allocated as the dim_th + * dimension at a particular allocation + */ + public abstract InstanceKey getInstanceKeyForMultiNewArray(CGNode node, NewSiteReference allocation, int dim); + + /** + * @return the instance key that represents a constant with value S, when considered as a particular type + */ + public abstract InstanceKey getInstanceKeyForConstant(TypeReference type, T S); + + /** + * @param node + * @param instr + * @param type + * @return the instance key that represents the exception of type _type_ + * thrown by a particular PEI. + */ + public abstract InstanceKey getInstanceKeyForPEI(CGNode node, ProgramCounter instr, TypeReference type); + + /** + * @return the instance key that represents the class object of type _type_. + */ + public abstract InstanceKey getInstanceKeyForClassObject(TypeReference type); + +} diff --git a/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/LocalPointerKey.java b/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/LocalPointerKey.java index 6af0347ae..d390b86d9 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/LocalPointerKey.java +++ b/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/LocalPointerKey.java @@ -1,67 +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.ipa.callgraph.propagation; - -import com.ibm.wala.ipa.callgraph.CGNode; - -/** - * A pointer key which provides a unique set for each local in each call graph node. - */ -public class LocalPointerKey extends AbstractLocalPointerKey { - private final CGNode node; - - private final int valueNumber; - - public LocalPointerKey(CGNode node, int valueNumber) { - super(); - this.node = node; - this.valueNumber = valueNumber; - if (valueNumber <= 0) { - throw new IllegalArgumentException("illegal valueNumber: " + valueNumber); - } - if (node == null) { - throw new IllegalArgumentException("null node"); - } - } - - @Override - public final boolean equals(Object obj) { - if (obj instanceof LocalPointerKey) { - LocalPointerKey other = (LocalPointerKey) obj; - return node.equals(other.node) && valueNumber == other.valueNumber; - } else { - return false; - } - } - - @Override - public final int hashCode() { - return node.hashCode() * 23 + valueNumber; - } - - @Override - public String toString() { - return "[" + node + ", v" + valueNumber + "]"; - } - - @Override - public final CGNode getNode() { - return node; - } - - public final int getValueNumber() { - return valueNumber; - } - - public final boolean isParameter() { - return valueNumber <= node.getMethod().getNumberOfParameters(); - } -} +/******************************************************************************* + * 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.ipa.callgraph.propagation; + +import com.ibm.wala.ipa.callgraph.CGNode; + +/** + * A pointer key which provides a unique set for each local in each call graph node. + */ +public class LocalPointerKey extends AbstractLocalPointerKey { + private final CGNode node; + + private final int valueNumber; + + public LocalPointerKey(CGNode node, int valueNumber) { + super(); + this.node = node; + this.valueNumber = valueNumber; + if (valueNumber <= 0) { + throw new IllegalArgumentException("illegal valueNumber: " + valueNumber); + } + if (node == null) { + throw new IllegalArgumentException("null node"); + } + } + + @Override + public final boolean equals(Object obj) { + if (obj instanceof LocalPointerKey) { + LocalPointerKey other = (LocalPointerKey) obj; + return node.equals(other.node) && valueNumber == other.valueNumber; + } else { + return false; + } + } + + @Override + public final int hashCode() { + return node.hashCode() * 23 + valueNumber; + } + + @Override + public String toString() { + return "[" + node + ", v" + valueNumber + "]"; + } + + @Override + public final CGNode getNode() { + return node; + } + + public final int getValueNumber() { + return valueNumber; + } + + public final boolean isParameter() { + return valueNumber <= node.getMethod().getNumberOfParameters(); + } +} diff --git a/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/LocalPointerKeyWithFilter.java b/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/LocalPointerKeyWithFilter.java index 66b24b0a1..d0f66ac48 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/LocalPointerKeyWithFilter.java +++ b/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/LocalPointerKeyWithFilter.java @@ -1,33 +1,33 @@ -/******************************************************************************* - * Copyright (c) 2002 - 2006 IBM Corporation. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * IBM Corporation - initial API and implementation - *******************************************************************************/ -package com.ibm.wala.ipa.callgraph.propagation; - -import com.ibm.wala.ipa.callgraph.CGNode; - -/** - * a local pointer key that carries a type filter - */ -public class LocalPointerKeyWithFilter extends LocalPointerKey implements FilteredPointerKey { - - private final TypeFilter typeFilter; - - public LocalPointerKeyWithFilter(CGNode node, int valueNumber, TypeFilter typeFilter) { - super(node,valueNumber); - assert typeFilter != null; - this.typeFilter = typeFilter; - } - - - public TypeFilter getTypeFilter() { - return typeFilter; - } - -} +/******************************************************************************* + * 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.ipa.callgraph.propagation; + +import com.ibm.wala.ipa.callgraph.CGNode; + +/** + * a local pointer key that carries a type filter + */ +public class LocalPointerKeyWithFilter extends LocalPointerKey implements FilteredPointerKey { + + private final TypeFilter typeFilter; + + public LocalPointerKeyWithFilter(CGNode node, int valueNumber, TypeFilter typeFilter) { + super(node,valueNumber); + assert typeFilter != null; + this.typeFilter = typeFilter; + } + + + public TypeFilter getTypeFilter() { + return typeFilter; + } + +} diff --git a/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/MultiNewArrayInNode.java b/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/MultiNewArrayInNode.java index 00fa1fbb3..28f9829d2 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/MultiNewArrayInNode.java +++ b/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/MultiNewArrayInNode.java @@ -1,74 +1,74 @@ -/******************************************************************************* - * 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.ipa.callgraph.propagation; - -import com.ibm.wala.classLoader.ArrayClass; -import com.ibm.wala.classLoader.IClass; -import com.ibm.wala.classLoader.NewSiteReference; -import com.ibm.wala.ipa.callgraph.CGNode; - -/** - * An {@link InstanceKey} which represents a multinewarray allocation site in a {@link CGNode}. - */ -public final class MultiNewArrayInNode extends AllocationSiteInNode { - private final int dim; - - /** - * @return null if the element type is a primitive - * @throws IllegalArgumentException if T == null - */ - private static IClass myElementType(ArrayClass T, int d) throws IllegalArgumentException, IllegalArgumentException { - if (T == null) { - throw new IllegalArgumentException("T == null"); - } - if (d == 0) { - return T.getElementClass(); - } else { - ArrayClass element = (ArrayClass) T.getElementClass(); - if (element == null) { - return null; - } else { - return myElementType(element, d - 1); - } - } - } - - public MultiNewArrayInNode(CGNode node, NewSiteReference allocation, ArrayClass type, int dim) { - super(node, allocation, myElementType(type, dim)); - this.dim = dim; - } - - @Override - public boolean equals(Object obj) { - // instanceof is OK because this class is final - if (obj instanceof MultiNewArrayInNode) { - MultiNewArrayInNode other = (MultiNewArrayInNode) obj; - return (dim == other.dim && getNode().equals(other.getNode()) && getSite().equals(other.getSite())); - } else { - return false; - } - } - - @Override - public int hashCode() { - return 9967 * dim + getNode().hashCode() * 8647 * getSite().hashCode(); - } - - @Override - public String toString() { - return super.toString() + ""; - } - - public int getDim() { - return dim; - } -} +/******************************************************************************* + * 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.ipa.callgraph.propagation; + +import com.ibm.wala.classLoader.ArrayClass; +import com.ibm.wala.classLoader.IClass; +import com.ibm.wala.classLoader.NewSiteReference; +import com.ibm.wala.ipa.callgraph.CGNode; + +/** + * An {@link InstanceKey} which represents a multinewarray allocation site in a {@link CGNode}. + */ +public final class MultiNewArrayInNode extends AllocationSiteInNode { + private final int dim; + + /** + * @return null if the element type is a primitive + * @throws IllegalArgumentException if T == null + */ + private static IClass myElementType(ArrayClass T, int d) throws IllegalArgumentException, IllegalArgumentException { + if (T == null) { + throw new IllegalArgumentException("T == null"); + } + if (d == 0) { + return T.getElementClass(); + } else { + ArrayClass element = (ArrayClass) T.getElementClass(); + if (element == null) { + return null; + } else { + return myElementType(element, d - 1); + } + } + } + + public MultiNewArrayInNode(CGNode node, NewSiteReference allocation, ArrayClass type, int dim) { + super(node, allocation, myElementType(type, dim)); + this.dim = dim; + } + + @Override + public boolean equals(Object obj) { + // instanceof is OK because this class is final + if (obj instanceof MultiNewArrayInNode) { + MultiNewArrayInNode other = (MultiNewArrayInNode) obj; + return (dim == other.dim && getNode().equals(other.getNode()) && getSite().equals(other.getSite())); + } else { + return false; + } + } + + @Override + public int hashCode() { + return 9967 * dim + getNode().hashCode() * 8647 * getSite().hashCode(); + } + + @Override + public String toString() { + return super.toString() + ""; + } + + public int getDim() { + return dim; + } +} diff --git a/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/NodeKey.java b/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/NodeKey.java index 897eabb60..e34a615aa 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/NodeKey.java +++ b/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/NodeKey.java @@ -1,51 +1,51 @@ -/******************************************************************************* - * Copyright (c) 2002 - 2006 IBM Corporation. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * IBM Corporation - initial API and implementation - *******************************************************************************/ -package com.ibm.wala.ipa.callgraph.propagation; - -import com.ibm.wala.ipa.callgraph.CGNode; - -/** - * A key which represents a set corresponding to a call graph node. - */ -public abstract class NodeKey extends AbstractLocalPointerKey { - private final CGNode node; - protected NodeKey(CGNode node) { - if (node == null) { - throw new IllegalArgumentException("null node"); - } - this.node = node; - } - protected boolean internalEquals(Object obj) { - if (obj instanceof NodeKey) { - NodeKey other = (NodeKey) obj; - return node.equals(other.node); - } else { - return false; - } - } - protected int internalHashCode() { - return node.hashCode() * 1621; - } - /** - * @return the node this key represents - */ - @Override - public CGNode getNode() { - return node; - } - - @Override - public abstract boolean equals(Object obj); - - @Override - public abstract int hashCode(); - -} +/******************************************************************************* + * 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.ipa.callgraph.propagation; + +import com.ibm.wala.ipa.callgraph.CGNode; + +/** + * A key which represents a set corresponding to a call graph node. + */ +public abstract class NodeKey extends AbstractLocalPointerKey { + private final CGNode node; + protected NodeKey(CGNode node) { + if (node == null) { + throw new IllegalArgumentException("null node"); + } + this.node = node; + } + protected boolean internalEquals(Object obj) { + if (obj instanceof NodeKey) { + NodeKey other = (NodeKey) obj; + return node.equals(other.node); + } else { + return false; + } + } + protected int internalHashCode() { + return node.hashCode() * 1621; + } + /** + * @return the node this key represents + */ + @Override + public CGNode getNode() { + return node; + } + + @Override + public abstract boolean equals(Object obj); + + @Override + public abstract int hashCode(); + +} diff --git a/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/NormalAllocationInNode.java b/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/NormalAllocationInNode.java index ad8c5ae51..28040510d 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/NormalAllocationInNode.java +++ b/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/NormalAllocationInNode.java @@ -1,41 +1,41 @@ -/******************************************************************************* - * 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.ipa.callgraph.propagation; - -import com.ibm.wala.classLoader.IClass; -import com.ibm.wala.classLoader.NewSiteReference; -import com.ibm.wala.ipa.callgraph.CGNode; - -/** - * An {@link InstanceKey} which represents a "normal" (not multinewarray) {@link NewSiteReference} in a {@link CGNode}. - */ -public final class NormalAllocationInNode extends AllocationSiteInNode { - public NormalAllocationInNode(CGNode node, NewSiteReference allocation, IClass type) { - super(node, allocation, type); - } - - @Override - public boolean equals(Object obj) { - // instanceof is OK because this class is final - if (obj instanceof NormalAllocationInNode) { - AllocationSiteInNode other = (AllocationSiteInNode) obj; - return getNode().equals(other.getNode()) && getSite().equals(other.getSite()); - } else { - return false; - } - } - - @Override - public int hashCode() { - return getNode().hashCode() * 8647 + getSite().hashCode(); - } - -} +/******************************************************************************* + * 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.ipa.callgraph.propagation; + +import com.ibm.wala.classLoader.IClass; +import com.ibm.wala.classLoader.NewSiteReference; +import com.ibm.wala.ipa.callgraph.CGNode; + +/** + * An {@link InstanceKey} which represents a "normal" (not multinewarray) {@link NewSiteReference} in a {@link CGNode}. + */ +public final class NormalAllocationInNode extends AllocationSiteInNode { + public NormalAllocationInNode(CGNode node, NewSiteReference allocation, IClass type) { + super(node, allocation, type); + } + + @Override + public boolean equals(Object obj) { + // instanceof is OK because this class is final + if (obj instanceof NormalAllocationInNode) { + AllocationSiteInNode other = (AllocationSiteInNode) obj; + return getNode().equals(other.getNode()) && getSite().equals(other.getSite()); + } else { + return false; + } + } + + @Override + public int hashCode() { + return getNode().hashCode() * 8647 + getSite().hashCode(); + } + +} diff --git a/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/PointerAnalysis.java b/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/PointerAnalysis.java index 870fb471b..4362f4649 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/PointerAnalysis.java +++ b/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/PointerAnalysis.java @@ -1,67 +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.ipa.callgraph.propagation; - -import java.util.Collection; - -import com.ibm.wala.analysis.pointers.HeapGraph; -import com.ibm.wala.ipa.cha.IClassHierarchy; -import com.ibm.wala.util.intset.OrdinalSet; -import com.ibm.wala.util.intset.OrdinalSetMapping; - -/** - * Abstract definition of pointer analysis - */ -public interface PointerAnalysis { - - /** - * @param key representative of an equivalence class of pointers - * @return Set of InstanceKey, representing the instance abstractions that define - * the points-to set computed for the pointer key - */ - OrdinalSet getPointsToSet(PointerKey key); - - /** - * @return an Object that determines how to model abstract locations in the heap. - */ - HeapModel getHeapModel(); - - /** - * @return a graph view of the pointer analysis solution - */ - HeapGraph getHeapGraph(); - - /** - * @return the bijection between InstanceKey <=> Integer that defines the - * interpretation of points-to-sets. - */ - OrdinalSetMapping getInstanceKeyMapping(); - - /** - * @return all pointer keys known - */ - Iterable getPointerKeys(); - - - /** - * @return all instance keys known - */ - Collection getInstanceKeys(); - - /** - * did the pointer analysis use a type filter for a given points-to set? - * (this is ugly). - */ - boolean isFiltered(PointerKey pk); - - public IClassHierarchy getClassHierarchy(); - -} +/******************************************************************************* + * 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.ipa.callgraph.propagation; + +import java.util.Collection; + +import com.ibm.wala.analysis.pointers.HeapGraph; +import com.ibm.wala.ipa.cha.IClassHierarchy; +import com.ibm.wala.util.intset.OrdinalSet; +import com.ibm.wala.util.intset.OrdinalSetMapping; + +/** + * Abstract definition of pointer analysis + */ +public interface PointerAnalysis { + + /** + * @param key representative of an equivalence class of pointers + * @return Set of InstanceKey, representing the instance abstractions that define + * the points-to set computed for the pointer key + */ + OrdinalSet getPointsToSet(PointerKey key); + + /** + * @return an Object that determines how to model abstract locations in the heap. + */ + HeapModel getHeapModel(); + + /** + * @return a graph view of the pointer analysis solution + */ + HeapGraph getHeapGraph(); + + /** + * @return the bijection between InstanceKey <=> Integer that defines the + * interpretation of points-to-sets. + */ + OrdinalSetMapping getInstanceKeyMapping(); + + /** + * @return all pointer keys known + */ + Iterable getPointerKeys(); + + + /** + * @return all instance keys known + */ + Collection getInstanceKeys(); + + /** + * did the pointer analysis use a type filter for a given points-to set? + * (this is ugly). + */ + boolean isFiltered(PointerKey pk); + + public IClassHierarchy getClassHierarchy(); + +} diff --git a/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/PointerAnalysisImpl.java b/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/PointerAnalysisImpl.java index 238c99ea7..ca45f0604 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/PointerAnalysisImpl.java +++ b/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/PointerAnalysisImpl.java @@ -1,548 +1,548 @@ -/******************************************************************************* - * 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.ipa.callgraph.propagation; - -import java.util.Collection; -import java.util.Iterator; -import java.util.List; -import java.util.Set; - -import com.ibm.wala.classLoader.IClass; -import com.ibm.wala.classLoader.IField; -import com.ibm.wala.classLoader.NewSiteReference; -import com.ibm.wala.classLoader.ProgramCounter; -import com.ibm.wala.ipa.callgraph.CGNode; -import com.ibm.wala.ipa.callgraph.CallGraph; -import com.ibm.wala.ipa.cha.IClassHierarchy; -import com.ibm.wala.ssa.DefUse; -import com.ibm.wala.ssa.IR; -import com.ibm.wala.ssa.SSAAbstractInvokeInstruction; -import com.ibm.wala.ssa.SSAArrayLoadInstruction; -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.SSAPhiInstruction; -import com.ibm.wala.ssa.SSAPiInstruction; -import com.ibm.wala.ssa.SSAThrowInstruction; -import com.ibm.wala.types.FieldReference; -import com.ibm.wala.types.TypeReference; -import com.ibm.wala.util.collections.HashSetFactory; -import com.ibm.wala.util.collections.Iterator2Iterable; -import com.ibm.wala.util.debug.Assertions; -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; - -/** - * General representation of the results of pointer analysis - */ -public class PointerAnalysisImpl extends AbstractPointerAnalysis { - - /** - * mapping from PointerKey to PointsToSetVariable - */ - private final PointsToMap pointsToMap; - - /** - * Meta-data regarding heap abstractions - */ - private final HeapModel H; - - /** - * An object that abstracts how to model pointers in the heap. - */ - private final PointerKeyFactory pointerKeys; - - /** - * An object that abstracts how to model instances in the heap. - */ - private final InstanceKeyFactory iKeyFactory; - - protected final PropagationCallGraphBuilder builder; - - public PointerAnalysisImpl(PropagationCallGraphBuilder builder, CallGraph cg, PointsToMap pointsToMap, - MutableMapping instanceKeys, PointerKeyFactory pointerKeys, InstanceKeyFactory iKeyFactory) { - super(cg, instanceKeys); - this.builder = builder; - this.pointerKeys = pointerKeys; - this.iKeyFactory = iKeyFactory; - this.pointsToMap = pointsToMap; - if (iKeyFactory == null) { - throw new IllegalArgumentException("null iKeyFactory"); - } - H = makeHeapModel(); - } - - @Override - public String toString() { - StringBuffer result = new StringBuffer("PointerAnalysis:\n"); - for (Iterator it = pointsToMap.iterateKeys(); it.hasNext();) { - PointerKey p = (PointerKey) it.next(); - OrdinalSet O = getPointsToSet(p); - result.append(" ").append(p).append(" ->\n"); - for (Iterator it2 = O.iterator(); it2.hasNext();) { - result.append(" ").append(it2.next()).append("\n"); - } - } - return result.toString(); - } - - private HeapModel makeHeapModel() { - return new HModel(); - } - - /* - * @see com.ibm.wala.ipa.callgraph.propagation.PointerAnalysis#getPointsToSet(com.ibm.wala.ipa.callgraph.propagation.PointerKey) - */ - @SuppressWarnings("unchecked") - public OrdinalSet getPointsToSet(PointerKey key) { - if (pointsToMap.isImplicit(key)) { - return computeImplicitPointsToSet(key); - } - - // special logic to handle contents of char[] from string constants. - if (key instanceof InstanceFieldKey) { - InstanceFieldKey ifk = (InstanceFieldKey) key; - if (ifk.getInstanceKey() instanceof ConstantKey) { - ConstantKey i = (ConstantKey) ifk.getInstanceKey(); - if (i.getValue() instanceof String) { - StringConstantCharArray contents = StringConstantCharArray.make((ConstantKey) i); - instanceKeys.add(contents); - Collection singleton = HashSetFactory.make(); - singleton.add(contents); - return OrdinalSet.toOrdinalSet(singleton, instanceKeys); - } - } - } - - PointsToSetVariable v = pointsToMap.getPointsToSet(key); - - if (v == null) { - return OrdinalSet.empty(); - } else { - IntSet S = v.getValue(); - return new OrdinalSet(S, instanceKeys); - } - } - - /** - * did the pointer analysis use a type filter for a given points-to set? (this is ugly). - */ - public boolean isFiltered(PointerKey key) { - if (pointsToMap.isImplicit(key)) { - return false; - } - PointsToSetVariable v = pointsToMap.getPointsToSet(key); - if (v == null) { - return false; - } else { - return v.getPointerKey() instanceof FilteredPointerKey; - } - } - - protected static class ImplicitPointsToSetVisitor extends SSAInstruction.Visitor { - protected final PointerAnalysisImpl analysis; - - protected final CGNode node; - - protected final LocalPointerKey lpk; - - protected OrdinalSet pointsToSet = null; - - protected ImplicitPointsToSetVisitor(PointerAnalysisImpl analysis, LocalPointerKey lpk) { - this.lpk = lpk; - this.node = lpk.getNode(); - this.analysis = analysis; - } - - @Override - public void visitNew(SSANewInstruction instruction) { - pointsToSet = OrdinalSet.empty(); - } - - @Override - public void visitInvoke(SSAInvokeInstruction instruction) { - pointsToSet = analysis.computeImplicitPointsToSetAtCall(lpk, node, instruction); - } - - @Override - public void visitCheckCast(SSACheckCastInstruction instruction) { - pointsToSet = analysis.computeImplicitPointsToSetAtCheckCast(node, instruction); - } - - @Override - public void visitGetCaughtException(SSAGetCaughtExceptionInstruction instruction) { - pointsToSet = analysis.computeImplicitPointsToSetAtCatch(node, instruction); - } - - @Override - public void visitGet(SSAGetInstruction instruction) { - pointsToSet = analysis.computeImplicitPointsToSetAtGet(node, instruction); - } - - @Override - public void visitPhi(SSAPhiInstruction instruction) { - pointsToSet = analysis.computeImplicitPointsToSetAtPhi(node, instruction); - } - - @Override - public void visitPi(SSAPiInstruction instruction) { - pointsToSet = analysis.computeImplicitPointsToSetAtPi(node, instruction); - } - - @Override - public void visitArrayLoad(SSAArrayLoadInstruction instruction) { - pointsToSet = analysis.computeImplicitPointsToSetAtALoad(node, instruction); - } - }; - - protected ImplicitPointsToSetVisitor makeImplicitPointsToVisitor(LocalPointerKey lpk) { - return new ImplicitPointsToSetVisitor(this, lpk); - } - - private OrdinalSet computeImplicitPointsToSet(PointerKey key) { - if (key instanceof LocalPointerKey) { - LocalPointerKey lpk = (LocalPointerKey) key; - CGNode node = lpk.getNode(); - IR ir = node.getIR(); - DefUse du = node.getDU(); - if (((SSAPropagationCallGraphBuilder) builder).contentsAreInvariant(ir.getSymbolTable(), du, lpk.getValueNumber())) { - // cons up the points-to set for invariant contents - InstanceKey[] ik = ((SSAPropagationCallGraphBuilder) builder).getInvariantContents(ir.getSymbolTable(), du, node, lpk - .getValueNumber(), H, true); - return toOrdinalSet(ik); - } else { - SSAInstruction def = du.getDef(lpk.getValueNumber()); - if (def != null) { - ImplicitPointsToSetVisitor v = makeImplicitPointsToVisitor(lpk); - def.visit(v); - if (v.pointsToSet != null) { - return v.pointsToSet; - } else { - Assertions.UNREACHABLE("saw " + key + ": time to implement for " + def.getClass()); - return null; - } - } else { - Assertions.UNREACHABLE("unexpected null def for " + key); - return null; - } - } - } else { - Assertions.UNREACHABLE("unexpected implicit key " + key + " that's not a local pointer key"); - return null; - } - } - - private OrdinalSet computeImplicitPointsToSetAtPi(CGNode node, SSAPiInstruction instruction) { - MutableSparseIntSet S = MutableSparseIntSet.makeEmpty(); - for (int i = 0; i < instruction.getNumberOfUses(); i++) { - int vn = instruction.getUse(i); - if (vn != -1) { - PointerKey lpk = pointerKeys.getPointerKeyForLocal(node, vn); - OrdinalSet pointees = getPointsToSet(lpk); - IntSet set = pointees.getBackingSet(); - if (set != null) { - S.addAll(set); - } - } - } - return new OrdinalSet(S, instanceKeys); - } - - private OrdinalSet computeImplicitPointsToSetAtPhi(CGNode node, SSAPhiInstruction instruction) { - MutableSparseIntSet S = MutableSparseIntSet.makeEmpty(); - for (int i = 0; i < instruction.getNumberOfUses(); i++) { - int vn = instruction.getUse(i); - if (vn != -1) { - PointerKey lpk = pointerKeys.getPointerKeyForLocal(node, vn); - OrdinalSet pointees = getPointsToSet(lpk); - IntSet set = pointees.getBackingSet(); - if (set != null) { - S.addAll(set); - } - } - } - return new OrdinalSet(S, instanceKeys); - } - - private OrdinalSet computeImplicitPointsToSetAtALoad(CGNode node, SSAArrayLoadInstruction instruction) { - PointerKey arrayRef = pointerKeys.getPointerKeyForLocal(node, instruction.getArrayRef()); - MutableSparseIntSet S = MutableSparseIntSet.makeEmpty(); - OrdinalSet refs = getPointsToSet(arrayRef); - for (Iterator it = refs.iterator(); it.hasNext();) { - InstanceKey ik = (InstanceKey) it.next(); - PointerKey key = pointerKeys.getPointerKeyForArrayContents(ik); - OrdinalSet pointees = getPointsToSet(key); - IntSet set = pointees.getBackingSet(); - if (set != null) { - S.addAll(set); - } - } - return new OrdinalSet(S, instanceKeys); - } - - private OrdinalSet computeImplicitPointsToSetAtGet(CGNode node, SSAGetInstruction instruction) { - return computeImplicitPointsToSetAtGet(node, instruction.getDeclaredField(), instruction.getRef(), instruction.isStatic()); - } - - public OrdinalSet computeImplicitPointsToSetAtGet(CGNode node, FieldReference field, int refVn, boolean isStatic) { - IField f = getCallGraph().getClassHierarchy().resolveField(field); - if (f == null) { - return OrdinalSet.empty(); - } - if (isStatic) { - PointerKey fKey = pointerKeys.getPointerKeyForStaticField(f); - return getPointsToSet(fKey); - } else { - PointerKey ref = pointerKeys.getPointerKeyForLocal(node, refVn); - MutableSparseIntSet S = MutableSparseIntSet.makeEmpty(); - OrdinalSet refs = getPointsToSet(ref); - for (Iterator it = refs.iterator(); it.hasNext();) { - InstanceKey ik = (InstanceKey) it.next(); - PointerKey fkey = pointerKeys.getPointerKeyForInstanceField(ik, f); - if (fkey != null) { - OrdinalSet pointees = getPointsToSet(fkey); - IntSet set = pointees.getBackingSet(); - if (set != null) { - S.addAll(set); - } - } - } - return new OrdinalSet(S, instanceKeys); - } - } - - private OrdinalSet computeImplicitPointsToSetAtCatch(CGNode node, SSAGetCaughtExceptionInstruction instruction) { - IR ir = node.getIR(); - List peis = SSAPropagationCallGraphBuilder.getIncomingPEIs(ir, ir.getBasicBlockForCatch(instruction)); - Set caughtTypes = SSAPropagationCallGraphBuilder.getCaughtExceptionTypes(instruction, ir); - MutableSparseIntSet S = MutableSparseIntSet.makeEmpty(); - // add the instances from each incoming pei ... - for (Iterator it = peis.iterator(); it.hasNext();) { - ProgramCounter peiLoc = it.next(); - SSAInstruction pei = ir.getPEI(peiLoc); - PointerKey e = null; - // first deal with exception variables from calls and throws. - if (pei instanceof SSAAbstractInvokeInstruction) { - SSAAbstractInvokeInstruction s = (SSAAbstractInvokeInstruction) pei; - e = pointerKeys.getPointerKeyForLocal(node, s.getException()); - } else if (pei instanceof SSAThrowInstruction) { - SSAThrowInstruction s = (SSAThrowInstruction) pei; - e = pointerKeys.getPointerKeyForLocal(node, s.getException()); - } - if (e != null) { - OrdinalSet ep = getPointsToSet(e); - for (Iterator it2 = ep.iterator(); it2.hasNext();) { - InstanceKey ik = (InstanceKey) it2.next(); - if (PropagationCallGraphBuilder.catches(caughtTypes, ik.getConcreteType(), getCallGraph().getClassHierarchy())) { - S.add(instanceKeys.getMappedIndex(ik)); - } - } - } - - // Account for those exceptions for which we do not actually have a - // points-to set for - // the pei, but just instance keys - Collection types = pei.getExceptionTypes(); - if (types != null) { - for (Iterator it2 = types.iterator(); it2.hasNext();) { - TypeReference type = (TypeReference) it2.next(); - if (type != null) { - InstanceKey ik = SSAPropagationCallGraphBuilder.getInstanceKeyForPEI(node, peiLoc, type, iKeyFactory); - ConcreteTypeKey ck = (ConcreteTypeKey) ik; - IClass klass = ck.getType(); - if (PropagationCallGraphBuilder.catches(caughtTypes, klass, getCallGraph().getClassHierarchy())) { - S.add(instanceKeys.getMappedIndex(SSAPropagationCallGraphBuilder - .getInstanceKeyForPEI(node, peiLoc, type, iKeyFactory))); - } - } - } - } - } - return new OrdinalSet(S, instanceKeys); - } - - private OrdinalSet computeImplicitPointsToSetAtCheckCast(CGNode node, SSACheckCastInstruction instruction) { - PointerKey rhs = pointerKeys.getPointerKeyForLocal(node, instruction.getVal()); - OrdinalSet rhsSet = getPointsToSet(rhs); - MutableSparseIntSet S = MutableSparseIntSet.makeEmpty(); - for (TypeReference t : instruction.getDeclaredResultTypes()) { - IClass klass = getCallGraph().getClassHierarchy().lookupClass(t); - if (klass == null) { - // could not find the type. conservatively assume Object - return rhsSet; - } else { - if (klass.isInterface()) { - for (Iterator it = rhsSet.iterator(); it.hasNext();) { - InstanceKey ik = (InstanceKey) it.next(); - if (getCallGraph().getClassHierarchy().implementsInterface(ik.getConcreteType(), klass)) { - S.add(getInstanceKeyMapping().getMappedIndex(ik)); - } - } - } else { - for (Iterator it = rhsSet.iterator(); it.hasNext();) { - InstanceKey ik = (InstanceKey) it.next(); - if (getCallGraph().getClassHierarchy().isSubclassOf(ik.getConcreteType(), klass)) { - S.add(getInstanceKeyMapping().getMappedIndex(ik)); - } - } - } - } - } - return new OrdinalSet(S, instanceKeys); - } - - private OrdinalSet computeImplicitPointsToSetAtCall(LocalPointerKey lpk, CGNode node, SSAInvokeInstruction call) { - int exc = call.getException(); - if (lpk.getValueNumber() == exc) { - return computeImplicitExceptionsForCall(node, call); - } else { - Assertions.UNREACHABLE("time to implement me."); - return null; - } - } - - private OrdinalSet toOrdinalSet(InstanceKey[] ik) { - MutableSparseIntSet s = MutableSparseIntSet.makeEmpty(); - for (int i = 0; i < ik.length; i++) { - int index = instanceKeys.getMappedIndex(ik[i]); - if (index != -1) { - s.add(index); - } else { - assert index != -1 : "instance " + ik[i] + " not mapped!"; - } - } - return new OrdinalSet(s, instanceKeys); - } - - /** - * @return the points-to set for the exceptional return values from a particular call site - */ - private OrdinalSet computeImplicitExceptionsForCall(CGNode node, SSAInvokeInstruction call) { - MutableSparseIntSet S = MutableSparseIntSet.makeEmpty(); - for (Iterator it = getCallGraph().getPossibleTargets(node, call.getCallSite()).iterator(); it.hasNext();) { - CGNode target = (CGNode) it.next(); - PointerKey retVal = pointerKeys.getPointerKeyForExceptionalReturnValue(target); - IntSet set = getPointsToSet(retVal).getBackingSet(); - if (set != null) { - S.addAll(set); - } - } - return new OrdinalSet(S, instanceKeys); - } - - /* - * @see com.ibm.wala.ipa.callgraph.propagation.PointerAnalysis#getHeapModel() - */ - public HeapModel getHeapModel() { - return H; - } - - private class HModel implements HeapModel { - - public Iterator iteratePointerKeys() { - return pointsToMap.iterateKeys(); - } - - public InstanceKey getInstanceKeyForAllocation(CGNode node, NewSiteReference allocation) { - return iKeyFactory.getInstanceKeyForAllocation(node, allocation); - } - - public InstanceKey getInstanceKeyForMultiNewArray(CGNode node, NewSiteReference allocation, int dim) { - return iKeyFactory.getInstanceKeyForMultiNewArray(node, allocation, dim); - } - - public InstanceKey getInstanceKeyForConstant(TypeReference type, T S) { - return iKeyFactory.getInstanceKeyForConstant(type, S); - } - - public InstanceKey getInstanceKeyForPEI(CGNode node, ProgramCounter peiLoc, TypeReference type) { - return iKeyFactory.getInstanceKeyForPEI(node, peiLoc, type); - } - - public InstanceKey getInstanceKeyForClassObject(TypeReference type) { - return iKeyFactory.getInstanceKeyForClassObject(type); - } - - /* - * @see com.ibm.wala.ipa.callgraph.propagation.PointerKeyFactory#getPointerKeyForLocal(com.ibm.detox.ipa.callgraph.CGNode, int) - */ - public PointerKey getPointerKeyForLocal(CGNode node, int valueNumber) { - return pointerKeys.getPointerKeyForLocal(node, valueNumber); - } - - public FilteredPointerKey getFilteredPointerKeyForLocal(CGNode node, int valueNumber, FilteredPointerKey.TypeFilter filter) { - return pointerKeys.getFilteredPointerKeyForLocal(node, valueNumber, filter); - } - - /* - * @see com.ibm.wala.ipa.callgraph.propagation.PointerKeyFactory#getPointerKeyForReturnValue(com.ibm.detox.ipa.callgraph.CGNode) - */ - public PointerKey getPointerKeyForReturnValue(CGNode node) { - return pointerKeys.getPointerKeyForReturnValue(node); - } - - /* - * @see - * com.ibm.wala.ipa.callgraph.propagation.PointerKeyFactory#getPointerKeyForExceptionalReturnValue(com.ibm.detox.ipa.callgraph - * .CGNode) - */ - public PointerKey getPointerKeyForExceptionalReturnValue(CGNode node) { - return pointerKeys.getPointerKeyForExceptionalReturnValue(node); - } - - /* - * @see - * com.ibm.wala.ipa.callgraph.propagation.PointerKeyFactory#getPointerKeyForStaticField(com.ibm.wala.classLoader.FieldReference) - */ - public PointerKey getPointerKeyForStaticField(IField f) { - return pointerKeys.getPointerKeyForStaticField(f); - } - - /* - * @see - * com.ibm.wala.ipa.callgraph.propagation.PointerKeyFactory#getPointerKeyForInstance(com.ibm.wala.ipa.callgraph.propagation. - * InstanceKey, com.ibm.wala.classLoader.FieldReference) - */ - public PointerKey getPointerKeyForInstanceField(InstanceKey I, IField field) { - assert field != null; - return pointerKeys.getPointerKeyForInstanceField(I, field); - } - - /* - * @see - * com.ibm.wala.ipa.callgraph.propagation.PointerKeyFactory#getPointerKeyForArrayContents(com.ibm.wala.ipa.callgraph.propagation - * .InstanceKey) - */ - public PointerKey getPointerKeyForArrayContents(InstanceKey I) { - return pointerKeys.getPointerKeyForArrayContents(I); - } - - public IClassHierarchy getClassHierarchy() { - return getCallGraph().getClassHierarchy(); - } - } - - /* - * @see com.ibm.wala.ipa.callgraph.propagation.PointerAnalysis#iteratePointerKeys() - */ - public Iterable getPointerKeys() { - return Iterator2Iterable.make(pointsToMap.iterateKeys()); - } - - public IClassHierarchy getClassHierarchy() { - return builder.getClassHierarchy(); - } -} +/******************************************************************************* + * 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.ipa.callgraph.propagation; + +import java.util.Collection; +import java.util.Iterator; +import java.util.List; +import java.util.Set; + +import com.ibm.wala.classLoader.IClass; +import com.ibm.wala.classLoader.IField; +import com.ibm.wala.classLoader.NewSiteReference; +import com.ibm.wala.classLoader.ProgramCounter; +import com.ibm.wala.ipa.callgraph.CGNode; +import com.ibm.wala.ipa.callgraph.CallGraph; +import com.ibm.wala.ipa.cha.IClassHierarchy; +import com.ibm.wala.ssa.DefUse; +import com.ibm.wala.ssa.IR; +import com.ibm.wala.ssa.SSAAbstractInvokeInstruction; +import com.ibm.wala.ssa.SSAArrayLoadInstruction; +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.SSAPhiInstruction; +import com.ibm.wala.ssa.SSAPiInstruction; +import com.ibm.wala.ssa.SSAThrowInstruction; +import com.ibm.wala.types.FieldReference; +import com.ibm.wala.types.TypeReference; +import com.ibm.wala.util.collections.HashSetFactory; +import com.ibm.wala.util.collections.Iterator2Iterable; +import com.ibm.wala.util.debug.Assertions; +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; + +/** + * General representation of the results of pointer analysis + */ +public class PointerAnalysisImpl extends AbstractPointerAnalysis { + + /** + * mapping from PointerKey to PointsToSetVariable + */ + private final PointsToMap pointsToMap; + + /** + * Meta-data regarding heap abstractions + */ + private final HeapModel H; + + /** + * An object that abstracts how to model pointers in the heap. + */ + private final PointerKeyFactory pointerKeys; + + /** + * An object that abstracts how to model instances in the heap. + */ + private final InstanceKeyFactory iKeyFactory; + + protected final PropagationCallGraphBuilder builder; + + public PointerAnalysisImpl(PropagationCallGraphBuilder builder, CallGraph cg, PointsToMap pointsToMap, + MutableMapping instanceKeys, PointerKeyFactory pointerKeys, InstanceKeyFactory iKeyFactory) { + super(cg, instanceKeys); + this.builder = builder; + this.pointerKeys = pointerKeys; + this.iKeyFactory = iKeyFactory; + this.pointsToMap = pointsToMap; + if (iKeyFactory == null) { + throw new IllegalArgumentException("null iKeyFactory"); + } + H = makeHeapModel(); + } + + @Override + public String toString() { + StringBuffer result = new StringBuffer("PointerAnalysis:\n"); + for (Iterator it = pointsToMap.iterateKeys(); it.hasNext();) { + PointerKey p = (PointerKey) it.next(); + OrdinalSet O = getPointsToSet(p); + result.append(" ").append(p).append(" ->\n"); + for (Iterator it2 = O.iterator(); it2.hasNext();) { + result.append(" ").append(it2.next()).append("\n"); + } + } + return result.toString(); + } + + private HeapModel makeHeapModel() { + return new HModel(); + } + + /* + * @see com.ibm.wala.ipa.callgraph.propagation.PointerAnalysis#getPointsToSet(com.ibm.wala.ipa.callgraph.propagation.PointerKey) + */ + @SuppressWarnings("unchecked") + public OrdinalSet getPointsToSet(PointerKey key) { + if (pointsToMap.isImplicit(key)) { + return computeImplicitPointsToSet(key); + } + + // special logic to handle contents of char[] from string constants. + if (key instanceof InstanceFieldKey) { + InstanceFieldKey ifk = (InstanceFieldKey) key; + if (ifk.getInstanceKey() instanceof ConstantKey) { + ConstantKey i = (ConstantKey) ifk.getInstanceKey(); + if (i.getValue() instanceof String) { + StringConstantCharArray contents = StringConstantCharArray.make((ConstantKey) i); + instanceKeys.add(contents); + Collection singleton = HashSetFactory.make(); + singleton.add(contents); + return OrdinalSet.toOrdinalSet(singleton, instanceKeys); + } + } + } + + PointsToSetVariable v = pointsToMap.getPointsToSet(key); + + if (v == null) { + return OrdinalSet.empty(); + } else { + IntSet S = v.getValue(); + return new OrdinalSet(S, instanceKeys); + } + } + + /** + * did the pointer analysis use a type filter for a given points-to set? (this is ugly). + */ + public boolean isFiltered(PointerKey key) { + if (pointsToMap.isImplicit(key)) { + return false; + } + PointsToSetVariable v = pointsToMap.getPointsToSet(key); + if (v == null) { + return false; + } else { + return v.getPointerKey() instanceof FilteredPointerKey; + } + } + + protected static class ImplicitPointsToSetVisitor extends SSAInstruction.Visitor { + protected final PointerAnalysisImpl analysis; + + protected final CGNode node; + + protected final LocalPointerKey lpk; + + protected OrdinalSet pointsToSet = null; + + protected ImplicitPointsToSetVisitor(PointerAnalysisImpl analysis, LocalPointerKey lpk) { + this.lpk = lpk; + this.node = lpk.getNode(); + this.analysis = analysis; + } + + @Override + public void visitNew(SSANewInstruction instruction) { + pointsToSet = OrdinalSet.empty(); + } + + @Override + public void visitInvoke(SSAInvokeInstruction instruction) { + pointsToSet = analysis.computeImplicitPointsToSetAtCall(lpk, node, instruction); + } + + @Override + public void visitCheckCast(SSACheckCastInstruction instruction) { + pointsToSet = analysis.computeImplicitPointsToSetAtCheckCast(node, instruction); + } + + @Override + public void visitGetCaughtException(SSAGetCaughtExceptionInstruction instruction) { + pointsToSet = analysis.computeImplicitPointsToSetAtCatch(node, instruction); + } + + @Override + public void visitGet(SSAGetInstruction instruction) { + pointsToSet = analysis.computeImplicitPointsToSetAtGet(node, instruction); + } + + @Override + public void visitPhi(SSAPhiInstruction instruction) { + pointsToSet = analysis.computeImplicitPointsToSetAtPhi(node, instruction); + } + + @Override + public void visitPi(SSAPiInstruction instruction) { + pointsToSet = analysis.computeImplicitPointsToSetAtPi(node, instruction); + } + + @Override + public void visitArrayLoad(SSAArrayLoadInstruction instruction) { + pointsToSet = analysis.computeImplicitPointsToSetAtALoad(node, instruction); + } + }; + + protected ImplicitPointsToSetVisitor makeImplicitPointsToVisitor(LocalPointerKey lpk) { + return new ImplicitPointsToSetVisitor(this, lpk); + } + + private OrdinalSet computeImplicitPointsToSet(PointerKey key) { + if (key instanceof LocalPointerKey) { + LocalPointerKey lpk = (LocalPointerKey) key; + CGNode node = lpk.getNode(); + IR ir = node.getIR(); + DefUse du = node.getDU(); + if (((SSAPropagationCallGraphBuilder) builder).contentsAreInvariant(ir.getSymbolTable(), du, lpk.getValueNumber())) { + // cons up the points-to set for invariant contents + InstanceKey[] ik = ((SSAPropagationCallGraphBuilder) builder).getInvariantContents(ir.getSymbolTable(), du, node, lpk + .getValueNumber(), H, true); + return toOrdinalSet(ik); + } else { + SSAInstruction def = du.getDef(lpk.getValueNumber()); + if (def != null) { + ImplicitPointsToSetVisitor v = makeImplicitPointsToVisitor(lpk); + def.visit(v); + if (v.pointsToSet != null) { + return v.pointsToSet; + } else { + Assertions.UNREACHABLE("saw " + key + ": time to implement for " + def.getClass()); + return null; + } + } else { + Assertions.UNREACHABLE("unexpected null def for " + key); + return null; + } + } + } else { + Assertions.UNREACHABLE("unexpected implicit key " + key + " that's not a local pointer key"); + return null; + } + } + + private OrdinalSet computeImplicitPointsToSetAtPi(CGNode node, SSAPiInstruction instruction) { + MutableSparseIntSet S = MutableSparseIntSet.makeEmpty(); + for (int i = 0; i < instruction.getNumberOfUses(); i++) { + int vn = instruction.getUse(i); + if (vn != -1) { + PointerKey lpk = pointerKeys.getPointerKeyForLocal(node, vn); + OrdinalSet pointees = getPointsToSet(lpk); + IntSet set = pointees.getBackingSet(); + if (set != null) { + S.addAll(set); + } + } + } + return new OrdinalSet(S, instanceKeys); + } + + private OrdinalSet computeImplicitPointsToSetAtPhi(CGNode node, SSAPhiInstruction instruction) { + MutableSparseIntSet S = MutableSparseIntSet.makeEmpty(); + for (int i = 0; i < instruction.getNumberOfUses(); i++) { + int vn = instruction.getUse(i); + if (vn != -1) { + PointerKey lpk = pointerKeys.getPointerKeyForLocal(node, vn); + OrdinalSet pointees = getPointsToSet(lpk); + IntSet set = pointees.getBackingSet(); + if (set != null) { + S.addAll(set); + } + } + } + return new OrdinalSet(S, instanceKeys); + } + + private OrdinalSet computeImplicitPointsToSetAtALoad(CGNode node, SSAArrayLoadInstruction instruction) { + PointerKey arrayRef = pointerKeys.getPointerKeyForLocal(node, instruction.getArrayRef()); + MutableSparseIntSet S = MutableSparseIntSet.makeEmpty(); + OrdinalSet refs = getPointsToSet(arrayRef); + for (Iterator it = refs.iterator(); it.hasNext();) { + InstanceKey ik = (InstanceKey) it.next(); + PointerKey key = pointerKeys.getPointerKeyForArrayContents(ik); + OrdinalSet pointees = getPointsToSet(key); + IntSet set = pointees.getBackingSet(); + if (set != null) { + S.addAll(set); + } + } + return new OrdinalSet(S, instanceKeys); + } + + private OrdinalSet computeImplicitPointsToSetAtGet(CGNode node, SSAGetInstruction instruction) { + return computeImplicitPointsToSetAtGet(node, instruction.getDeclaredField(), instruction.getRef(), instruction.isStatic()); + } + + public OrdinalSet computeImplicitPointsToSetAtGet(CGNode node, FieldReference field, int refVn, boolean isStatic) { + IField f = getCallGraph().getClassHierarchy().resolveField(field); + if (f == null) { + return OrdinalSet.empty(); + } + if (isStatic) { + PointerKey fKey = pointerKeys.getPointerKeyForStaticField(f); + return getPointsToSet(fKey); + } else { + PointerKey ref = pointerKeys.getPointerKeyForLocal(node, refVn); + MutableSparseIntSet S = MutableSparseIntSet.makeEmpty(); + OrdinalSet refs = getPointsToSet(ref); + for (Iterator it = refs.iterator(); it.hasNext();) { + InstanceKey ik = (InstanceKey) it.next(); + PointerKey fkey = pointerKeys.getPointerKeyForInstanceField(ik, f); + if (fkey != null) { + OrdinalSet pointees = getPointsToSet(fkey); + IntSet set = pointees.getBackingSet(); + if (set != null) { + S.addAll(set); + } + } + } + return new OrdinalSet(S, instanceKeys); + } + } + + private OrdinalSet computeImplicitPointsToSetAtCatch(CGNode node, SSAGetCaughtExceptionInstruction instruction) { + IR ir = node.getIR(); + List peis = SSAPropagationCallGraphBuilder.getIncomingPEIs(ir, ir.getBasicBlockForCatch(instruction)); + Set caughtTypes = SSAPropagationCallGraphBuilder.getCaughtExceptionTypes(instruction, ir); + MutableSparseIntSet S = MutableSparseIntSet.makeEmpty(); + // add the instances from each incoming pei ... + for (Iterator it = peis.iterator(); it.hasNext();) { + ProgramCounter peiLoc = it.next(); + SSAInstruction pei = ir.getPEI(peiLoc); + PointerKey e = null; + // first deal with exception variables from calls and throws. + if (pei instanceof SSAAbstractInvokeInstruction) { + SSAAbstractInvokeInstruction s = (SSAAbstractInvokeInstruction) pei; + e = pointerKeys.getPointerKeyForLocal(node, s.getException()); + } else if (pei instanceof SSAThrowInstruction) { + SSAThrowInstruction s = (SSAThrowInstruction) pei; + e = pointerKeys.getPointerKeyForLocal(node, s.getException()); + } + if (e != null) { + OrdinalSet ep = getPointsToSet(e); + for (Iterator it2 = ep.iterator(); it2.hasNext();) { + InstanceKey ik = (InstanceKey) it2.next(); + if (PropagationCallGraphBuilder.catches(caughtTypes, ik.getConcreteType(), getCallGraph().getClassHierarchy())) { + S.add(instanceKeys.getMappedIndex(ik)); + } + } + } + + // Account for those exceptions for which we do not actually have a + // points-to set for + // the pei, but just instance keys + Collection types = pei.getExceptionTypes(); + if (types != null) { + for (Iterator it2 = types.iterator(); it2.hasNext();) { + TypeReference type = (TypeReference) it2.next(); + if (type != null) { + InstanceKey ik = SSAPropagationCallGraphBuilder.getInstanceKeyForPEI(node, peiLoc, type, iKeyFactory); + ConcreteTypeKey ck = (ConcreteTypeKey) ik; + IClass klass = ck.getType(); + if (PropagationCallGraphBuilder.catches(caughtTypes, klass, getCallGraph().getClassHierarchy())) { + S.add(instanceKeys.getMappedIndex(SSAPropagationCallGraphBuilder + .getInstanceKeyForPEI(node, peiLoc, type, iKeyFactory))); + } + } + } + } + } + return new OrdinalSet(S, instanceKeys); + } + + private OrdinalSet computeImplicitPointsToSetAtCheckCast(CGNode node, SSACheckCastInstruction instruction) { + PointerKey rhs = pointerKeys.getPointerKeyForLocal(node, instruction.getVal()); + OrdinalSet rhsSet = getPointsToSet(rhs); + MutableSparseIntSet S = MutableSparseIntSet.makeEmpty(); + for (TypeReference t : instruction.getDeclaredResultTypes()) { + IClass klass = getCallGraph().getClassHierarchy().lookupClass(t); + if (klass == null) { + // could not find the type. conservatively assume Object + return rhsSet; + } else { + if (klass.isInterface()) { + for (Iterator it = rhsSet.iterator(); it.hasNext();) { + InstanceKey ik = (InstanceKey) it.next(); + if (getCallGraph().getClassHierarchy().implementsInterface(ik.getConcreteType(), klass)) { + S.add(getInstanceKeyMapping().getMappedIndex(ik)); + } + } + } else { + for (Iterator it = rhsSet.iterator(); it.hasNext();) { + InstanceKey ik = (InstanceKey) it.next(); + if (getCallGraph().getClassHierarchy().isSubclassOf(ik.getConcreteType(), klass)) { + S.add(getInstanceKeyMapping().getMappedIndex(ik)); + } + } + } + } + } + return new OrdinalSet(S, instanceKeys); + } + + private OrdinalSet computeImplicitPointsToSetAtCall(LocalPointerKey lpk, CGNode node, SSAInvokeInstruction call) { + int exc = call.getException(); + if (lpk.getValueNumber() == exc) { + return computeImplicitExceptionsForCall(node, call); + } else { + Assertions.UNREACHABLE("time to implement me."); + return null; + } + } + + private OrdinalSet toOrdinalSet(InstanceKey[] ik) { + MutableSparseIntSet s = MutableSparseIntSet.makeEmpty(); + for (int i = 0; i < ik.length; i++) { + int index = instanceKeys.getMappedIndex(ik[i]); + if (index != -1) { + s.add(index); + } else { + assert index != -1 : "instance " + ik[i] + " not mapped!"; + } + } + return new OrdinalSet(s, instanceKeys); + } + + /** + * @return the points-to set for the exceptional return values from a particular call site + */ + private OrdinalSet computeImplicitExceptionsForCall(CGNode node, SSAInvokeInstruction call) { + MutableSparseIntSet S = MutableSparseIntSet.makeEmpty(); + for (Iterator it = getCallGraph().getPossibleTargets(node, call.getCallSite()).iterator(); it.hasNext();) { + CGNode target = (CGNode) it.next(); + PointerKey retVal = pointerKeys.getPointerKeyForExceptionalReturnValue(target); + IntSet set = getPointsToSet(retVal).getBackingSet(); + if (set != null) { + S.addAll(set); + } + } + return new OrdinalSet(S, instanceKeys); + } + + /* + * @see com.ibm.wala.ipa.callgraph.propagation.PointerAnalysis#getHeapModel() + */ + public HeapModel getHeapModel() { + return H; + } + + private class HModel implements HeapModel { + + public Iterator iteratePointerKeys() { + return pointsToMap.iterateKeys(); + } + + public InstanceKey getInstanceKeyForAllocation(CGNode node, NewSiteReference allocation) { + return iKeyFactory.getInstanceKeyForAllocation(node, allocation); + } + + public InstanceKey getInstanceKeyForMultiNewArray(CGNode node, NewSiteReference allocation, int dim) { + return iKeyFactory.getInstanceKeyForMultiNewArray(node, allocation, dim); + } + + public InstanceKey getInstanceKeyForConstant(TypeReference type, T S) { + return iKeyFactory.getInstanceKeyForConstant(type, S); + } + + public InstanceKey getInstanceKeyForPEI(CGNode node, ProgramCounter peiLoc, TypeReference type) { + return iKeyFactory.getInstanceKeyForPEI(node, peiLoc, type); + } + + public InstanceKey getInstanceKeyForClassObject(TypeReference type) { + return iKeyFactory.getInstanceKeyForClassObject(type); + } + + /* + * @see com.ibm.wala.ipa.callgraph.propagation.PointerKeyFactory#getPointerKeyForLocal(com.ibm.detox.ipa.callgraph.CGNode, int) + */ + public PointerKey getPointerKeyForLocal(CGNode node, int valueNumber) { + return pointerKeys.getPointerKeyForLocal(node, valueNumber); + } + + public FilteredPointerKey getFilteredPointerKeyForLocal(CGNode node, int valueNumber, FilteredPointerKey.TypeFilter filter) { + return pointerKeys.getFilteredPointerKeyForLocal(node, valueNumber, filter); + } + + /* + * @see com.ibm.wala.ipa.callgraph.propagation.PointerKeyFactory#getPointerKeyForReturnValue(com.ibm.detox.ipa.callgraph.CGNode) + */ + public PointerKey getPointerKeyForReturnValue(CGNode node) { + return pointerKeys.getPointerKeyForReturnValue(node); + } + + /* + * @see + * com.ibm.wala.ipa.callgraph.propagation.PointerKeyFactory#getPointerKeyForExceptionalReturnValue(com.ibm.detox.ipa.callgraph + * .CGNode) + */ + public PointerKey getPointerKeyForExceptionalReturnValue(CGNode node) { + return pointerKeys.getPointerKeyForExceptionalReturnValue(node); + } + + /* + * @see + * com.ibm.wala.ipa.callgraph.propagation.PointerKeyFactory#getPointerKeyForStaticField(com.ibm.wala.classLoader.FieldReference) + */ + public PointerKey getPointerKeyForStaticField(IField f) { + return pointerKeys.getPointerKeyForStaticField(f); + } + + /* + * @see + * com.ibm.wala.ipa.callgraph.propagation.PointerKeyFactory#getPointerKeyForInstance(com.ibm.wala.ipa.callgraph.propagation. + * InstanceKey, com.ibm.wala.classLoader.FieldReference) + */ + public PointerKey getPointerKeyForInstanceField(InstanceKey I, IField field) { + assert field != null; + return pointerKeys.getPointerKeyForInstanceField(I, field); + } + + /* + * @see + * com.ibm.wala.ipa.callgraph.propagation.PointerKeyFactory#getPointerKeyForArrayContents(com.ibm.wala.ipa.callgraph.propagation + * .InstanceKey) + */ + public PointerKey getPointerKeyForArrayContents(InstanceKey I) { + return pointerKeys.getPointerKeyForArrayContents(I); + } + + public IClassHierarchy getClassHierarchy() { + return getCallGraph().getClassHierarchy(); + } + } + + /* + * @see com.ibm.wala.ipa.callgraph.propagation.PointerAnalysis#iteratePointerKeys() + */ + public Iterable getPointerKeys() { + return Iterator2Iterable.make(pointsToMap.iterateKeys()); + } + + public IClassHierarchy getClassHierarchy() { + return builder.getClassHierarchy(); + } +} diff --git a/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/PointerKey.java b/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/PointerKey.java index 3a075ede0..7a9becccc 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/PointerKey.java +++ b/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/PointerKey.java @@ -1,29 +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.ipa.callgraph.propagation; - -/** - * A PointerKey instance serves as the representative for an equivalence class - * of pointers. (or more generally ...locations, if we allow primitives). - * - * For example, a PointerKey for 0-CFA might be - a pair, where the - * int represents an SSA value number. This PointerKey would represent all - * values of the pointer of a particular local variable. - a , - * representing the set of instances of a given field in the heap, or of a - * particular static field. - * - * A PointerKey for 0-1-CFA, with 1-level of InstanceVar context in the Grove et - * al. terminology, would instead of FieldReference, use a - pair - */ -public interface PointerKey { - -} +/******************************************************************************* + * 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.ipa.callgraph.propagation; + +/** + * A PointerKey instance serves as the representative for an equivalence class + * of pointers. (or more generally ...locations, if we allow primitives). + * + * For example, a PointerKey for 0-CFA might be - a pair, where the + * int represents an SSA value number. This PointerKey would represent all + * values of the pointer of a particular local variable. - a , + * representing the set of instances of a given field in the heap, or of a + * particular static field. + * + * A PointerKey for 0-1-CFA, with 1-level of InstanceVar context in the Grove et + * al. terminology, would instead of FieldReference, use a - pair + */ +public interface PointerKey { + +} diff --git a/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/PointerKeyComparator.java b/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/PointerKeyComparator.java index 9374c629c..0ae185f0a 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/PointerKeyComparator.java +++ b/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/PointerKeyComparator.java @@ -1,261 +1,261 @@ -/******************************************************************************* - * 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.ipa.callgraph.propagation; - -import java.util.Comparator; - -import com.ibm.wala.classLoader.ArrayClass; -import com.ibm.wala.classLoader.IClass; -import com.ibm.wala.classLoader.IField; -import com.ibm.wala.ipa.callgraph.propagation.cfa.ExceptionReturnValueKey; -import com.ibm.wala.ipa.cha.IClassHierarchy; -import com.ibm.wala.types.TypeReference; -import com.ibm.wala.util.debug.Assertions; - -public class PointerKeyComparator implements Comparator { - - private final IClassHierarchy cha; - - public PointerKeyComparator(IClassHierarchy cha) { - if (cha == null) { - throw new IllegalArgumentException("null cha"); - } - this.cha = cha; - } - - protected int comparePrimitives(TypeReference r1, TypeReference r2) { - int h1 = r1.hashCode(); - int h2 = r2.hashCode(); - if (h1 != h2) - return h1-h2; - else { - assert r1 == r2; - return 0; - } - } - - protected int compareConcreteTypes(IClass k1, IClass k2) { - int n1 = cha.getNumber( k1 ); - int n2 = cha.getNumber( k2 ); - if (n1 != n2) - return n1-n2; - else { - int s1 = k1.hashCode(); - int s2 = k2.hashCode(); - assert k1 == k2 || s1 != s2; - return s1-s2; - } - } - - protected int compareInstanceKeys(InstanceKey k1, InstanceKey k2) { - return compareConcreteTypes( k1.getConcreteType(), k2.getConcreteType() ); - } - - protected int compareFields(IField if1, IField if2) { - int f1 = if1.hashCode(); - int f2 = if2.hashCode(); - if (f1 != f2) - return f1-f2; - else { - assert if1 == if2; - return 0; - } - } - - private int compareLocalKey(LocalPointerKey key1, Object key2) { - if (key2 instanceof LocalPointerKey) { - int l1 = key1.getValueNumber(); - int l2 = ((LocalPointerKey)key2).getValueNumber(); - if (l1 != l2) - return l1-l2; - else { - int n1 = key1.getNode().getGraphNodeId(); - int n2 = ((LocalPointerKey)key2).getNode().getGraphNodeId(); - if (n1 != n2) - return n1-n2; - else { - assert key1.equals(key2); - return 0; - } - } - } - - else return -1; - } - - private int compareReturnValueKey(ReturnValueKey key1, Object key2) { - if (key2 instanceof ReturnValueKey) { - int n1 = key1.getNode().getGraphNodeId(); - int n2 = ((ReturnValueKey)key2).getNode().getGraphNodeId(); - if (n1 != n2) - return n1-n2; - else { - assert key1.equals(key2); - return 0; - } - } - - else return -1; - } - - private int compareExceptionKey(ExceptionReturnValueKey key1, Object key2) { - if (key2 instanceof ExceptionReturnValueKey) { - int n1 = key1.getNode().getGraphNodeId(); - int n2 = ((ExceptionReturnValueKey)key2).getNode().getGraphNodeId(); - if (n1 != n2) - return n1-n2; - else { - assert key1.equals(key2); - return 0; - } - } - - else return -1; - } - - private int compareFieldKey(InstanceFieldKey key1, Object key2) { - if (key2 instanceof InstanceFieldKey) { - int r1 = compareInstanceKeys(key1.getInstanceKey(), ((InstanceFieldKey)key2).getInstanceKey()); - if (r1 != 0) - return r1; - else { - return compareFields(key1.getField(), ((InstanceFieldKey)key2).getField()); - } - } - - else - return -1; - } - - private int compareStaticKey(StaticFieldKey key1, Object key2) { - if (key2 instanceof StaticFieldKey) { - int n1 = cha.getNumber( key1.getField().getDeclaringClass() ); - int n2 = cha.getNumber( ((StaticFieldKey)key2).getField().getDeclaringClass() ); - if (n1 != n2) - return n1-n2; - else { - return compareFields(key1.getField(), ((StaticFieldKey)key2).getField()); - } - } - - else - return -1; - } - - private int compareArrayKey(ArrayContentsKey key1, Object key2) { - if (key2 instanceof ArrayContentsKey) { - ArrayClass k1 = (ArrayClass)key1.getInstanceKey().getConcreteType(); - ArrayClass k2 = (ArrayClass)((ArrayContentsKey)key2).getInstanceKey().getConcreteType(); - int d1 = k1.getDimensionality(); - int d2 = k2.getDimensionality(); - if (d1 != d2) { - return d1-d2; - } else if (k1.getInnermostElementClass() == null) { - if (k2.getInnermostElementClass() == null) - return - comparePrimitives( - k1.getReference().getInnermostElementType(), - k2.getReference().getInnermostElementType()); - else - return -1; - } else if (k2.getInnermostElementClass() == null) { - return 1; - } else { - return - compareConcreteTypes( - k1.getInnermostElementClass(), - k2.getInnermostElementClass()); - } - } - - else - return -1; - } - - public int compare(Object key1, Object key2) { - if (key1 == key2) return 0; - - else if (key1 instanceof LocalPointerKey) { - return compareLocalKey((LocalPointerKey) key1, key2); - } - - else if (key2 instanceof LocalPointerKey) { - return -1*compareLocalKey((LocalPointerKey) key2, key1); - } - - // at this point, neither key is local - else if (key1 instanceof ReturnValueKey) { - return compareReturnValueKey((ReturnValueKey)key1, key2); - } - - else if (key2 instanceof ReturnValueKey) { - return -1*compareReturnValueKey((ReturnValueKey)key2, key1); - } - - // at this point, neither key is local or retval - else if (key1 instanceof ExceptionReturnValueKey) { - return compareExceptionKey((ExceptionReturnValueKey)key1, key2); - } - - else if (key2 instanceof ExceptionReturnValueKey) { - return -1*compareExceptionKey((ExceptionReturnValueKey)key2, key1); - } - - // at this point, neither key is local or retval, expretval - else if (key1 instanceof InstanceFieldKey) { - return compareFieldKey((InstanceFieldKey)key1, key2); - } - - else if (key2 instanceof InstanceFieldKey) { - return -1*compareFieldKey((InstanceFieldKey)key2, key1); - } - - // at this point, neither key is local or retval, expretval, field - else if (key1 instanceof StaticFieldKey) { - return compareStaticKey((StaticFieldKey)key1, key2); - } - - else if (key2 instanceof StaticFieldKey) { - return -1*compareStaticKey((StaticFieldKey)key2, key1); - } - - // at this point, neither key is local or retval, expretval, field, static - else if (key1 instanceof ArrayContentsKey) { - return compareArrayKey((ArrayContentsKey)key1, key2); - } - - else if (key2 instanceof ArrayContentsKey) { - return -1*compareArrayKey((ArrayContentsKey)key2, key1); - } - - else { - return compareOtherKeys(key1, key2); - } - } - - protected int compareOtherKeys(Object key1, Object key2) { - System.err.println("Cannot compare " + key1 + " and " + key2); - Assertions.UNREACHABLE(); - return 0; - } - - @Override - public boolean equals(Object o) { - return (o instanceof PointerKeyComparator) && - ((PointerKeyComparator)o).cha.equals(cha); - } - - @Override - public int hashCode() { - return cha.hashCode(); - } - -} +/******************************************************************************* + * 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.ipa.callgraph.propagation; + +import java.util.Comparator; + +import com.ibm.wala.classLoader.ArrayClass; +import com.ibm.wala.classLoader.IClass; +import com.ibm.wala.classLoader.IField; +import com.ibm.wala.ipa.callgraph.propagation.cfa.ExceptionReturnValueKey; +import com.ibm.wala.ipa.cha.IClassHierarchy; +import com.ibm.wala.types.TypeReference; +import com.ibm.wala.util.debug.Assertions; + +public class PointerKeyComparator implements Comparator { + + private final IClassHierarchy cha; + + public PointerKeyComparator(IClassHierarchy cha) { + if (cha == null) { + throw new IllegalArgumentException("null cha"); + } + this.cha = cha; + } + + protected int comparePrimitives(TypeReference r1, TypeReference r2) { + int h1 = r1.hashCode(); + int h2 = r2.hashCode(); + if (h1 != h2) + return h1-h2; + else { + assert r1 == r2; + return 0; + } + } + + protected int compareConcreteTypes(IClass k1, IClass k2) { + int n1 = cha.getNumber( k1 ); + int n2 = cha.getNumber( k2 ); + if (n1 != n2) + return n1-n2; + else { + int s1 = k1.hashCode(); + int s2 = k2.hashCode(); + assert k1 == k2 || s1 != s2; + return s1-s2; + } + } + + protected int compareInstanceKeys(InstanceKey k1, InstanceKey k2) { + return compareConcreteTypes( k1.getConcreteType(), k2.getConcreteType() ); + } + + protected int compareFields(IField if1, IField if2) { + int f1 = if1.hashCode(); + int f2 = if2.hashCode(); + if (f1 != f2) + return f1-f2; + else { + assert if1 == if2; + return 0; + } + } + + private int compareLocalKey(LocalPointerKey key1, Object key2) { + if (key2 instanceof LocalPointerKey) { + int l1 = key1.getValueNumber(); + int l2 = ((LocalPointerKey)key2).getValueNumber(); + if (l1 != l2) + return l1-l2; + else { + int n1 = key1.getNode().getGraphNodeId(); + int n2 = ((LocalPointerKey)key2).getNode().getGraphNodeId(); + if (n1 != n2) + return n1-n2; + else { + assert key1.equals(key2); + return 0; + } + } + } + + else return -1; + } + + private int compareReturnValueKey(ReturnValueKey key1, Object key2) { + if (key2 instanceof ReturnValueKey) { + int n1 = key1.getNode().getGraphNodeId(); + int n2 = ((ReturnValueKey)key2).getNode().getGraphNodeId(); + if (n1 != n2) + return n1-n2; + else { + assert key1.equals(key2); + return 0; + } + } + + else return -1; + } + + private int compareExceptionKey(ExceptionReturnValueKey key1, Object key2) { + if (key2 instanceof ExceptionReturnValueKey) { + int n1 = key1.getNode().getGraphNodeId(); + int n2 = ((ExceptionReturnValueKey)key2).getNode().getGraphNodeId(); + if (n1 != n2) + return n1-n2; + else { + assert key1.equals(key2); + return 0; + } + } + + else return -1; + } + + private int compareFieldKey(InstanceFieldKey key1, Object key2) { + if (key2 instanceof InstanceFieldKey) { + int r1 = compareInstanceKeys(key1.getInstanceKey(), ((InstanceFieldKey)key2).getInstanceKey()); + if (r1 != 0) + return r1; + else { + return compareFields(key1.getField(), ((InstanceFieldKey)key2).getField()); + } + } + + else + return -1; + } + + private int compareStaticKey(StaticFieldKey key1, Object key2) { + if (key2 instanceof StaticFieldKey) { + int n1 = cha.getNumber( key1.getField().getDeclaringClass() ); + int n2 = cha.getNumber( ((StaticFieldKey)key2).getField().getDeclaringClass() ); + if (n1 != n2) + return n1-n2; + else { + return compareFields(key1.getField(), ((StaticFieldKey)key2).getField()); + } + } + + else + return -1; + } + + private int compareArrayKey(ArrayContentsKey key1, Object key2) { + if (key2 instanceof ArrayContentsKey) { + ArrayClass k1 = (ArrayClass)key1.getInstanceKey().getConcreteType(); + ArrayClass k2 = (ArrayClass)((ArrayContentsKey)key2).getInstanceKey().getConcreteType(); + int d1 = k1.getDimensionality(); + int d2 = k2.getDimensionality(); + if (d1 != d2) { + return d1-d2; + } else if (k1.getInnermostElementClass() == null) { + if (k2.getInnermostElementClass() == null) + return + comparePrimitives( + k1.getReference().getInnermostElementType(), + k2.getReference().getInnermostElementType()); + else + return -1; + } else if (k2.getInnermostElementClass() == null) { + return 1; + } else { + return + compareConcreteTypes( + k1.getInnermostElementClass(), + k2.getInnermostElementClass()); + } + } + + else + return -1; + } + + public int compare(Object key1, Object key2) { + if (key1 == key2) return 0; + + else if (key1 instanceof LocalPointerKey) { + return compareLocalKey((LocalPointerKey) key1, key2); + } + + else if (key2 instanceof LocalPointerKey) { + return -1*compareLocalKey((LocalPointerKey) key2, key1); + } + + // at this point, neither key is local + else if (key1 instanceof ReturnValueKey) { + return compareReturnValueKey((ReturnValueKey)key1, key2); + } + + else if (key2 instanceof ReturnValueKey) { + return -1*compareReturnValueKey((ReturnValueKey)key2, key1); + } + + // at this point, neither key is local or retval + else if (key1 instanceof ExceptionReturnValueKey) { + return compareExceptionKey((ExceptionReturnValueKey)key1, key2); + } + + else if (key2 instanceof ExceptionReturnValueKey) { + return -1*compareExceptionKey((ExceptionReturnValueKey)key2, key1); + } + + // at this point, neither key is local or retval, expretval + else if (key1 instanceof InstanceFieldKey) { + return compareFieldKey((InstanceFieldKey)key1, key2); + } + + else if (key2 instanceof InstanceFieldKey) { + return -1*compareFieldKey((InstanceFieldKey)key2, key1); + } + + // at this point, neither key is local or retval, expretval, field + else if (key1 instanceof StaticFieldKey) { + return compareStaticKey((StaticFieldKey)key1, key2); + } + + else if (key2 instanceof StaticFieldKey) { + return -1*compareStaticKey((StaticFieldKey)key2, key1); + } + + // at this point, neither key is local or retval, expretval, field, static + else if (key1 instanceof ArrayContentsKey) { + return compareArrayKey((ArrayContentsKey)key1, key2); + } + + else if (key2 instanceof ArrayContentsKey) { + return -1*compareArrayKey((ArrayContentsKey)key2, key1); + } + + else { + return compareOtherKeys(key1, key2); + } + } + + protected int compareOtherKeys(Object key1, Object key2) { + System.err.println("Cannot compare " + key1 + " and " + key2); + Assertions.UNREACHABLE(); + return 0; + } + + @Override + public boolean equals(Object o) { + return (o instanceof PointerKeyComparator) && + ((PointerKeyComparator)o).cha.equals(cha); + } + + @Override + public int hashCode() { + return cha.hashCode(); + } + +} diff --git a/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/PointerKeyFactory.java b/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/PointerKeyFactory.java index 48d48a15c..74aa69ee0 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/PointerKeyFactory.java +++ b/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/PointerKeyFactory.java @@ -1,62 +1,62 @@ -/******************************************************************************* - * 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.ipa.callgraph.propagation; - -import com.ibm.wala.classLoader.IField; -import com.ibm.wala.ipa.callgraph.CGNode; - -/** - * An object that abstracts how to model pointers in the heap. - */ -public interface PointerKeyFactory { - /** - * @return the PointerKey that acts as a representative for the class of pointers that includes the local variable identified by - * the value number parameter. - * - */ - PointerKey getPointerKeyForLocal(CGNode node, int valueNumber); - - /** - * @return the PointerKey that acts as a representative for the class of pointers that includes the local variable identified by - * the value number parameter. - * - */ - FilteredPointerKey getFilteredPointerKeyForLocal(CGNode node, int valueNumber, FilteredPointerKey.TypeFilter filter); - - /** - * @param node - * @return the PointerKey that acts as a representative for the class of pointers that includes the return value for a node - */ - PointerKey getPointerKeyForReturnValue(CGNode node); - - /** - * @return the PointerKey that acts as a representative for the class of pointers that includes the exceptional return value - */ - PointerKey getPointerKeyForExceptionalReturnValue(CGNode node); - - /** - * @return the PointerKey that acts as a representative for the class of pointers that includes the contents of the static field - */ - PointerKey getPointerKeyForStaticField(IField f); - - /** - * @return the PointerKey that acts as a representation for the class of pointers that includes the given instance field. - */ - PointerKey getPointerKeyForInstanceField(InstanceKey I, IField field); - - /** - * TODO: expand this API to differentiate between different array indices - * - * @param I an InstanceKey representing an abstract array - * @return the PointerKey that acts as a representation for the class of pointers that includes the given array contents. - */ - PointerKey getPointerKeyForArrayContents(InstanceKey I); -} +/******************************************************************************* + * 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.ipa.callgraph.propagation; + +import com.ibm.wala.classLoader.IField; +import com.ibm.wala.ipa.callgraph.CGNode; + +/** + * An object that abstracts how to model pointers in the heap. + */ +public interface PointerKeyFactory { + /** + * @return the PointerKey that acts as a representative for the class of pointers that includes the local variable identified by + * the value number parameter. + * + */ + PointerKey getPointerKeyForLocal(CGNode node, int valueNumber); + + /** + * @return the PointerKey that acts as a representative for the class of pointers that includes the local variable identified by + * the value number parameter. + * + */ + FilteredPointerKey getFilteredPointerKeyForLocal(CGNode node, int valueNumber, FilteredPointerKey.TypeFilter filter); + + /** + * @param node + * @return the PointerKey that acts as a representative for the class of pointers that includes the return value for a node + */ + PointerKey getPointerKeyForReturnValue(CGNode node); + + /** + * @return the PointerKey that acts as a representative for the class of pointers that includes the exceptional return value + */ + PointerKey getPointerKeyForExceptionalReturnValue(CGNode node); + + /** + * @return the PointerKey that acts as a representative for the class of pointers that includes the contents of the static field + */ + PointerKey getPointerKeyForStaticField(IField f); + + /** + * @return the PointerKey that acts as a representation for the class of pointers that includes the given instance field. + */ + PointerKey getPointerKeyForInstanceField(InstanceKey I, IField field); + + /** + * TODO: expand this API to differentiate between different array indices + * + * @param I an InstanceKey representing an abstract array + * @return the PointerKey that acts as a representation for the class of pointers that includes the given array contents. + */ + PointerKey getPointerKeyForArrayContents(InstanceKey I); +} diff --git a/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/PointsToMap.java b/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/PointsToMap.java index e58622c53..cc4b03dca 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/PointsToMap.java +++ b/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/PointsToMap.java @@ -1,310 +1,310 @@ -/******************************************************************************* - * 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.ipa.callgraph.propagation; - -import java.util.Iterator; - -import com.ibm.wala.util.collections.Filter; -import com.ibm.wala.util.collections.FilterIterator; -import com.ibm.wala.util.collections.IVector; -import com.ibm.wala.util.collections.SimpleVector; -import com.ibm.wala.util.debug.Assertions; -import com.ibm.wala.util.intset.BitVector; -import com.ibm.wala.util.intset.IntIterator; -import com.ibm.wala.util.intset.IntSet; -import com.ibm.wala.util.intset.IntegerUnionFind; -import com.ibm.wala.util.intset.MutableMapping; - -/** - * An object that tracks the mapping between pointer keys and points-to set variables - */ -public class PointsToMap { - - /** - * An object that manages the numbering of pointer keys - */ - private final MutableMapping pointerKeys = MutableMapping.make(); - - /** - * pointsToSets[i] says something about the representation of the points-to set for the ith {@link PointerKey}, as determined by - * the pointerKeys mapping. pointsToSets[i] can be one of the following: - *
          - *
        • a PointsToSetVariable - *
        • IMPLICIT - *
        • UNIFIED - *
        - */ - private final IVector pointsToSets = new SimpleVector(); - - private final IntegerUnionFind uf = new IntegerUnionFind(); - - /** - * A hack: used to represent points-to-sets that are represented implicitly - */ - final static Object IMPLICIT = new Object() { - @Override - public String toString() { - return "IMPLICIT points-to set"; - } - }; - - /** - * A hack: used to represent points-to-sets that are unified with another - */ - final static Object UNIFIED = new Object() { - @Override - public String toString() { - return "UNIFIED points-to set"; - } - }; - - /** - * Numbers of pointer keys (non locals) that are roots of transitive closure. A "root" is a points-to-set whose contents do not - * result from flow from other points-to-sets; these points-to-sets are the primordial assignments from which the transitive - * closure flows. - */ - private final BitVector transitiveRoots = new BitVector(); - - /** - * @return iterator of all PointerKeys tracked - */ - public Iterator iterateKeys() { - return pointerKeys.iterator(); - } - - /** - * If p is unified, returns the representative for p. - */ - public PointsToSetVariable getPointsToSet(PointerKey p) { - if (p == null) { - throw new IllegalArgumentException("null p"); - } - if (isImplicit(p)) { - throw new IllegalArgumentException("unexpected: shouldn't ask a PointsToMap for an implicit points-to-set: " + p); - } - int i = pointerKeys.getMappedIndex(p); - if (i == -1) { - return null; - } - int repI = uf.find(i); - PointsToSetVariable result = (PointsToSetVariable) pointsToSets.get(repI); - if (result != null && p instanceof FilteredPointerKey && (!(result.getPointerKey() instanceof FilteredPointerKey))) { - upgradeToFilter(result, ((FilteredPointerKey) p).getTypeFilter()); - } - return result; - } - - /** - * @return the {@link PointsToSetVariable} recorded for a particular id - */ - public PointsToSetVariable getPointsToSet(int id) { - int repI = uf.find(id); - return (PointsToSetVariable) pointsToSets.get(repI); - } - - /** - * record that a particular points-to-set is represented implicitly - */ - public void recordImplicit(PointerKey key) { - if (key == null) { - throw new IllegalArgumentException("null key"); - } - int i = findOrCreateIndex(key); - pointsToSets.set(i, IMPLICIT); - } - - public void put(PointerKey key, PointsToSetVariable v) { - int i = findOrCreateIndex(key); - pointsToSets.set(i, v); - } - - private int findOrCreateIndex(PointerKey key) { - int result = pointerKeys.getMappedIndex(key); - if (result == -1) { - result = pointerKeys.add(key); - } - return result; - } - - /** - * record that a particular points-to-set has been unioned with another - */ - public void recordUnified(PointerKey key) { - if (key == null) { - throw new IllegalArgumentException("null key"); - } - int i = findOrCreateIndex(key); - pointsToSets.set(i, UNIFIED); - } - - /** - * record points-to-sets that are "roots" of the transitive closure. These points-to-sets can't be thrown away for a - * pre-transitive solver. A "root" is a points-to-set whose contents do not result from flow from other points-to-sets; there - * points-to-sets are the primordial assignments from which the transitive closure flows. - */ - public void recordTransitiveRoot(PointerKey key) { - if (key == null) { - throw new IllegalArgumentException("null key"); - } - int i = findOrCreateIndex(key); - transitiveRoots.set(i); - } - - /** - * A "root" is a points-to-set whose contents do not result from flow from other points-to-sets; there points-to-sets are the - * primordial assignments from which the transitive closure flows. - */ - boolean isTransitiveRoot(PointerKey key) { - int i = findOrCreateIndex(key); - return transitiveRoots.get(i); - } - - public boolean isUnified(PointerKey p) { - if (p == null) { - throw new IllegalArgumentException("null p"); - } - int i = findOrCreateIndex(p); - return pointsToSets.get(i) == UNIFIED; - } - - public boolean isImplicit(PointerKey p) { - int i = getIndex(p); - return i != -1 && pointsToSets.get(i) == IMPLICIT; - } - - protected int getNumberOfPointerKeys() { - return pointerKeys.getSize(); - } - - /** - * Wipe out the cached transitive closure information - */ - public void revertToPreTransitive() { - for (Iterator it = iterateKeys(); it.hasNext();) { - PointerKey key = (PointerKey) it.next(); - if (!isTransitiveRoot(key) && !isImplicit(key) && !isUnified(key)) { - PointsToSetVariable v = getPointsToSet(key); - v.removeAll(); - } - } - } - - /** - * @return Iterator - */ - public Iterator getTransitiveRoots() { - return new FilterIterator(iterateKeys(), new Filter() { - public boolean accepts(Object o) { - return isTransitiveRoot((PointerKey) o); - } - }); - } - - /** - * Unify the points-to-sets for the variables identified by the set s - * - * @param s numbers of points-to-set variables - * @throws IllegalArgumentException if s is null - */ - public void unify(IntSet s) throws IllegalArgumentException { - if (s == null) { - throw new IllegalArgumentException("s is null"); - } - if (s.size() <= 1) { - throw new IllegalArgumentException("Can't unify set of size " + s.size()); - } - IntIterator it = s.intIterator(); - int i = it.next(); - while (it.hasNext()) { - unify(i, it.next()); - } - } - - /** - * Unify the points-to-sets for the variables with numbers i and j - */ - public void unify(int i, int j) { - int repI = uf.find(i); - int repJ = uf.find(j); - if (repI != repJ) { - PointsToSetVariable pi = (PointsToSetVariable) pointsToSets.get(repI); - PointsToSetVariable pj = (PointsToSetVariable) pointsToSets.get(repJ); - if (pi == null) { - throw new IllegalArgumentException("No PointsToSetVariable for i: " + i); - } - if (pj == null) { - throw new IllegalArgumentException("No PointsToSetVariable for j: " + j); - } - uf.union(repI, repJ); - int rep = uf.find(repI); - PointsToSetVariable p = (PointsToSetVariable) pointsToSets.get(rep); - if (pi.getValue() != null) { - p.addAll(pi.getValue()); - } - if (pj.getValue() != null) { - p.addAll(pj.getValue()); - } - if (p != pi) { - recordUnified(pi.getPointerKey()); - upgradeTypeFilter(pi, p); - } - if (p != pj) { - recordUnified(pj.getPointerKey()); - upgradeTypeFilter(pj, p); - } - if (isTransitiveRoot(pi.getPointerKey()) || isTransitiveRoot(pj.getPointerKey())) { - recordTransitiveRoot(p.getPointerKey()); - } - } - } - - private void upgradeTypeFilter(PointsToSetVariable src, PointsToSetVariable dest) { - if (src.getPointerKey() instanceof FilteredPointerKey) { - FilteredPointerKey fpk = (FilteredPointerKey) src.getPointerKey(); - if (dest.getPointerKey() instanceof FilteredPointerKey) { - FilteredPointerKey fp = (FilteredPointerKey) dest.getPointerKey(); - if (!fp.getTypeFilter().equals(fpk.getTypeFilter())) { - Assertions.UNREACHABLE("src " + fpk.getTypeFilter() + " dest " + fp.getTypeFilter()); - } - } else { - upgradeToFilter(dest, fpk.getTypeFilter()); - } - } - } - - private void upgradeToFilter(PointsToSetVariable p, FilteredPointerKey.TypeFilter typeFilter) { - if (p.getPointerKey() instanceof LocalPointerKey) { - LocalPointerKey lpk = (LocalPointerKey) p.getPointerKey(); - LocalPointerKeyWithFilter f = new LocalPointerKeyWithFilter(lpk.getNode(), lpk.getValueNumber(), typeFilter); - p.setPointerKey(f); - pointerKeys.replace(lpk, f); - } else if (p.getPointerKey() instanceof ReturnValueKey) { - ReturnValueKey r = (ReturnValueKey) p.getPointerKey(); - ReturnValueKeyWithFilter f = new ReturnValueKeyWithFilter(r.getNode(), typeFilter); - p.setPointerKey(f); - pointerKeys.replace(r, f); - } else { - Assertions.UNREACHABLE(p.getPointerKey().getClass().toString()); - } - } - - /** - * @return the unique integer that identifies this pointer key - */ - public int getIndex(PointerKey p) { - return pointerKeys.getMappedIndex(p); - } - - public int getRepresentative(int i) { - return uf.find(i); - } - -} +/******************************************************************************* + * 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.ipa.callgraph.propagation; + +import java.util.Iterator; + +import com.ibm.wala.util.collections.Filter; +import com.ibm.wala.util.collections.FilterIterator; +import com.ibm.wala.util.collections.IVector; +import com.ibm.wala.util.collections.SimpleVector; +import com.ibm.wala.util.debug.Assertions; +import com.ibm.wala.util.intset.BitVector; +import com.ibm.wala.util.intset.IntIterator; +import com.ibm.wala.util.intset.IntSet; +import com.ibm.wala.util.intset.IntegerUnionFind; +import com.ibm.wala.util.intset.MutableMapping; + +/** + * An object that tracks the mapping between pointer keys and points-to set variables + */ +public class PointsToMap { + + /** + * An object that manages the numbering of pointer keys + */ + private final MutableMapping pointerKeys = MutableMapping.make(); + + /** + * pointsToSets[i] says something about the representation of the points-to set for the ith {@link PointerKey}, as determined by + * the pointerKeys mapping. pointsToSets[i] can be one of the following: + *
          + *
        • a PointsToSetVariable + *
        • IMPLICIT + *
        • UNIFIED + *
        + */ + private final IVector pointsToSets = new SimpleVector(); + + private final IntegerUnionFind uf = new IntegerUnionFind(); + + /** + * A hack: used to represent points-to-sets that are represented implicitly + */ + final static Object IMPLICIT = new Object() { + @Override + public String toString() { + return "IMPLICIT points-to set"; + } + }; + + /** + * A hack: used to represent points-to-sets that are unified with another + */ + final static Object UNIFIED = new Object() { + @Override + public String toString() { + return "UNIFIED points-to set"; + } + }; + + /** + * Numbers of pointer keys (non locals) that are roots of transitive closure. A "root" is a points-to-set whose contents do not + * result from flow from other points-to-sets; these points-to-sets are the primordial assignments from which the transitive + * closure flows. + */ + private final BitVector transitiveRoots = new BitVector(); + + /** + * @return iterator of all PointerKeys tracked + */ + public Iterator iterateKeys() { + return pointerKeys.iterator(); + } + + /** + * If p is unified, returns the representative for p. + */ + public PointsToSetVariable getPointsToSet(PointerKey p) { + if (p == null) { + throw new IllegalArgumentException("null p"); + } + if (isImplicit(p)) { + throw new IllegalArgumentException("unexpected: shouldn't ask a PointsToMap for an implicit points-to-set: " + p); + } + int i = pointerKeys.getMappedIndex(p); + if (i == -1) { + return null; + } + int repI = uf.find(i); + PointsToSetVariable result = (PointsToSetVariable) pointsToSets.get(repI); + if (result != null && p instanceof FilteredPointerKey && (!(result.getPointerKey() instanceof FilteredPointerKey))) { + upgradeToFilter(result, ((FilteredPointerKey) p).getTypeFilter()); + } + return result; + } + + /** + * @return the {@link PointsToSetVariable} recorded for a particular id + */ + public PointsToSetVariable getPointsToSet(int id) { + int repI = uf.find(id); + return (PointsToSetVariable) pointsToSets.get(repI); + } + + /** + * record that a particular points-to-set is represented implicitly + */ + public void recordImplicit(PointerKey key) { + if (key == null) { + throw new IllegalArgumentException("null key"); + } + int i = findOrCreateIndex(key); + pointsToSets.set(i, IMPLICIT); + } + + public void put(PointerKey key, PointsToSetVariable v) { + int i = findOrCreateIndex(key); + pointsToSets.set(i, v); + } + + private int findOrCreateIndex(PointerKey key) { + int result = pointerKeys.getMappedIndex(key); + if (result == -1) { + result = pointerKeys.add(key); + } + return result; + } + + /** + * record that a particular points-to-set has been unioned with another + */ + public void recordUnified(PointerKey key) { + if (key == null) { + throw new IllegalArgumentException("null key"); + } + int i = findOrCreateIndex(key); + pointsToSets.set(i, UNIFIED); + } + + /** + * record points-to-sets that are "roots" of the transitive closure. These points-to-sets can't be thrown away for a + * pre-transitive solver. A "root" is a points-to-set whose contents do not result from flow from other points-to-sets; there + * points-to-sets are the primordial assignments from which the transitive closure flows. + */ + public void recordTransitiveRoot(PointerKey key) { + if (key == null) { + throw new IllegalArgumentException("null key"); + } + int i = findOrCreateIndex(key); + transitiveRoots.set(i); + } + + /** + * A "root" is a points-to-set whose contents do not result from flow from other points-to-sets; there points-to-sets are the + * primordial assignments from which the transitive closure flows. + */ + boolean isTransitiveRoot(PointerKey key) { + int i = findOrCreateIndex(key); + return transitiveRoots.get(i); + } + + public boolean isUnified(PointerKey p) { + if (p == null) { + throw new IllegalArgumentException("null p"); + } + int i = findOrCreateIndex(p); + return pointsToSets.get(i) == UNIFIED; + } + + public boolean isImplicit(PointerKey p) { + int i = getIndex(p); + return i != -1 && pointsToSets.get(i) == IMPLICIT; + } + + protected int getNumberOfPointerKeys() { + return pointerKeys.getSize(); + } + + /** + * Wipe out the cached transitive closure information + */ + public void revertToPreTransitive() { + for (Iterator it = iterateKeys(); it.hasNext();) { + PointerKey key = (PointerKey) it.next(); + if (!isTransitiveRoot(key) && !isImplicit(key) && !isUnified(key)) { + PointsToSetVariable v = getPointsToSet(key); + v.removeAll(); + } + } + } + + /** + * @return Iterator + */ + public Iterator getTransitiveRoots() { + return new FilterIterator(iterateKeys(), new Filter() { + public boolean accepts(Object o) { + return isTransitiveRoot((PointerKey) o); + } + }); + } + + /** + * Unify the points-to-sets for the variables identified by the set s + * + * @param s numbers of points-to-set variables + * @throws IllegalArgumentException if s is null + */ + public void unify(IntSet s) throws IllegalArgumentException { + if (s == null) { + throw new IllegalArgumentException("s is null"); + } + if (s.size() <= 1) { + throw new IllegalArgumentException("Can't unify set of size " + s.size()); + } + IntIterator it = s.intIterator(); + int i = it.next(); + while (it.hasNext()) { + unify(i, it.next()); + } + } + + /** + * Unify the points-to-sets for the variables with numbers i and j + */ + public void unify(int i, int j) { + int repI = uf.find(i); + int repJ = uf.find(j); + if (repI != repJ) { + PointsToSetVariable pi = (PointsToSetVariable) pointsToSets.get(repI); + PointsToSetVariable pj = (PointsToSetVariable) pointsToSets.get(repJ); + if (pi == null) { + throw new IllegalArgumentException("No PointsToSetVariable for i: " + i); + } + if (pj == null) { + throw new IllegalArgumentException("No PointsToSetVariable for j: " + j); + } + uf.union(repI, repJ); + int rep = uf.find(repI); + PointsToSetVariable p = (PointsToSetVariable) pointsToSets.get(rep); + if (pi.getValue() != null) { + p.addAll(pi.getValue()); + } + if (pj.getValue() != null) { + p.addAll(pj.getValue()); + } + if (p != pi) { + recordUnified(pi.getPointerKey()); + upgradeTypeFilter(pi, p); + } + if (p != pj) { + recordUnified(pj.getPointerKey()); + upgradeTypeFilter(pj, p); + } + if (isTransitiveRoot(pi.getPointerKey()) || isTransitiveRoot(pj.getPointerKey())) { + recordTransitiveRoot(p.getPointerKey()); + } + } + } + + private void upgradeTypeFilter(PointsToSetVariable src, PointsToSetVariable dest) { + if (src.getPointerKey() instanceof FilteredPointerKey) { + FilteredPointerKey fpk = (FilteredPointerKey) src.getPointerKey(); + if (dest.getPointerKey() instanceof FilteredPointerKey) { + FilteredPointerKey fp = (FilteredPointerKey) dest.getPointerKey(); + if (!fp.getTypeFilter().equals(fpk.getTypeFilter())) { + Assertions.UNREACHABLE("src " + fpk.getTypeFilter() + " dest " + fp.getTypeFilter()); + } + } else { + upgradeToFilter(dest, fpk.getTypeFilter()); + } + } + } + + private void upgradeToFilter(PointsToSetVariable p, FilteredPointerKey.TypeFilter typeFilter) { + if (p.getPointerKey() instanceof LocalPointerKey) { + LocalPointerKey lpk = (LocalPointerKey) p.getPointerKey(); + LocalPointerKeyWithFilter f = new LocalPointerKeyWithFilter(lpk.getNode(), lpk.getValueNumber(), typeFilter); + p.setPointerKey(f); + pointerKeys.replace(lpk, f); + } else if (p.getPointerKey() instanceof ReturnValueKey) { + ReturnValueKey r = (ReturnValueKey) p.getPointerKey(); + ReturnValueKeyWithFilter f = new ReturnValueKeyWithFilter(r.getNode(), typeFilter); + p.setPointerKey(f); + pointerKeys.replace(r, f); + } else { + Assertions.UNREACHABLE(p.getPointerKey().getClass().toString()); + } + } + + /** + * @return the unique integer that identifies this pointer key + */ + public int getIndex(PointerKey p) { + return pointerKeys.getMappedIndex(p); + } + + public int getRepresentative(int i) { + return uf.find(i); + } + +} diff --git a/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/PointsToSetVariable.java b/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/PointsToSetVariable.java index af29270cd..f016a093d 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/PointsToSetVariable.java +++ b/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/PointsToSetVariable.java @@ -1,166 +1,166 @@ -/******************************************************************************* - * Copyright (c) 2002 - 2006 IBM Corporation. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * IBM Corporation - initial API and implementation - *******************************************************************************/ -package com.ibm.wala.ipa.callgraph.propagation; - -import com.ibm.wala.analysis.typeInference.TypeInference; -import com.ibm.wala.classLoader.IClass; -import com.ibm.wala.fixpoint.IntSetVariable; -import com.ibm.wala.ipa.callgraph.CGNode; -import com.ibm.wala.ipa.cha.IClassHierarchy; -import com.ibm.wala.ssa.IR; -import com.ibm.wala.types.TypeReference; -import com.ibm.wala.util.debug.Assertions; -import com.ibm.wala.util.intset.IntSet; -import com.ibm.wala.util.intset.IntSetAction; -import com.ibm.wala.util.intset.MutableMapping; -import com.ibm.wala.util.intset.MutableSparseIntSet; - -/** - * Representation of a points-to set during an andersen-style analysis. - */ -public class PointsToSetVariable extends IntSetVariable { - /** - * if set, emits a warning whenever a points-to set grows bigger than {@link #SIZE_THRESHOLD} - */ - public static final boolean CRY_ABOUT_BIG_POINTSTO_SETS = false; - public static final int SIZE_THRESHOLD = 100; - - /** - * if set, check that all instance keys in a points-to set are consistent with the type of the corresponding pointer key - */ - public static final boolean PARANOID = false; - - /** - * used only for paranoid checking. a bit ugly, but avoids adding an instance field just for debugging - */ - public static MutableMapping instanceKeys = null; - - private PointerKey pointerKey; - - public PointsToSetVariable(PointerKey key) { - super(); - if (key == null) { - throw new IllegalArgumentException("null key"); - } - this.pointerKey = key; - } - - public PointerKey getPointerKey() { - return pointerKey; - } - - @Override - public boolean equals(Object obj) { - if (obj instanceof PointsToSetVariable) { - return pointerKey.equals(((PointsToSetVariable) obj).pointerKey); - } else { - return false; - } - } - - private boolean cried = false; - @SuppressWarnings("unused") - private void cryIfTooBig() { - if (CRY_ABOUT_BIG_POINTSTO_SETS && !cried && super.size() > SIZE_THRESHOLD) { - cried = true; - System.err.println("too big: " + pointerKey + ": " + size()); - } - } - - @Override - public void add(int b) { - if (PARANOID) { - MutableSparseIntSet m = MutableSparseIntSet.createMutableSparseIntSet(1); - m.add(b); - checkTypes(m); - } - super.add(b); - cryIfTooBig(); - } - - @Override - public boolean addAll(IntSet B) { - if (PARANOID) { - checkTypes(B); - } - boolean v = super.addAll(B); - cryIfTooBig(); - return v; - } - - /** - * check that the types of all instance keys are assignable to declared type of pointer key - */ - private void checkTypes(IntSet b) { - assert PARANOID; - if (b == null) - return; - if (!(pointerKey instanceof LocalPointerKey)) { - return; - } - final LocalPointerKey lpk = (LocalPointerKey) pointerKey; - CGNode node = lpk.getNode(); - final IClassHierarchy cha = node.getClassHierarchy(); - final IR ir = node.getIR(); - if (ir == null) - return; - TypeInference ti = TypeInference.make(ir, false); - final IClass type = ti.getType(lpk.getValueNumber()).getType(); - if (type == null) - return; - // don't perform checking for exception variables - if (cha.isAssignableFrom(cha.lookupClass(TypeReference.JavaLangThrowable), type)) { - return; - } - b.foreach(new IntSetAction() { - - public void act(int x) { - InstanceKey ik = instanceKeys.getMappedObject(x); - IClass concreteType = ik.getConcreteType(); - if (!cha.isAssignableFrom(type, concreteType)) { - System.err.println("BOOM"); - System.err.println(ir); - System.err.println(lpk + " type " + type); - System.err.println(ik + " type " + concreteType); - Assertions.UNREACHABLE(); - } - } - - }); - } - - @Override - public boolean addAll(PointsToSetVariable other) { - if (PARANOID) { - checkTypes(other.getValue()); - } - // TODO Auto-generated method stub - boolean v = super.addAll(other); - cryIfTooBig(); - return v; - } - - /** - * Use this with extreme care, to add filters to this variable.. - * - * @param pointerKey The pointerKey to set. - */ - void setPointerKey(PointerKey pointerKey) { - // check that we haven't modified the hash code!!! this is crucial - assert this.pointerKey.hashCode() == pointerKey.hashCode(); - this.pointerKey = pointerKey; - } - - @Override - public String toString() { - return pointerKey.toString() + ":" + super.toString(); - } -} +/******************************************************************************* + * 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.ipa.callgraph.propagation; + +import com.ibm.wala.analysis.typeInference.TypeInference; +import com.ibm.wala.classLoader.IClass; +import com.ibm.wala.fixpoint.IntSetVariable; +import com.ibm.wala.ipa.callgraph.CGNode; +import com.ibm.wala.ipa.cha.IClassHierarchy; +import com.ibm.wala.ssa.IR; +import com.ibm.wala.types.TypeReference; +import com.ibm.wala.util.debug.Assertions; +import com.ibm.wala.util.intset.IntSet; +import com.ibm.wala.util.intset.IntSetAction; +import com.ibm.wala.util.intset.MutableMapping; +import com.ibm.wala.util.intset.MutableSparseIntSet; + +/** + * Representation of a points-to set during an andersen-style analysis. + */ +public class PointsToSetVariable extends IntSetVariable { + /** + * if set, emits a warning whenever a points-to set grows bigger than {@link #SIZE_THRESHOLD} + */ + public static final boolean CRY_ABOUT_BIG_POINTSTO_SETS = false; + public static final int SIZE_THRESHOLD = 100; + + /** + * if set, check that all instance keys in a points-to set are consistent with the type of the corresponding pointer key + */ + public static final boolean PARANOID = false; + + /** + * used only for paranoid checking. a bit ugly, but avoids adding an instance field just for debugging + */ + public static MutableMapping instanceKeys = null; + + private PointerKey pointerKey; + + public PointsToSetVariable(PointerKey key) { + super(); + if (key == null) { + throw new IllegalArgumentException("null key"); + } + this.pointerKey = key; + } + + public PointerKey getPointerKey() { + return pointerKey; + } + + @Override + public boolean equals(Object obj) { + if (obj instanceof PointsToSetVariable) { + return pointerKey.equals(((PointsToSetVariable) obj).pointerKey); + } else { + return false; + } + } + + private boolean cried = false; + @SuppressWarnings("unused") + private void cryIfTooBig() { + if (CRY_ABOUT_BIG_POINTSTO_SETS && !cried && super.size() > SIZE_THRESHOLD) { + cried = true; + System.err.println("too big: " + pointerKey + ": " + size()); + } + } + + @Override + public void add(int b) { + if (PARANOID) { + MutableSparseIntSet m = MutableSparseIntSet.createMutableSparseIntSet(1); + m.add(b); + checkTypes(m); + } + super.add(b); + cryIfTooBig(); + } + + @Override + public boolean addAll(IntSet B) { + if (PARANOID) { + checkTypes(B); + } + boolean v = super.addAll(B); + cryIfTooBig(); + return v; + } + + /** + * check that the types of all instance keys are assignable to declared type of pointer key + */ + private void checkTypes(IntSet b) { + assert PARANOID; + if (b == null) + return; + if (!(pointerKey instanceof LocalPointerKey)) { + return; + } + final LocalPointerKey lpk = (LocalPointerKey) pointerKey; + CGNode node = lpk.getNode(); + final IClassHierarchy cha = node.getClassHierarchy(); + final IR ir = node.getIR(); + if (ir == null) + return; + TypeInference ti = TypeInference.make(ir, false); + final IClass type = ti.getType(lpk.getValueNumber()).getType(); + if (type == null) + return; + // don't perform checking for exception variables + if (cha.isAssignableFrom(cha.lookupClass(TypeReference.JavaLangThrowable), type)) { + return; + } + b.foreach(new IntSetAction() { + + public void act(int x) { + InstanceKey ik = instanceKeys.getMappedObject(x); + IClass concreteType = ik.getConcreteType(); + if (!cha.isAssignableFrom(type, concreteType)) { + System.err.println("BOOM"); + System.err.println(ir); + System.err.println(lpk + " type " + type); + System.err.println(ik + " type " + concreteType); + Assertions.UNREACHABLE(); + } + } + + }); + } + + @Override + public boolean addAll(PointsToSetVariable other) { + if (PARANOID) { + checkTypes(other.getValue()); + } + // TODO Auto-generated method stub + boolean v = super.addAll(other); + cryIfTooBig(); + return v; + } + + /** + * Use this with extreme care, to add filters to this variable.. + * + * @param pointerKey The pointerKey to set. + */ + void setPointerKey(PointerKey pointerKey) { + // check that we haven't modified the hash code!!! this is crucial + assert this.pointerKey.hashCode() == pointerKey.hashCode(); + this.pointerKey = pointerKey; + } + + @Override + public String toString() { + return pointerKey.toString() + ":" + super.toString(); + } +} diff --git a/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/PropagationCallGraphBuilder.java b/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/PropagationCallGraphBuilder.java index e5ef06b7b..372c3a108 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/PropagationCallGraphBuilder.java +++ b/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/PropagationCallGraphBuilder.java @@ -1,1462 +1,1462 @@ -/******************************************************************************* - * 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.ipa.callgraph.propagation; - -import java.util.Iterator; -import java.util.List; -import java.util.Set; - -import com.ibm.wala.analysis.reflection.IllegalArgumentExceptionContext; -import com.ibm.wala.classLoader.CallSiteReference; -import com.ibm.wala.classLoader.IClass; -import com.ibm.wala.classLoader.IField; -import com.ibm.wala.classLoader.IMethod; -import com.ibm.wala.classLoader.Language; -import com.ibm.wala.classLoader.NewSiteReference; -import com.ibm.wala.classLoader.SyntheticClass; -import com.ibm.wala.fixpoint.UnaryOperator; -import com.ibm.wala.ipa.callgraph.AnalysisCache; -import com.ibm.wala.ipa.callgraph.AnalysisOptions; -import com.ibm.wala.ipa.callgraph.CGNode; -import com.ibm.wala.ipa.callgraph.CallGraph; -import com.ibm.wala.ipa.callgraph.CallGraphBuilder; -import com.ibm.wala.ipa.callgraph.CallGraphBuilderCancelException; -import com.ibm.wala.ipa.callgraph.Context; -import com.ibm.wala.ipa.callgraph.ContextSelector; -import com.ibm.wala.ipa.callgraph.Entrypoint; -import com.ibm.wala.ipa.callgraph.impl.AbstractRootMethod; -import com.ibm.wala.ipa.callgraph.impl.ExplicitCallGraph; -import com.ibm.wala.ipa.callgraph.propagation.rta.RTAContextInterpreter; -import com.ibm.wala.ipa.cha.IClassHierarchy; -import com.ibm.wala.ssa.SSAAbstractInvokeInstruction; -import com.ibm.wala.types.TypeReference; -import com.ibm.wala.util.CancelException; -import com.ibm.wala.util.CancelRuntimeException; -import com.ibm.wala.util.MonitorUtil.IProgressMonitor; -import com.ibm.wala.util.collections.HashSetFactory; -import com.ibm.wala.util.debug.Assertions; -import com.ibm.wala.util.intset.IntSet; -import com.ibm.wala.util.intset.IntSetAction; -import com.ibm.wala.util.intset.IntSetUtil; -import com.ibm.wala.util.intset.MutableIntSet; -import com.ibm.wala.util.warnings.Warning; -import com.ibm.wala.util.warnings.Warnings; - -/** - * This abstract base class provides the general algorithm for a call graph builder that relies on propagation through an iterative - * dataflow solver - * - * TODO: This implementation currently keeps all points to sets live ... even those for local variables that do not span - * interprocedural boundaries. This may be too space-inefficient .. we can consider recomputing local sets on demand. - */ -public abstract class PropagationCallGraphBuilder implements CallGraphBuilder { - private final static boolean DEBUG_ALL = false; - - final static boolean DEBUG_ASSIGN = DEBUG_ALL | false; - - private final static boolean DEBUG_ARRAY_LOAD = DEBUG_ALL | false; - - private final static boolean DEBUG_ARRAY_STORE = DEBUG_ALL | false; - - private final static boolean DEBUG_FILTER = DEBUG_ALL | false; - - final protected static boolean DEBUG_GENERAL = DEBUG_ALL | false; - - private final static boolean DEBUG_GET = DEBUG_ALL | false; - - private final static boolean DEBUG_PUT = DEBUG_ALL | false; - - private final static boolean DEBUG_ENTRYPOINTS = DEBUG_ALL | false; - - /** - * Meta-data regarding how pointers are modeled - */ - protected final PointerKeyFactory pointerKeyFactory; - - /** - * The object that represents the java.lang.Object class - */ - final private IClass JAVA_LANG_OBJECT; - - /** - * Governing class hierarchy - */ - final protected IClassHierarchy cha; - - /** - * Special rules for bypassing Java calls - */ - final protected AnalysisOptions options; - - /** - * Cache of IRs and things - */ - private final AnalysisCache analysisCache; - - /** - * Set of nodes that have already been traversed for constraints - */ - final private Set alreadyVisited = HashSetFactory.make(); - - /** - * At any given time, the set of nodes that have been discovered but not yet processed for constraints - */ - private Set discoveredNodes = HashSetFactory.make(); - - /** - * Set of calls (CallSiteReferences) that are created by entrypoints - */ - final protected Set entrypointCallSites = HashSetFactory.make(); - - /** - * The system of constraints used to build this graph - */ - protected PropagationSystem system; - - /** - * Algorithm used to solve the system of constraints - */ - private IPointsToSolver solver; - - /** - * The call graph under construction - */ - protected final ExplicitCallGraph callGraph; - - /** - * Singleton operator for assignments - */ - protected final static AssignOperator assignOperator = new AssignOperator(); - - /** - * singleton operator for filter - */ - public final FilterOperator filterOperator = new FilterOperator(); - - /** - * singleton operator for inverse filter - */ - protected final InverseFilterOperator inverseFilterOperator = new InverseFilterOperator(); - - /** - * An object which interprets methods in context - */ - private SSAContextInterpreter contextInterpreter; - - /** - * A context selector which may use information derived from the propagation-based dataflow. - */ - protected ContextSelector contextSelector; - - /** - * An object that abstracts how to model instances in the heap. - */ - protected InstanceKeyFactory instanceKeyFactory; - - /** - * Algorithmic choice: should the GetfieldOperator and PutfieldOperator cache its previous history to reduce work? - */ - final private boolean rememberGetPutHistory = true; - - /** - * @param cha governing class hierarchy - * @param options governing call graph construction options - * @param pointerKeyFactory factory which embodies pointer abstraction policy - */ - protected PropagationCallGraphBuilder(IClassHierarchy cha, AnalysisOptions options, AnalysisCache cache, - PointerKeyFactory pointerKeyFactory) { - if (cha == null) { - throw new IllegalArgumentException("cha is null"); - } - if (options == null) { - throw new IllegalArgumentException("options is null"); - } - assert cache != null; - this.cha = cha; - this.options = options; - this.analysisCache = cache; - // we need pointer keys to handle reflection - assert pointerKeyFactory != null; - this.pointerKeyFactory = pointerKeyFactory; - callGraph = createEmptyCallGraph(cha, options); - try { - callGraph.init(); - } catch (CancelException e) { - if (DEBUG_GENERAL) { - System.err.println("Could not initialize the call graph due to node number constraints: " + e.getMessage()); - } - } - callGraph.setInterpreter(contextInterpreter); - JAVA_LANG_OBJECT = cha.lookupClass(TypeReference.JavaLangObject); - } - - protected ExplicitCallGraph createEmptyCallGraph(IClassHierarchy cha, AnalysisOptions options) { - return new ExplicitCallGraph(cha, options, getAnalysisCache()); - } - - /** - * @return true iff the klass represents java.lang.Object - */ - protected boolean isJavaLangObject(IClass klass) { - return (klass.getReference().equals(TypeReference.JavaLangObject)); - } - - public CallGraph makeCallGraph(AnalysisOptions options) throws IllegalArgumentException, CancelException { - return makeCallGraph(options, null); - } - - /* - * @see com.ibm.wala.ipa.callgraph.CallGraphBuilder#makeCallGraph(com.ibm.wala.ipa.callgraph.AnalysisOptions) - */ - public CallGraph makeCallGraph(AnalysisOptions options, IProgressMonitor monitor) throws IllegalArgumentException, - CallGraphBuilderCancelException { - if (options == null) { - throw new IllegalArgumentException("options is null"); - } - system = makeSystem(options); - - if (DEBUG_GENERAL) { - System.err.println("Enter makeCallGraph!"); - } - - if (DEBUG_GENERAL) { - System.err.println("Initialized call graph"); - } - - system.setMinEquationsForTopSort(options.getMinEquationsForTopSort()); - system.setTopologicalGrowthFactor(options.getTopologicalGrowthFactor()); - system.setMaxEvalBetweenTopo(options.getMaxEvalBetweenTopo()); - - discoveredNodes = HashSetFactory.make(); - discoveredNodes.add(callGraph.getFakeRootNode()); - - // Set up the initially reachable methods and classes - for (Iterator it = options.getEntrypoints().iterator(); it.hasNext();) { - Entrypoint E = (Entrypoint) it.next(); - if (DEBUG_ENTRYPOINTS) { - System.err.println("Entrypoint: " + E); - } - SSAAbstractInvokeInstruction call = E.addCall((AbstractRootMethod) callGraph.getFakeRootNode().getMethod()); - - if (call == null) { - Warnings.add(EntrypointResolutionWarning.create(E)); - } else { - entrypointCallSites.add(call.getCallSite()); - } - } - - customInit(); - - solver = makeSolver(); - try { - solver.solve(monitor); - } catch (CancelException e) { - CallGraphBuilderCancelException c = CallGraphBuilderCancelException.createCallGraphBuilderCancelException(e, callGraph, - system.extractPointerAnalysis(this)); - throw c; - } catch (CancelRuntimeException e) { - CallGraphBuilderCancelException c = CallGraphBuilderCancelException.createCallGraphBuilderCancelException(e, callGraph, - system.extractPointerAnalysis(this)); - throw c; - } - - return callGraph; - } - - protected PropagationSystem makeSystem(AnalysisOptions options) { - return new PropagationSystem(callGraph, pointerKeyFactory, instanceKeyFactory); - } - - protected abstract IPointsToSolver makeSolver(); - - /** - * A warning for when we fail to resolve a call to an entrypoint - */ - private static class EntrypointResolutionWarning extends Warning { - - final Entrypoint entrypoint; - - EntrypointResolutionWarning(Entrypoint entrypoint) { - super(Warning.SEVERE); - this.entrypoint = entrypoint; - } - - @Override - public String getMsg() { - return getClass().toString() + " : " + entrypoint; - } - - public static EntrypointResolutionWarning create(Entrypoint entrypoint) { - return new EntrypointResolutionWarning(entrypoint); - } - } - - protected void customInit() { - } - - /** - * Add constraints for a node. - * @param monitor - * - * @return true iff any new constraints are added. - */ - protected abstract boolean addConstraintsFromNode(CGNode n, IProgressMonitor monitor) throws CancelException; - - /** - * Add constraints from newly discovered nodes. Note: the act of adding constraints may discover new nodes, so this routine is - * iterative. - * - * @return true iff any new constraints are added. - * @throws CancelException - */ - protected boolean addConstraintsFromNewNodes(IProgressMonitor monitor) throws CancelException { - boolean result = false; - while (!discoveredNodes.isEmpty()) { - Iterator it = discoveredNodes.iterator(); - discoveredNodes = HashSetFactory.make(); - while (it.hasNext()) { - CGNode n = it.next(); - result |= addConstraintsFromNode(n, monitor); - } - } - return result; - } - - /** - * @return the PointerKey that acts as a representative for the class of pointers that includes the local variable identified by - * the value number parameter. - */ - public PointerKey getPointerKeyForLocal(CGNode node, int valueNumber) { - return pointerKeyFactory.getPointerKeyForLocal(node, valueNumber); - } - - /** - * @return the PointerKey that acts as a representative for the class of pointers that includes the local variable identified by - * the value number parameter. - */ - public FilteredPointerKey getFilteredPointerKeyForLocal(CGNode node, int valueNumber, FilteredPointerKey.TypeFilter filter) { - assert filter != null; - return pointerKeyFactory.getFilteredPointerKeyForLocal(node, valueNumber, filter); - } - - public FilteredPointerKey getFilteredPointerKeyForLocal(CGNode node, int valueNumber, IClass filter) { - return getFilteredPointerKeyForLocal(node, valueNumber, new FilteredPointerKey.SingleClassFilter(filter)); - } - - public FilteredPointerKey getFilteredPointerKeyForLocal(CGNode node, int valueNumber, InstanceKey filter) { - return getFilteredPointerKeyForLocal(node, valueNumber, new FilteredPointerKey.SingleInstanceFilter(filter)); - } - - /** - * @return the PointerKey that acts as a representative for the class of pointers that includes the return value for a node - */ - public PointerKey getPointerKeyForReturnValue(CGNode node) { - return pointerKeyFactory.getPointerKeyForReturnValue(node); - } - - /** - * @return the PointerKey that acts as a representative for the class of pointers that includes the exceptional return value - */ - public PointerKey getPointerKeyForExceptionalReturnValue(CGNode node) { - return pointerKeyFactory.getPointerKeyForExceptionalReturnValue(node); - } - - /** - * @return the PointerKey that acts as a representative for the class of pointers that includes the contents of the static field - */ - public PointerKey getPointerKeyForStaticField(IField f) { - assert f != null : "null FieldReference"; - return pointerKeyFactory.getPointerKeyForStaticField(f); - } - - /** - * @return the PointerKey that acts as a representation for the class of pointers that includes the given instance field. null if - * there's some problem. - * @throws IllegalArgumentException if I is null - * @throws IllegalArgumentException if field is null - */ - public PointerKey getPointerKeyForInstanceField(InstanceKey I, IField field) { - if (field == null) { - throw new IllegalArgumentException("field is null"); - } - if (I == null) { - throw new IllegalArgumentException("I is null"); - } - IClass t = field.getDeclaringClass(); - IClass C = I.getConcreteType(); - if (!(C instanceof SyntheticClass)) { - if (!getClassHierarchy().isSubclassOf(C, t)) { - return null; - } - } - - return pointerKeyFactory.getPointerKeyForInstanceField(I, field); - } - - /** - * TODO: expand this API to differentiate between different array indices - * - * @param I an InstanceKey representing an abstract array - * @return the PointerKey that acts as a representation for the class of pointers that includes the given array contents, or null - * if none found. - * @throws IllegalArgumentException if I is null - */ - public PointerKey getPointerKeyForArrayContents(InstanceKey I) { - if (I == null) { - throw new IllegalArgumentException("I is null"); - } - IClass C = I.getConcreteType(); - if (!C.isArrayClass()) { - assert false : "illegal arguments: " + I; - } - return pointerKeyFactory.getPointerKeyForArrayContents(I); - } - - /** - * Handle assign of a particular exception instance into an exception variable - * - * @param exceptionVar points-to set for a variable representing a caught exception - * @param catchClasses set of TypeReferences that the exceptionVar may catch - * @param e a particular exception instance - */ - protected void assignInstanceToCatch(PointerKey exceptionVar, Set catchClasses, InstanceKey e) { - if (catches(catchClasses, e.getConcreteType(), cha)) { - system.newConstraint(exceptionVar, e); - } - } - - /** - * Generate a set of constraints to represent assignment to an exception variable in a catch clause. Note that we use - * FilterOperator to filter out types that the exception handler doesn't catch. - * - * @param exceptionVar points-to set for a variable representing a caught exception - * @param catchClasses set of TypeReferences that the exceptionVar may catch - * @param e points-to-set representing a thrown exception that might be caught. - */ - protected void addAssignmentsForCatchPointerKey(PointerKey exceptionVar, Set catchClasses, PointerKey e) { - if (DEBUG_GENERAL) { - System.err.println("addAssignmentsForCatch: " + catchClasses); - } - // this is tricky ... we want to filter based on a number of classes ... so we can't - // just used a FilteredPointerKey for the exceptionVar. Instead, we create a new - // "typed local" for each catch class, and coalesce the results using - // assignment - for (IClass c : catchClasses) { - if (c.getReference().equals(c.getClassLoader().getLanguage().getThrowableType())) { - system.newConstraint(exceptionVar, assignOperator, e); - } else { - FilteredPointerKey typedException = TypedPointerKey.make(exceptionVar, c); - system.newConstraint(typedException, filterOperator, e); - system.newConstraint(exceptionVar, assignOperator, typedException); - } - } - } - - /** - * A warning for when we fail to resolve a call to an entrypoint - */ - @SuppressWarnings("unused") - private static class ExceptionLookupFailure extends Warning { - - final TypeReference t; - - ExceptionLookupFailure(TypeReference t) { - super(Warning.SEVERE); - this.t = t; - } - - @Override - public String getMsg() { - return getClass().toString() + " : " + t; - } - - public static ExceptionLookupFailure create(TypeReference t) { - return new ExceptionLookupFailure(t); - } - } - - /** - * A pointer key that delegates to an untyped variant, but adds a type filter - */ - public final static class TypedPointerKey implements FilteredPointerKey { - - private final IClass type; - - private final PointerKey base; - - static TypedPointerKey make(PointerKey base, IClass type) { - assert type != null; - return new TypedPointerKey(base, type); - } - - private TypedPointerKey(PointerKey base, IClass type) { - this.type = type; - this.base = base; - assert type != null; - assert !(type instanceof FilteredPointerKey); - } - - /* - * @see com.ibm.wala.ipa.callgraph.propagation.FilteredPointerKey#getTypeFilter() - */ - public TypeFilter getTypeFilter() { - return new SingleClassFilter(type); - } - - @Override - public boolean equals(Object obj) { - // instanceof is OK because this class is final - if (obj instanceof TypedPointerKey) { - TypedPointerKey other = (TypedPointerKey) obj; - return type.equals(other.type) && base.equals(other.base); - } else { - return false; - } - } - - @Override - public int hashCode() { - return 67931 * base.hashCode() + type.hashCode(); - } - - @Override - public String toString() { - return "{ " + base + " type: " + type + "}"; - } - - public PointerKey getBase() { - return base; - } - } - - /** - * @param catchClasses Set of TypeReference - * @param klass an Exception Class - * @return true iff klass is a subclass of some element of the Set - * @throws IllegalArgumentException if catchClasses is null - */ - public static boolean catches(Set catchClasses, IClass klass, IClassHierarchy cha) { - if (catchClasses == null) { - throw new IllegalArgumentException("catchClasses is null"); - } - // quick shortcut - if (catchClasses.size() == 1) { - IClass c = catchClasses.iterator().next(); - if (c != null && c.getReference().equals(TypeReference.JavaLangThread)) { - return true; - } - } - for (IClass c : catchClasses) { - if (c != null && cha.isAssignableFrom(c, klass)) { - return true; - } - } - return false; - } - - public static boolean representsNullType(InstanceKey key) throws IllegalArgumentException { - if (key == null) { - throw new IllegalArgumentException("key == null"); - } - IClass cls = key.getConcreteType(); - Language L = cls.getClassLoader().getLanguage(); - return L.isNullType(cls.getReference()); - } - - /** - * The FilterOperator is a filtered set-union. i.e. the LHS is `unioned' with the RHS, but filtered by the set associated with - * this operator instance. The filter is the set of InstanceKeys corresponding to the target type of this cast. This is still - * monotonic. - * - * LHS U= (RHS n k) - * - * - * Unary op: := Cast_k( ) - * - * (Again, technically a binary op -- see note for Assign) - * - * TODO: these need to be canonicalized. - * - */ - public class FilterOperator extends UnaryOperator implements IPointerOperator { - - protected FilterOperator() { - } - - /* - * @see com.ibm.wala.dataflow.UnaryOperator#evaluate(com.ibm.wala.dataflow.IVariable, com.ibm.wala.dataflow.IVariable) - */ - @Override - public byte evaluate(PointsToSetVariable lhs, PointsToSetVariable rhs) { - - FilteredPointerKey pk = (FilteredPointerKey) lhs.getPointerKey(); - - if (DEBUG_FILTER) { - String S = "EVAL Filter " + lhs.getPointerKey() + " " + rhs.getPointerKey(); - S += "\nEVAL " + lhs + " " + rhs; - System.err.println(S); - } - if (rhs.size() == 0) { - return NOT_CHANGED; - } - - boolean changed = false; - FilteredPointerKey.TypeFilter filter = pk.getTypeFilter(); - changed = filter.addFiltered(system, lhs, rhs); - - if (DEBUG_FILTER) { - System.err.println("RESULT " + lhs + (changed ? " (changed)" : "")); - } - - return changed ? CHANGED : NOT_CHANGED; - } - - /* - * @see com.ibm.wala.ipa.callgraph.propagation.IPointerOperator#isComplex() - */ - public boolean isComplex() { - return false; - } - - @Override - public String toString() { - return "Filter "; - } - - @Override - public boolean equals(Object obj) { - // these objects are canonicalized for the duration of a solve - return this == obj; - } - - @Override - public int hashCode() { - return 88651; - } - - } - - public IClassHierarchy getClassHierarchy() { - return cha; - } - - public AnalysisOptions getOptions() { - return options; - } - - public IClass getJavaLangObject() { - return JAVA_LANG_OBJECT; - } - - public ExplicitCallGraph getCallGraph() { - return callGraph; - } - - /** - * Subclasses must register the context interpreter before building a call graph. - */ - public void setContextInterpreter(SSAContextInterpreter interpreter) { - contextInterpreter = interpreter; - callGraph.setInterpreter(interpreter); - } - - /* - * @see com.ibm.detox.ipa.callgraph.CallGraphBuilder#getPointerAnalysis() - */ - public PointerAnalysis getPointerAnalysis() { - return system.extractPointerAnalysis(this); - } - - public PropagationSystem getPropagationSystem() { - return system; - } - - public PointerKeyFactory getPointerKeyFactory() { - return pointerKeyFactory; - } - - public RTAContextInterpreter getContextInterpreter() { - return contextInterpreter; - } - - /** - * @param caller the caller node - * @param iKey an abstraction of the receiver of the call (or null if not applicable) - * @return the CGNode to which this particular call should dispatch. - */ - protected CGNode getTargetForCall(CGNode caller, CallSiteReference site, IClass recv, InstanceKey iKey[]) { - - IMethod targetMethod = options.getMethodTargetSelector().getCalleeTarget(caller, site, recv); - - // this most likely indicates an exclusion at work; the target selector - // should have issued a warning - if (targetMethod == null || targetMethod.isAbstract()) { - return null; - } - Context targetContext = contextSelector.getCalleeTarget(caller, site, targetMethod, iKey); - - if (targetContext instanceof IllegalArgumentExceptionContext) { - return null; - } - try { - return getCallGraph().findOrCreateNode(targetMethod, targetContext); - } catch (CancelException e) { - return null; - } - } - - /** - * @return the context selector for this call graph builder - */ - public ContextSelector getContextSelector() { - return contextSelector; - } - - public void setContextSelector(ContextSelector selector) { - contextSelector = selector; - } - - public InstanceKeyFactory getInstanceKeys() { - return instanceKeyFactory; - } - - public void setInstanceKeys(InstanceKeyFactory keys) { - this.instanceKeyFactory = keys; - } - - /** - * @return the InstanceKey that acts as a representative for the class of objects that includes objects allocated at the given new - * instruction in the given node - */ - public InstanceKey getInstanceKeyForAllocation(CGNode node, NewSiteReference allocation) { - return instanceKeyFactory.getInstanceKeyForAllocation(node, allocation); - } - - /** - * @param dim the dimension of the array whose instance we would like to model. dim == 0 represents the first dimension, e.g., the - * [Object; instances in [[Object; e.g., the [[Object; instances in [[[Object; dim == 1 represents the second dimension, - * e.g., the [Object instances in [[[Object; - * @return the InstanceKey that acts as a representative for the class of array contents objects that includes objects allocated - * at the given new instruction in the given node - */ - public InstanceKey getInstanceKeyForMultiNewArray(CGNode node, NewSiteReference allocation, int dim) { - return instanceKeyFactory.getInstanceKeyForMultiNewArray(node, allocation, dim); - } - - public InstanceKey getInstanceKeyForConstant(TypeReference type, T S) { - return instanceKeyFactory.getInstanceKeyForConstant(type, S); - } - - public InstanceKey getInstanceKeyForClassObject(TypeReference type) { - return instanceKeyFactory.getInstanceKeyForClassObject(type); - } - - public boolean haveAlreadyVisited(CGNode node) { - return alreadyVisited.contains(node); - } - - protected void markAlreadyVisited(CGNode node) { - alreadyVisited.add(node); - } - - /** - * record that we've discovered a node - */ - public void markDiscovered(CGNode node) { - discoveredNodes.add(node); - } - - protected void markChanged(CGNode node) { - alreadyVisited.remove(node); - discoveredNodes.add(node); - } - - protected boolean wasChanged(CGNode node) { - return discoveredNodes.contains(node) && !alreadyVisited.contains(node); - } - - /** - * Binary op: := ArrayLoad( <arrayref>) Side effect: Creates new equations. - */ - public final class ArrayLoadOperator extends UnarySideEffect implements IPointerOperator { - protected final MutableIntSet priorInstances = rememberGetPutHistory ? IntSetUtil.make() : null; - - @Override - public String toString() { - return "ArrayLoad"; - } - - public ArrayLoadOperator(PointsToSetVariable def) { - super(def); - system.registerFixedSet(def, this); - } - - @Override - public byte evaluate(PointsToSetVariable rhs) { - if (DEBUG_ARRAY_LOAD) { - PointsToSetVariable def = getFixedSet(); - String S = "EVAL ArrayLoad " + rhs.getPointerKey() + " " + def.getPointerKey(); - System.err.println(S); - System.err.println("EVAL ArrayLoad " + def + " " + rhs); - if (priorInstances != null) { - System.err.println("prior instances: " + priorInstances + " " + priorInstances.getClass()); - } - } - - if (rhs.size() == 0) { - return NOT_CHANGED; - } - final PointerKey object = rhs.getPointerKey(); - - PointsToSetVariable def = getFixedSet(); - final PointerKey dVal = def.getPointerKey(); - - final MutableBoolean sideEffect = new MutableBoolean(); - IntSetAction action = new IntSetAction() { - public void act(int i) { - InstanceKey I = system.getInstanceKey(i); - if (!I.getConcreteType().isArrayClass()) { - return; - } - TypeReference C = I.getConcreteType().getReference().getArrayElementType(); - if (C.isPrimitiveType()) { - return; - } - PointerKey p = getPointerKeyForArrayContents(I); - if (p == null) { - return; - } - - if (DEBUG_ARRAY_LOAD) { - System.err.println("ArrayLoad add assign: " + dVal + " " + p); - } - sideEffect.b |= system.newFieldRead(dVal, assignOperator, p, object); - } - }; - if (priorInstances != null) { - rhs.getValue().foreachExcluding(priorInstances, action); - priorInstances.addAll(rhs.getValue()); - } else { - rhs.getValue().foreach(action); - } - byte sideEffectMask = sideEffect.b ? (byte) SIDE_EFFECT_MASK : 0; - return (byte) (NOT_CHANGED | sideEffectMask); - } - - @Override - public int hashCode() { - return 9871 + super.hashCode(); - } - - @Override - public boolean equals(Object o) { - return super.equals(o); - } - - @Override - protected boolean isLoadOperator() { - return true; - } - - /* - * @see com.ibm.wala.ipa.callgraph.propagation.IPointerOperator#isComplex() - */ - public boolean isComplex() { - return true; - } - } - - /** - * Binary op: := ArrayStore( <arrayref>) Side effect: Creates new equations. - */ - public final class ArrayStoreOperator extends UnarySideEffect implements IPointerOperator { - @Override - public String toString() { - return "ArrayStore"; - } - - public ArrayStoreOperator(PointsToSetVariable val) { - super(val); - system.registerFixedSet(val, this); - } - - @Override - public byte evaluate(PointsToSetVariable rhs) { - if (DEBUG_ARRAY_STORE) { - PointsToSetVariable val = getFixedSet(); - String S = "EVAL ArrayStore " + rhs.getPointerKey() + " " + val.getPointerKey(); - System.err.println(S); - System.err.println("EVAL ArrayStore " + rhs + " " + getFixedSet()); - } - - if (rhs.size() == 0) { - return NOT_CHANGED; - } - PointerKey object = rhs.getPointerKey(); - - PointsToSetVariable val = getFixedSet(); - PointerKey pVal = val.getPointerKey(); - - List instances = system.getInstances(rhs.getValue()); - boolean sideEffect = false; - for (Iterator it = instances.iterator(); it.hasNext();) { - InstanceKey I = it.next(); - if (!I.getConcreteType().isArrayClass()) { - continue; - } - if (I instanceof ZeroLengthArrayInNode) { - continue; - } - TypeReference C = I.getConcreteType().getReference().getArrayElementType(); - if (C.isPrimitiveType()) { - continue; - } - IClass contents = getClassHierarchy().lookupClass(C); - if (contents == null) { - assert false : "null type for " + C + " " + I.getConcreteType(); - } - PointerKey p = getPointerKeyForArrayContents(I); - if (DEBUG_ARRAY_STORE) { - System.err.println("ArrayStore add filtered-assign: " + p + " " + pVal); - } - - // note that the following is idempotent - if (isJavaLangObject(contents)) { - sideEffect |= system.newFieldWrite(p, assignOperator, pVal, object); - } else { - sideEffect |= system.newFieldWrite(p, filterOperator, pVal, object); - } - } - byte sideEffectMask = sideEffect ? (byte) SIDE_EFFECT_MASK : 0; - return (byte) (NOT_CHANGED | sideEffectMask); - } - - @Override - public int hashCode() { - return 9859 + super.hashCode(); - } - - public boolean isComplex() { - return true; - } - - @Override - public boolean equals(Object o) { - return super.equals(o); - } - - @Override - protected boolean isLoadOperator() { - return false; - } - } - - /** - * Binary op: := GetField( ) Side effect: Creates new equations. - */ - public class GetFieldOperator extends UnarySideEffect implements IPointerOperator { - private final IField field; - - protected final MutableIntSet priorInstances = rememberGetPutHistory ? IntSetUtil.make() : null; - - public GetFieldOperator(IField field, PointsToSetVariable def) { - super(def); - this.field = field; - system.registerFixedSet(def, this); - } - - @Override - public String toString() { - return "GetField " + getField() + "," + getFixedSet().getPointerKey(); - } - - @Override - public byte evaluate(PointsToSetVariable rhs) { - if (DEBUG_GET) { - String S = "EVAL GetField " + getField() + " " + getFixedSet().getPointerKey() + " " + rhs.getPointerKey() + getFixedSet() - + " " + rhs; - System.err.println(S); - } - - PointsToSetVariable ref = rhs; - if (ref.size() == 0) { - return NOT_CHANGED; - } - final PointerKey object = ref.getPointerKey(); - PointsToSetVariable def = getFixedSet(); - final PointerKey dVal = def.getPointerKey(); - - IntSet value = filterInstances(ref.getValue()); - if (DEBUG_GET) { - System.err.println("filtered value: " + value + " " + value.getClass()); - if (priorInstances != null) { - System.err.println("prior instances: " + priorInstances + " " + priorInstances.getClass()); - } - } - final MutableBoolean sideEffect = new MutableBoolean(); - IntSetAction action = new IntSetAction() { - public void act(int i) { - InstanceKey I = system.getInstanceKey(i); - if (!representsNullType(I)) { - PointerKey p = getPointerKeyForInstanceField(I, getField()); - - if (p != null) { - if (DEBUG_GET) { - String S = "Getfield add constraint " + dVal + " " + p; - System.err.println(S); - } - sideEffect.b |= system.newFieldRead(dVal, assignOperator, p, object); - } - } - } - }; - if (priorInstances != null) { - value.foreachExcluding(priorInstances, action); - priorInstances.addAll(value); - } else { - value.foreach(action); - } - byte sideEffectMask = sideEffect.b ? (byte) SIDE_EFFECT_MASK : 0; - return (byte) (NOT_CHANGED | sideEffectMask); - } - - /** - * Subclasses can override as needed - */ - protected IntSet filterInstances(IntSet value) { - return value; - } - - @Override - public int hashCode() { - return 9857 * getField().hashCode() + getFixedSet().hashCode(); - } - - @Override - public boolean equals(Object o) { - if (o instanceof GetFieldOperator) { - GetFieldOperator other = (GetFieldOperator) o; - return getField().equals(other.getField()) && getFixedSet().equals(other.getFixedSet()); - } else { - return false; - } - } - - protected IField getField() { - return field; - } - - @Override - protected boolean isLoadOperator() { - return true; - } - - /* - * @see com.ibm.wala.ipa.callgraph.propagation.IPointerOperator#isComplex() - */ - public boolean isComplex() { - return true; - } - } - - /** - * Operator that represents a putfield - */ - public class PutFieldOperator extends UnarySideEffect implements IPointerOperator { - private final IField field; - - protected final MutableIntSet priorInstances = rememberGetPutHistory ? IntSetUtil.make() : null; - - @Override - public String toString() { - return "PutField" + getField(); - } - - public PutFieldOperator(IField field, PointsToSetVariable val) { - super(val); - this.field = field; - system.registerFixedSet(val, this); - } - - /* - * @see com.ibm.wala.ipa.callgraph.propagation.IPointerOperator#isComplex() - */ - public boolean isComplex() { - return true; - } - - @Override - public byte evaluate(PointsToSetVariable rhs) { - if (DEBUG_PUT) { - String S = "EVAL PutField " + getField() + " " + (getFixedSet()).getPointerKey() + " " + rhs.getPointerKey() - + getFixedSet() + " " + rhs; - System.err.println(S); - } - - if (rhs.size() == 0) { - return NOT_CHANGED; - } - final PointerKey object = rhs.getPointerKey(); - - PointsToSetVariable val = getFixedSet(); - final PointerKey pVal = val.getPointerKey(); - IntSet value = rhs.getValue(); - value = filterInstances(value); - final UnaryOperator assign = getPutAssignmentOperator(); - if (assign == null) { - Assertions.UNREACHABLE(); - } - final MutableBoolean sideEffect = new MutableBoolean(); - IntSetAction action = new IntSetAction() { - public void act(int i) { - InstanceKey I = system.getInstanceKey(i); - if (!representsNullType(I)) { - if (DEBUG_PUT) { - String S = "Putfield consider instance " + I; - System.err.println(S); - } - PointerKey p = getPointerKeyForInstanceField(I, getField()); - if (p != null) { - if (DEBUG_PUT) { - String S = "Putfield add constraint " + p + " " + pVal; - System.err.println(S); - } - sideEffect.b |= system.newFieldWrite(p, assign, pVal, object); - } - } - } - }; - if (priorInstances != null) { - value.foreachExcluding(priorInstances, action); - priorInstances.addAll(value); - } else { - value.foreach(action); - } - byte sideEffectMask = sideEffect.b ? (byte) SIDE_EFFECT_MASK : 0; - return (byte) (NOT_CHANGED | sideEffectMask); - } - - /** - * Subclasses can override as needed - */ - protected IntSet filterInstances(IntSet value) { - return value; - } - - @Override - public int hashCode() { - return 9857 * getField().hashCode() + getFixedSet().hashCode(); - } - - @Override - public boolean equals(Object o) { - if (o != null && o.getClass().equals(getClass())) { - PutFieldOperator other = (PutFieldOperator) o; - return getField().equals(other.getField()) && getFixedSet().equals(other.getFixedSet()); - } else { - return false; - } - } - - /** - * subclasses (e.g. XTA) can override this to enforce a filtered assignment. returns null if there's a problem. - */ - public UnaryOperator getPutAssignmentOperator() { - return assignOperator; - } - - /** - * @return Returns the field. - */ - protected IField getField() { - return field; - } - - @Override - protected boolean isLoadOperator() { - return false; - } - } - - /** - * Update the points-to-set for a field to include a particular instance key. - */ - public final class InstancePutFieldOperator extends UnaryOperator implements IPointerOperator { - final private IField field; - - final private InstanceKey instance; - - protected final MutableIntSet priorInstances = rememberGetPutHistory ? IntSetUtil.make() : null; - - @Override - public String toString() { - return "InstancePutField" + field; - } - - public InstancePutFieldOperator(IField field, InstanceKey instance) { - this.field = field; - this.instance = instance; - } - - /** - * Simply add the instance to each relevant points-to set. - */ - @Override - public byte evaluate(PointsToSetVariable dummyLHS, PointsToSetVariable var) { - PointsToSetVariable ref = var; - if (ref.size() == 0) { - return NOT_CHANGED; - } - IntSet value = ref.getValue(); - final MutableBoolean sideEffect = new MutableBoolean(); - IntSetAction action = new IntSetAction() { - public void act(int i) { - InstanceKey I = system.getInstanceKey(i); - if (!representsNullType(I)) { - PointerKey p = getPointerKeyForInstanceField(I, field); - if (p != null) { - sideEffect.b |= system.newConstraint(p, instance); - } - } - } - }; - if (priorInstances != null) { - value.foreachExcluding(priorInstances, action); - priorInstances.addAll(value); - } else { - value.foreach(action); - } - byte sideEffectMask = sideEffect.b ? (byte) SIDE_EFFECT_MASK : 0; - return (byte) (NOT_CHANGED | sideEffectMask); - } - - @Override - public int hashCode() { - return field.hashCode() + 9839 * instance.hashCode(); - } - - @Override - public boolean equals(Object o) { - if (o instanceof InstancePutFieldOperator) { - InstancePutFieldOperator other = (InstancePutFieldOperator) o; - return field.equals(other.field) && instance.equals(other.instance); - } else { - return false; - } - } - - /* - * @see com.ibm.wala.ipa.callgraph.propagation.IPointerOperator#isComplex() - */ - public boolean isComplex() { - return true; - } - } - - /** - * Update the points-to-set for an array contents to include a particular instance key. - */ - public final class InstanceArrayStoreOperator extends UnaryOperator implements IPointerOperator { - final private InstanceKey instance; - - protected final MutableIntSet priorInstances = rememberGetPutHistory ? IntSetUtil.make() : null; - - @Override - public String toString() { - return "InstanceArrayStore "; - } - - public InstanceArrayStoreOperator(InstanceKey instance) { - this.instance = instance; - } - - /** - * Simply add the instance to each relevant points-to set. - */ - @Override - public byte evaluate(PointsToSetVariable dummyLHS, PointsToSetVariable var) { - PointsToSetVariable arrayref = var; - if (arrayref.size() == 0) { - return NOT_CHANGED; - } - IntSet value = arrayref.getValue(); - final MutableBoolean sideEffect = new MutableBoolean(); - IntSetAction action = new IntSetAction() { - public void act(int i) { - InstanceKey I = system.getInstanceKey(i); - if (!I.getConcreteType().isArrayClass()) { - return; - } - if (I instanceof ZeroLengthArrayInNode) { - return; - } - TypeReference C = I.getConcreteType().getReference().getArrayElementType(); - if (C.isPrimitiveType()) { - return; - } - IClass contents = getClassHierarchy().lookupClass(C); - if (contents == null) { - assert false : "null type for " + C + " " + I.getConcreteType(); - } - PointerKey p = getPointerKeyForArrayContents(I); - if (contents.isInterface()) { - if (getClassHierarchy().implementsInterface(instance.getConcreteType(), contents)) { - sideEffect.b |= system.newConstraint(p, instance); - } - } else { - if (getClassHierarchy().isSubclassOf(instance.getConcreteType(), contents)) { - sideEffect.b |= system.newConstraint(p, instance); - } - } - } - }; - if (priorInstances != null) { - value.foreachExcluding(priorInstances, action); - priorInstances.addAll(value); - } else { - value.foreach(action); - } - byte sideEffectMask = sideEffect.b ? (byte) SIDE_EFFECT_MASK : 0; - return (byte) (NOT_CHANGED | sideEffectMask); - } - - @Override - public int hashCode() { - return 9839 * instance.hashCode(); - } - - @Override - public boolean equals(Object o) { - if (o instanceof InstanceArrayStoreOperator) { - InstanceArrayStoreOperator other = (InstanceArrayStoreOperator) o; - return instance.equals(other.instance); - } else { - return false; - } - } - - /* - * @see com.ibm.wala.ipa.callgraph.propagation.IPointerOperator#isComplex() - */ - public boolean isComplex() { - return true; - } - } - - protected MutableIntSet getMutableInstanceKeysForClass(IClass klass) { - return system.cloneInstanceKeysForClass(klass); - } - - protected IntSet getInstanceKeysForClass(IClass klass) { - return system.getInstanceKeysForClass(klass); - } - - /** - * @param klass a class - * @return an int set which represents the subset of S that correspond to subtypes of klass - */ - protected IntSet filterForClass(IntSet S, IClass klass) { - MutableIntSet filter = null; - if (klass.getReference().equals(TypeReference.JavaLangObject)) { - return S; - } else { - filter = getMutableInstanceKeysForClass(klass); - - boolean debug = false; - if (DEBUG_FILTER) { - String s = "klass " + klass; - System.err.println(s); - System.err.println("initial filter " + filter); - } - filter.intersectWith(S); - - if (DEBUG_FILTER && debug) { - System.err.println("final filter " + filter); - } - } - return filter; - } - - protected class InverseFilterOperator extends FilterOperator { - public InverseFilterOperator() { - super(); - } - - @Override - public String toString() { - return "InverseFilter"; - } - - /* - * @see com.ibm.wala.ipa.callgraph.propagation.IPointerOperator#isComplex() - */ - @Override - public boolean isComplex() { - return false; - } - - /* - * simply check if rhs contains a malleable. - * - * @see com.ibm.wala.dataflow.UnaryOperator#evaluate(com.ibm.wala.dataflow.IVariable, com.ibm.wala.dataflow.IVariable) - */ - @Override - public byte evaluate(PointsToSetVariable lhs, PointsToSetVariable rhs) { - - FilteredPointerKey pk = (FilteredPointerKey) lhs.getPointerKey(); - FilteredPointerKey.TypeFilter filter = pk.getTypeFilter(); - - boolean debug = false; - if (DEBUG_FILTER) { - String S = "EVAL InverseFilter/" + filter + " " + lhs.getPointerKey() + " " + rhs.getPointerKey(); - S += "\nEVAL " + lhs + " " + rhs; - System.err.println(S); - } - if (rhs.size() == 0) { - return NOT_CHANGED; - } - - boolean changed = filter.addInverseFiltered(system, lhs, rhs); - - if (DEBUG_FILTER) { - if (debug) { - System.err.println("RESULT " + lhs + (changed ? " (changed)" : "")); - } - } - return changed ? CHANGED : NOT_CHANGED; - } - } - - protected IPointsToSolver getSolver() { - return solver; - } - - /** - * Add constraints when the interpretation of a node changes (e.g. reflection) - * @param monitor - * @throws CancelException - */ - public void addConstraintsFromChangedNode(CGNode node, IProgressMonitor monitor) throws CancelException { - unconditionallyAddConstraintsFromNode(node, monitor); - } - - protected abstract boolean unconditionallyAddConstraintsFromNode(CGNode node, IProgressMonitor monitor) throws CancelException; - - protected static class MutableBoolean { - // a horrendous hack since we don't have closures - boolean b = false; - } - - public AnalysisCache getAnalysisCache() { - return analysisCache; - }; - -} +/******************************************************************************* + * 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.ipa.callgraph.propagation; + +import java.util.Iterator; +import java.util.List; +import java.util.Set; + +import com.ibm.wala.analysis.reflection.IllegalArgumentExceptionContext; +import com.ibm.wala.classLoader.CallSiteReference; +import com.ibm.wala.classLoader.IClass; +import com.ibm.wala.classLoader.IField; +import com.ibm.wala.classLoader.IMethod; +import com.ibm.wala.classLoader.Language; +import com.ibm.wala.classLoader.NewSiteReference; +import com.ibm.wala.classLoader.SyntheticClass; +import com.ibm.wala.fixpoint.UnaryOperator; +import com.ibm.wala.ipa.callgraph.AnalysisCache; +import com.ibm.wala.ipa.callgraph.AnalysisOptions; +import com.ibm.wala.ipa.callgraph.CGNode; +import com.ibm.wala.ipa.callgraph.CallGraph; +import com.ibm.wala.ipa.callgraph.CallGraphBuilder; +import com.ibm.wala.ipa.callgraph.CallGraphBuilderCancelException; +import com.ibm.wala.ipa.callgraph.Context; +import com.ibm.wala.ipa.callgraph.ContextSelector; +import com.ibm.wala.ipa.callgraph.Entrypoint; +import com.ibm.wala.ipa.callgraph.impl.AbstractRootMethod; +import com.ibm.wala.ipa.callgraph.impl.ExplicitCallGraph; +import com.ibm.wala.ipa.callgraph.propagation.rta.RTAContextInterpreter; +import com.ibm.wala.ipa.cha.IClassHierarchy; +import com.ibm.wala.ssa.SSAAbstractInvokeInstruction; +import com.ibm.wala.types.TypeReference; +import com.ibm.wala.util.CancelException; +import com.ibm.wala.util.CancelRuntimeException; +import com.ibm.wala.util.MonitorUtil.IProgressMonitor; +import com.ibm.wala.util.collections.HashSetFactory; +import com.ibm.wala.util.debug.Assertions; +import com.ibm.wala.util.intset.IntSet; +import com.ibm.wala.util.intset.IntSetAction; +import com.ibm.wala.util.intset.IntSetUtil; +import com.ibm.wala.util.intset.MutableIntSet; +import com.ibm.wala.util.warnings.Warning; +import com.ibm.wala.util.warnings.Warnings; + +/** + * This abstract base class provides the general algorithm for a call graph builder that relies on propagation through an iterative + * dataflow solver + * + * TODO: This implementation currently keeps all points to sets live ... even those for local variables that do not span + * interprocedural boundaries. This may be too space-inefficient .. we can consider recomputing local sets on demand. + */ +public abstract class PropagationCallGraphBuilder implements CallGraphBuilder { + private final static boolean DEBUG_ALL = false; + + final static boolean DEBUG_ASSIGN = DEBUG_ALL | false; + + private final static boolean DEBUG_ARRAY_LOAD = DEBUG_ALL | false; + + private final static boolean DEBUG_ARRAY_STORE = DEBUG_ALL | false; + + private final static boolean DEBUG_FILTER = DEBUG_ALL | false; + + final protected static boolean DEBUG_GENERAL = DEBUG_ALL | false; + + private final static boolean DEBUG_GET = DEBUG_ALL | false; + + private final static boolean DEBUG_PUT = DEBUG_ALL | false; + + private final static boolean DEBUG_ENTRYPOINTS = DEBUG_ALL | false; + + /** + * Meta-data regarding how pointers are modeled + */ + protected final PointerKeyFactory pointerKeyFactory; + + /** + * The object that represents the java.lang.Object class + */ + final private IClass JAVA_LANG_OBJECT; + + /** + * Governing class hierarchy + */ + final protected IClassHierarchy cha; + + /** + * Special rules for bypassing Java calls + */ + final protected AnalysisOptions options; + + /** + * Cache of IRs and things + */ + private final AnalysisCache analysisCache; + + /** + * Set of nodes that have already been traversed for constraints + */ + final private Set alreadyVisited = HashSetFactory.make(); + + /** + * At any given time, the set of nodes that have been discovered but not yet processed for constraints + */ + private Set discoveredNodes = HashSetFactory.make(); + + /** + * Set of calls (CallSiteReferences) that are created by entrypoints + */ + final protected Set entrypointCallSites = HashSetFactory.make(); + + /** + * The system of constraints used to build this graph + */ + protected PropagationSystem system; + + /** + * Algorithm used to solve the system of constraints + */ + private IPointsToSolver solver; + + /** + * The call graph under construction + */ + protected final ExplicitCallGraph callGraph; + + /** + * Singleton operator for assignments + */ + protected final static AssignOperator assignOperator = new AssignOperator(); + + /** + * singleton operator for filter + */ + public final FilterOperator filterOperator = new FilterOperator(); + + /** + * singleton operator for inverse filter + */ + protected final InverseFilterOperator inverseFilterOperator = new InverseFilterOperator(); + + /** + * An object which interprets methods in context + */ + private SSAContextInterpreter contextInterpreter; + + /** + * A context selector which may use information derived from the propagation-based dataflow. + */ + protected ContextSelector contextSelector; + + /** + * An object that abstracts how to model instances in the heap. + */ + protected InstanceKeyFactory instanceKeyFactory; + + /** + * Algorithmic choice: should the GetfieldOperator and PutfieldOperator cache its previous history to reduce work? + */ + final private boolean rememberGetPutHistory = true; + + /** + * @param cha governing class hierarchy + * @param options governing call graph construction options + * @param pointerKeyFactory factory which embodies pointer abstraction policy + */ + protected PropagationCallGraphBuilder(IClassHierarchy cha, AnalysisOptions options, AnalysisCache cache, + PointerKeyFactory pointerKeyFactory) { + if (cha == null) { + throw new IllegalArgumentException("cha is null"); + } + if (options == null) { + throw new IllegalArgumentException("options is null"); + } + assert cache != null; + this.cha = cha; + this.options = options; + this.analysisCache = cache; + // we need pointer keys to handle reflection + assert pointerKeyFactory != null; + this.pointerKeyFactory = pointerKeyFactory; + callGraph = createEmptyCallGraph(cha, options); + try { + callGraph.init(); + } catch (CancelException e) { + if (DEBUG_GENERAL) { + System.err.println("Could not initialize the call graph due to node number constraints: " + e.getMessage()); + } + } + callGraph.setInterpreter(contextInterpreter); + JAVA_LANG_OBJECT = cha.lookupClass(TypeReference.JavaLangObject); + } + + protected ExplicitCallGraph createEmptyCallGraph(IClassHierarchy cha, AnalysisOptions options) { + return new ExplicitCallGraph(cha, options, getAnalysisCache()); + } + + /** + * @return true iff the klass represents java.lang.Object + */ + protected boolean isJavaLangObject(IClass klass) { + return (klass.getReference().equals(TypeReference.JavaLangObject)); + } + + public CallGraph makeCallGraph(AnalysisOptions options) throws IllegalArgumentException, CancelException { + return makeCallGraph(options, null); + } + + /* + * @see com.ibm.wala.ipa.callgraph.CallGraphBuilder#makeCallGraph(com.ibm.wala.ipa.callgraph.AnalysisOptions) + */ + public CallGraph makeCallGraph(AnalysisOptions options, IProgressMonitor monitor) throws IllegalArgumentException, + CallGraphBuilderCancelException { + if (options == null) { + throw new IllegalArgumentException("options is null"); + } + system = makeSystem(options); + + if (DEBUG_GENERAL) { + System.err.println("Enter makeCallGraph!"); + } + + if (DEBUG_GENERAL) { + System.err.println("Initialized call graph"); + } + + system.setMinEquationsForTopSort(options.getMinEquationsForTopSort()); + system.setTopologicalGrowthFactor(options.getTopologicalGrowthFactor()); + system.setMaxEvalBetweenTopo(options.getMaxEvalBetweenTopo()); + + discoveredNodes = HashSetFactory.make(); + discoveredNodes.add(callGraph.getFakeRootNode()); + + // Set up the initially reachable methods and classes + for (Iterator it = options.getEntrypoints().iterator(); it.hasNext();) { + Entrypoint E = (Entrypoint) it.next(); + if (DEBUG_ENTRYPOINTS) { + System.err.println("Entrypoint: " + E); + } + SSAAbstractInvokeInstruction call = E.addCall((AbstractRootMethod) callGraph.getFakeRootNode().getMethod()); + + if (call == null) { + Warnings.add(EntrypointResolutionWarning.create(E)); + } else { + entrypointCallSites.add(call.getCallSite()); + } + } + + customInit(); + + solver = makeSolver(); + try { + solver.solve(monitor); + } catch (CancelException e) { + CallGraphBuilderCancelException c = CallGraphBuilderCancelException.createCallGraphBuilderCancelException(e, callGraph, + system.extractPointerAnalysis(this)); + throw c; + } catch (CancelRuntimeException e) { + CallGraphBuilderCancelException c = CallGraphBuilderCancelException.createCallGraphBuilderCancelException(e, callGraph, + system.extractPointerAnalysis(this)); + throw c; + } + + return callGraph; + } + + protected PropagationSystem makeSystem(AnalysisOptions options) { + return new PropagationSystem(callGraph, pointerKeyFactory, instanceKeyFactory); + } + + protected abstract IPointsToSolver makeSolver(); + + /** + * A warning for when we fail to resolve a call to an entrypoint + */ + private static class EntrypointResolutionWarning extends Warning { + + final Entrypoint entrypoint; + + EntrypointResolutionWarning(Entrypoint entrypoint) { + super(Warning.SEVERE); + this.entrypoint = entrypoint; + } + + @Override + public String getMsg() { + return getClass().toString() + " : " + entrypoint; + } + + public static EntrypointResolutionWarning create(Entrypoint entrypoint) { + return new EntrypointResolutionWarning(entrypoint); + } + } + + protected void customInit() { + } + + /** + * Add constraints for a node. + * @param monitor + * + * @return true iff any new constraints are added. + */ + protected abstract boolean addConstraintsFromNode(CGNode n, IProgressMonitor monitor) throws CancelException; + + /** + * Add constraints from newly discovered nodes. Note: the act of adding constraints may discover new nodes, so this routine is + * iterative. + * + * @return true iff any new constraints are added. + * @throws CancelException + */ + protected boolean addConstraintsFromNewNodes(IProgressMonitor monitor) throws CancelException { + boolean result = false; + while (!discoveredNodes.isEmpty()) { + Iterator it = discoveredNodes.iterator(); + discoveredNodes = HashSetFactory.make(); + while (it.hasNext()) { + CGNode n = it.next(); + result |= addConstraintsFromNode(n, monitor); + } + } + return result; + } + + /** + * @return the PointerKey that acts as a representative for the class of pointers that includes the local variable identified by + * the value number parameter. + */ + public PointerKey getPointerKeyForLocal(CGNode node, int valueNumber) { + return pointerKeyFactory.getPointerKeyForLocal(node, valueNumber); + } + + /** + * @return the PointerKey that acts as a representative for the class of pointers that includes the local variable identified by + * the value number parameter. + */ + public FilteredPointerKey getFilteredPointerKeyForLocal(CGNode node, int valueNumber, FilteredPointerKey.TypeFilter filter) { + assert filter != null; + return pointerKeyFactory.getFilteredPointerKeyForLocal(node, valueNumber, filter); + } + + public FilteredPointerKey getFilteredPointerKeyForLocal(CGNode node, int valueNumber, IClass filter) { + return getFilteredPointerKeyForLocal(node, valueNumber, new FilteredPointerKey.SingleClassFilter(filter)); + } + + public FilteredPointerKey getFilteredPointerKeyForLocal(CGNode node, int valueNumber, InstanceKey filter) { + return getFilteredPointerKeyForLocal(node, valueNumber, new FilteredPointerKey.SingleInstanceFilter(filter)); + } + + /** + * @return the PointerKey that acts as a representative for the class of pointers that includes the return value for a node + */ + public PointerKey getPointerKeyForReturnValue(CGNode node) { + return pointerKeyFactory.getPointerKeyForReturnValue(node); + } + + /** + * @return the PointerKey that acts as a representative for the class of pointers that includes the exceptional return value + */ + public PointerKey getPointerKeyForExceptionalReturnValue(CGNode node) { + return pointerKeyFactory.getPointerKeyForExceptionalReturnValue(node); + } + + /** + * @return the PointerKey that acts as a representative for the class of pointers that includes the contents of the static field + */ + public PointerKey getPointerKeyForStaticField(IField f) { + assert f != null : "null FieldReference"; + return pointerKeyFactory.getPointerKeyForStaticField(f); + } + + /** + * @return the PointerKey that acts as a representation for the class of pointers that includes the given instance field. null if + * there's some problem. + * @throws IllegalArgumentException if I is null + * @throws IllegalArgumentException if field is null + */ + public PointerKey getPointerKeyForInstanceField(InstanceKey I, IField field) { + if (field == null) { + throw new IllegalArgumentException("field is null"); + } + if (I == null) { + throw new IllegalArgumentException("I is null"); + } + IClass t = field.getDeclaringClass(); + IClass C = I.getConcreteType(); + if (!(C instanceof SyntheticClass)) { + if (!getClassHierarchy().isSubclassOf(C, t)) { + return null; + } + } + + return pointerKeyFactory.getPointerKeyForInstanceField(I, field); + } + + /** + * TODO: expand this API to differentiate between different array indices + * + * @param I an InstanceKey representing an abstract array + * @return the PointerKey that acts as a representation for the class of pointers that includes the given array contents, or null + * if none found. + * @throws IllegalArgumentException if I is null + */ + public PointerKey getPointerKeyForArrayContents(InstanceKey I) { + if (I == null) { + throw new IllegalArgumentException("I is null"); + } + IClass C = I.getConcreteType(); + if (!C.isArrayClass()) { + assert false : "illegal arguments: " + I; + } + return pointerKeyFactory.getPointerKeyForArrayContents(I); + } + + /** + * Handle assign of a particular exception instance into an exception variable + * + * @param exceptionVar points-to set for a variable representing a caught exception + * @param catchClasses set of TypeReferences that the exceptionVar may catch + * @param e a particular exception instance + */ + protected void assignInstanceToCatch(PointerKey exceptionVar, Set catchClasses, InstanceKey e) { + if (catches(catchClasses, e.getConcreteType(), cha)) { + system.newConstraint(exceptionVar, e); + } + } + + /** + * Generate a set of constraints to represent assignment to an exception variable in a catch clause. Note that we use + * FilterOperator to filter out types that the exception handler doesn't catch. + * + * @param exceptionVar points-to set for a variable representing a caught exception + * @param catchClasses set of TypeReferences that the exceptionVar may catch + * @param e points-to-set representing a thrown exception that might be caught. + */ + protected void addAssignmentsForCatchPointerKey(PointerKey exceptionVar, Set catchClasses, PointerKey e) { + if (DEBUG_GENERAL) { + System.err.println("addAssignmentsForCatch: " + catchClasses); + } + // this is tricky ... we want to filter based on a number of classes ... so we can't + // just used a FilteredPointerKey for the exceptionVar. Instead, we create a new + // "typed local" for each catch class, and coalesce the results using + // assignment + for (IClass c : catchClasses) { + if (c.getReference().equals(c.getClassLoader().getLanguage().getThrowableType())) { + system.newConstraint(exceptionVar, assignOperator, e); + } else { + FilteredPointerKey typedException = TypedPointerKey.make(exceptionVar, c); + system.newConstraint(typedException, filterOperator, e); + system.newConstraint(exceptionVar, assignOperator, typedException); + } + } + } + + /** + * A warning for when we fail to resolve a call to an entrypoint + */ + @SuppressWarnings("unused") + private static class ExceptionLookupFailure extends Warning { + + final TypeReference t; + + ExceptionLookupFailure(TypeReference t) { + super(Warning.SEVERE); + this.t = t; + } + + @Override + public String getMsg() { + return getClass().toString() + " : " + t; + } + + public static ExceptionLookupFailure create(TypeReference t) { + return new ExceptionLookupFailure(t); + } + } + + /** + * A pointer key that delegates to an untyped variant, but adds a type filter + */ + public final static class TypedPointerKey implements FilteredPointerKey { + + private final IClass type; + + private final PointerKey base; + + static TypedPointerKey make(PointerKey base, IClass type) { + assert type != null; + return new TypedPointerKey(base, type); + } + + private TypedPointerKey(PointerKey base, IClass type) { + this.type = type; + this.base = base; + assert type != null; + assert !(type instanceof FilteredPointerKey); + } + + /* + * @see com.ibm.wala.ipa.callgraph.propagation.FilteredPointerKey#getTypeFilter() + */ + public TypeFilter getTypeFilter() { + return new SingleClassFilter(type); + } + + @Override + public boolean equals(Object obj) { + // instanceof is OK because this class is final + if (obj instanceof TypedPointerKey) { + TypedPointerKey other = (TypedPointerKey) obj; + return type.equals(other.type) && base.equals(other.base); + } else { + return false; + } + } + + @Override + public int hashCode() { + return 67931 * base.hashCode() + type.hashCode(); + } + + @Override + public String toString() { + return "{ " + base + " type: " + type + "}"; + } + + public PointerKey getBase() { + return base; + } + } + + /** + * @param catchClasses Set of TypeReference + * @param klass an Exception Class + * @return true iff klass is a subclass of some element of the Set + * @throws IllegalArgumentException if catchClasses is null + */ + public static boolean catches(Set catchClasses, IClass klass, IClassHierarchy cha) { + if (catchClasses == null) { + throw new IllegalArgumentException("catchClasses is null"); + } + // quick shortcut + if (catchClasses.size() == 1) { + IClass c = catchClasses.iterator().next(); + if (c != null && c.getReference().equals(TypeReference.JavaLangThread)) { + return true; + } + } + for (IClass c : catchClasses) { + if (c != null && cha.isAssignableFrom(c, klass)) { + return true; + } + } + return false; + } + + public static boolean representsNullType(InstanceKey key) throws IllegalArgumentException { + if (key == null) { + throw new IllegalArgumentException("key == null"); + } + IClass cls = key.getConcreteType(); + Language L = cls.getClassLoader().getLanguage(); + return L.isNullType(cls.getReference()); + } + + /** + * The FilterOperator is a filtered set-union. i.e. the LHS is `unioned' with the RHS, but filtered by the set associated with + * this operator instance. The filter is the set of InstanceKeys corresponding to the target type of this cast. This is still + * monotonic. + * + * LHS U= (RHS n k) + * + * + * Unary op: := Cast_k( ) + * + * (Again, technically a binary op -- see note for Assign) + * + * TODO: these need to be canonicalized. + * + */ + public class FilterOperator extends UnaryOperator implements IPointerOperator { + + protected FilterOperator() { + } + + /* + * @see com.ibm.wala.dataflow.UnaryOperator#evaluate(com.ibm.wala.dataflow.IVariable, com.ibm.wala.dataflow.IVariable) + */ + @Override + public byte evaluate(PointsToSetVariable lhs, PointsToSetVariable rhs) { + + FilteredPointerKey pk = (FilteredPointerKey) lhs.getPointerKey(); + + if (DEBUG_FILTER) { + String S = "EVAL Filter " + lhs.getPointerKey() + " " + rhs.getPointerKey(); + S += "\nEVAL " + lhs + " " + rhs; + System.err.println(S); + } + if (rhs.size() == 0) { + return NOT_CHANGED; + } + + boolean changed = false; + FilteredPointerKey.TypeFilter filter = pk.getTypeFilter(); + changed = filter.addFiltered(system, lhs, rhs); + + if (DEBUG_FILTER) { + System.err.println("RESULT " + lhs + (changed ? " (changed)" : "")); + } + + return changed ? CHANGED : NOT_CHANGED; + } + + /* + * @see com.ibm.wala.ipa.callgraph.propagation.IPointerOperator#isComplex() + */ + public boolean isComplex() { + return false; + } + + @Override + public String toString() { + return "Filter "; + } + + @Override + public boolean equals(Object obj) { + // these objects are canonicalized for the duration of a solve + return this == obj; + } + + @Override + public int hashCode() { + return 88651; + } + + } + + public IClassHierarchy getClassHierarchy() { + return cha; + } + + public AnalysisOptions getOptions() { + return options; + } + + public IClass getJavaLangObject() { + return JAVA_LANG_OBJECT; + } + + public ExplicitCallGraph getCallGraph() { + return callGraph; + } + + /** + * Subclasses must register the context interpreter before building a call graph. + */ + public void setContextInterpreter(SSAContextInterpreter interpreter) { + contextInterpreter = interpreter; + callGraph.setInterpreter(interpreter); + } + + /* + * @see com.ibm.detox.ipa.callgraph.CallGraphBuilder#getPointerAnalysis() + */ + public PointerAnalysis getPointerAnalysis() { + return system.extractPointerAnalysis(this); + } + + public PropagationSystem getPropagationSystem() { + return system; + } + + public PointerKeyFactory getPointerKeyFactory() { + return pointerKeyFactory; + } + + public RTAContextInterpreter getContextInterpreter() { + return contextInterpreter; + } + + /** + * @param caller the caller node + * @param iKey an abstraction of the receiver of the call (or null if not applicable) + * @return the CGNode to which this particular call should dispatch. + */ + protected CGNode getTargetForCall(CGNode caller, CallSiteReference site, IClass recv, InstanceKey iKey[]) { + + IMethod targetMethod = options.getMethodTargetSelector().getCalleeTarget(caller, site, recv); + + // this most likely indicates an exclusion at work; the target selector + // should have issued a warning + if (targetMethod == null || targetMethod.isAbstract()) { + return null; + } + Context targetContext = contextSelector.getCalleeTarget(caller, site, targetMethod, iKey); + + if (targetContext instanceof IllegalArgumentExceptionContext) { + return null; + } + try { + return getCallGraph().findOrCreateNode(targetMethod, targetContext); + } catch (CancelException e) { + return null; + } + } + + /** + * @return the context selector for this call graph builder + */ + public ContextSelector getContextSelector() { + return contextSelector; + } + + public void setContextSelector(ContextSelector selector) { + contextSelector = selector; + } + + public InstanceKeyFactory getInstanceKeys() { + return instanceKeyFactory; + } + + public void setInstanceKeys(InstanceKeyFactory keys) { + this.instanceKeyFactory = keys; + } + + /** + * @return the InstanceKey that acts as a representative for the class of objects that includes objects allocated at the given new + * instruction in the given node + */ + public InstanceKey getInstanceKeyForAllocation(CGNode node, NewSiteReference allocation) { + return instanceKeyFactory.getInstanceKeyForAllocation(node, allocation); + } + + /** + * @param dim the dimension of the array whose instance we would like to model. dim == 0 represents the first dimension, e.g., the + * [Object; instances in [[Object; e.g., the [[Object; instances in [[[Object; dim == 1 represents the second dimension, + * e.g., the [Object instances in [[[Object; + * @return the InstanceKey that acts as a representative for the class of array contents objects that includes objects allocated + * at the given new instruction in the given node + */ + public InstanceKey getInstanceKeyForMultiNewArray(CGNode node, NewSiteReference allocation, int dim) { + return instanceKeyFactory.getInstanceKeyForMultiNewArray(node, allocation, dim); + } + + public InstanceKey getInstanceKeyForConstant(TypeReference type, T S) { + return instanceKeyFactory.getInstanceKeyForConstant(type, S); + } + + public InstanceKey getInstanceKeyForClassObject(TypeReference type) { + return instanceKeyFactory.getInstanceKeyForClassObject(type); + } + + public boolean haveAlreadyVisited(CGNode node) { + return alreadyVisited.contains(node); + } + + protected void markAlreadyVisited(CGNode node) { + alreadyVisited.add(node); + } + + /** + * record that we've discovered a node + */ + public void markDiscovered(CGNode node) { + discoveredNodes.add(node); + } + + protected void markChanged(CGNode node) { + alreadyVisited.remove(node); + discoveredNodes.add(node); + } + + protected boolean wasChanged(CGNode node) { + return discoveredNodes.contains(node) && !alreadyVisited.contains(node); + } + + /** + * Binary op: := ArrayLoad( <arrayref>) Side effect: Creates new equations. + */ + public final class ArrayLoadOperator extends UnarySideEffect implements IPointerOperator { + protected final MutableIntSet priorInstances = rememberGetPutHistory ? IntSetUtil.make() : null; + + @Override + public String toString() { + return "ArrayLoad"; + } + + public ArrayLoadOperator(PointsToSetVariable def) { + super(def); + system.registerFixedSet(def, this); + } + + @Override + public byte evaluate(PointsToSetVariable rhs) { + if (DEBUG_ARRAY_LOAD) { + PointsToSetVariable def = getFixedSet(); + String S = "EVAL ArrayLoad " + rhs.getPointerKey() + " " + def.getPointerKey(); + System.err.println(S); + System.err.println("EVAL ArrayLoad " + def + " " + rhs); + if (priorInstances != null) { + System.err.println("prior instances: " + priorInstances + " " + priorInstances.getClass()); + } + } + + if (rhs.size() == 0) { + return NOT_CHANGED; + } + final PointerKey object = rhs.getPointerKey(); + + PointsToSetVariable def = getFixedSet(); + final PointerKey dVal = def.getPointerKey(); + + final MutableBoolean sideEffect = new MutableBoolean(); + IntSetAction action = new IntSetAction() { + public void act(int i) { + InstanceKey I = system.getInstanceKey(i); + if (!I.getConcreteType().isArrayClass()) { + return; + } + TypeReference C = I.getConcreteType().getReference().getArrayElementType(); + if (C.isPrimitiveType()) { + return; + } + PointerKey p = getPointerKeyForArrayContents(I); + if (p == null) { + return; + } + + if (DEBUG_ARRAY_LOAD) { + System.err.println("ArrayLoad add assign: " + dVal + " " + p); + } + sideEffect.b |= system.newFieldRead(dVal, assignOperator, p, object); + } + }; + if (priorInstances != null) { + rhs.getValue().foreachExcluding(priorInstances, action); + priorInstances.addAll(rhs.getValue()); + } else { + rhs.getValue().foreach(action); + } + byte sideEffectMask = sideEffect.b ? (byte) SIDE_EFFECT_MASK : 0; + return (byte) (NOT_CHANGED | sideEffectMask); + } + + @Override + public int hashCode() { + return 9871 + super.hashCode(); + } + + @Override + public boolean equals(Object o) { + return super.equals(o); + } + + @Override + protected boolean isLoadOperator() { + return true; + } + + /* + * @see com.ibm.wala.ipa.callgraph.propagation.IPointerOperator#isComplex() + */ + public boolean isComplex() { + return true; + } + } + + /** + * Binary op: := ArrayStore( <arrayref>) Side effect: Creates new equations. + */ + public final class ArrayStoreOperator extends UnarySideEffect implements IPointerOperator { + @Override + public String toString() { + return "ArrayStore"; + } + + public ArrayStoreOperator(PointsToSetVariable val) { + super(val); + system.registerFixedSet(val, this); + } + + @Override + public byte evaluate(PointsToSetVariable rhs) { + if (DEBUG_ARRAY_STORE) { + PointsToSetVariable val = getFixedSet(); + String S = "EVAL ArrayStore " + rhs.getPointerKey() + " " + val.getPointerKey(); + System.err.println(S); + System.err.println("EVAL ArrayStore " + rhs + " " + getFixedSet()); + } + + if (rhs.size() == 0) { + return NOT_CHANGED; + } + PointerKey object = rhs.getPointerKey(); + + PointsToSetVariable val = getFixedSet(); + PointerKey pVal = val.getPointerKey(); + + List instances = system.getInstances(rhs.getValue()); + boolean sideEffect = false; + for (Iterator it = instances.iterator(); it.hasNext();) { + InstanceKey I = it.next(); + if (!I.getConcreteType().isArrayClass()) { + continue; + } + if (I instanceof ZeroLengthArrayInNode) { + continue; + } + TypeReference C = I.getConcreteType().getReference().getArrayElementType(); + if (C.isPrimitiveType()) { + continue; + } + IClass contents = getClassHierarchy().lookupClass(C); + if (contents == null) { + assert false : "null type for " + C + " " + I.getConcreteType(); + } + PointerKey p = getPointerKeyForArrayContents(I); + if (DEBUG_ARRAY_STORE) { + System.err.println("ArrayStore add filtered-assign: " + p + " " + pVal); + } + + // note that the following is idempotent + if (isJavaLangObject(contents)) { + sideEffect |= system.newFieldWrite(p, assignOperator, pVal, object); + } else { + sideEffect |= system.newFieldWrite(p, filterOperator, pVal, object); + } + } + byte sideEffectMask = sideEffect ? (byte) SIDE_EFFECT_MASK : 0; + return (byte) (NOT_CHANGED | sideEffectMask); + } + + @Override + public int hashCode() { + return 9859 + super.hashCode(); + } + + public boolean isComplex() { + return true; + } + + @Override + public boolean equals(Object o) { + return super.equals(o); + } + + @Override + protected boolean isLoadOperator() { + return false; + } + } + + /** + * Binary op: := GetField( ) Side effect: Creates new equations. + */ + public class GetFieldOperator extends UnarySideEffect implements IPointerOperator { + private final IField field; + + protected final MutableIntSet priorInstances = rememberGetPutHistory ? IntSetUtil.make() : null; + + public GetFieldOperator(IField field, PointsToSetVariable def) { + super(def); + this.field = field; + system.registerFixedSet(def, this); + } + + @Override + public String toString() { + return "GetField " + getField() + "," + getFixedSet().getPointerKey(); + } + + @Override + public byte evaluate(PointsToSetVariable rhs) { + if (DEBUG_GET) { + String S = "EVAL GetField " + getField() + " " + getFixedSet().getPointerKey() + " " + rhs.getPointerKey() + getFixedSet() + + " " + rhs; + System.err.println(S); + } + + PointsToSetVariable ref = rhs; + if (ref.size() == 0) { + return NOT_CHANGED; + } + final PointerKey object = ref.getPointerKey(); + PointsToSetVariable def = getFixedSet(); + final PointerKey dVal = def.getPointerKey(); + + IntSet value = filterInstances(ref.getValue()); + if (DEBUG_GET) { + System.err.println("filtered value: " + value + " " + value.getClass()); + if (priorInstances != null) { + System.err.println("prior instances: " + priorInstances + " " + priorInstances.getClass()); + } + } + final MutableBoolean sideEffect = new MutableBoolean(); + IntSetAction action = new IntSetAction() { + public void act(int i) { + InstanceKey I = system.getInstanceKey(i); + if (!representsNullType(I)) { + PointerKey p = getPointerKeyForInstanceField(I, getField()); + + if (p != null) { + if (DEBUG_GET) { + String S = "Getfield add constraint " + dVal + " " + p; + System.err.println(S); + } + sideEffect.b |= system.newFieldRead(dVal, assignOperator, p, object); + } + } + } + }; + if (priorInstances != null) { + value.foreachExcluding(priorInstances, action); + priorInstances.addAll(value); + } else { + value.foreach(action); + } + byte sideEffectMask = sideEffect.b ? (byte) SIDE_EFFECT_MASK : 0; + return (byte) (NOT_CHANGED | sideEffectMask); + } + + /** + * Subclasses can override as needed + */ + protected IntSet filterInstances(IntSet value) { + return value; + } + + @Override + public int hashCode() { + return 9857 * getField().hashCode() + getFixedSet().hashCode(); + } + + @Override + public boolean equals(Object o) { + if (o instanceof GetFieldOperator) { + GetFieldOperator other = (GetFieldOperator) o; + return getField().equals(other.getField()) && getFixedSet().equals(other.getFixedSet()); + } else { + return false; + } + } + + protected IField getField() { + return field; + } + + @Override + protected boolean isLoadOperator() { + return true; + } + + /* + * @see com.ibm.wala.ipa.callgraph.propagation.IPointerOperator#isComplex() + */ + public boolean isComplex() { + return true; + } + } + + /** + * Operator that represents a putfield + */ + public class PutFieldOperator extends UnarySideEffect implements IPointerOperator { + private final IField field; + + protected final MutableIntSet priorInstances = rememberGetPutHistory ? IntSetUtil.make() : null; + + @Override + public String toString() { + return "PutField" + getField(); + } + + public PutFieldOperator(IField field, PointsToSetVariable val) { + super(val); + this.field = field; + system.registerFixedSet(val, this); + } + + /* + * @see com.ibm.wala.ipa.callgraph.propagation.IPointerOperator#isComplex() + */ + public boolean isComplex() { + return true; + } + + @Override + public byte evaluate(PointsToSetVariable rhs) { + if (DEBUG_PUT) { + String S = "EVAL PutField " + getField() + " " + (getFixedSet()).getPointerKey() + " " + rhs.getPointerKey() + + getFixedSet() + " " + rhs; + System.err.println(S); + } + + if (rhs.size() == 0) { + return NOT_CHANGED; + } + final PointerKey object = rhs.getPointerKey(); + + PointsToSetVariable val = getFixedSet(); + final PointerKey pVal = val.getPointerKey(); + IntSet value = rhs.getValue(); + value = filterInstances(value); + final UnaryOperator assign = getPutAssignmentOperator(); + if (assign == null) { + Assertions.UNREACHABLE(); + } + final MutableBoolean sideEffect = new MutableBoolean(); + IntSetAction action = new IntSetAction() { + public void act(int i) { + InstanceKey I = system.getInstanceKey(i); + if (!representsNullType(I)) { + if (DEBUG_PUT) { + String S = "Putfield consider instance " + I; + System.err.println(S); + } + PointerKey p = getPointerKeyForInstanceField(I, getField()); + if (p != null) { + if (DEBUG_PUT) { + String S = "Putfield add constraint " + p + " " + pVal; + System.err.println(S); + } + sideEffect.b |= system.newFieldWrite(p, assign, pVal, object); + } + } + } + }; + if (priorInstances != null) { + value.foreachExcluding(priorInstances, action); + priorInstances.addAll(value); + } else { + value.foreach(action); + } + byte sideEffectMask = sideEffect.b ? (byte) SIDE_EFFECT_MASK : 0; + return (byte) (NOT_CHANGED | sideEffectMask); + } + + /** + * Subclasses can override as needed + */ + protected IntSet filterInstances(IntSet value) { + return value; + } + + @Override + public int hashCode() { + return 9857 * getField().hashCode() + getFixedSet().hashCode(); + } + + @Override + public boolean equals(Object o) { + if (o != null && o.getClass().equals(getClass())) { + PutFieldOperator other = (PutFieldOperator) o; + return getField().equals(other.getField()) && getFixedSet().equals(other.getFixedSet()); + } else { + return false; + } + } + + /** + * subclasses (e.g. XTA) can override this to enforce a filtered assignment. returns null if there's a problem. + */ + public UnaryOperator getPutAssignmentOperator() { + return assignOperator; + } + + /** + * @return Returns the field. + */ + protected IField getField() { + return field; + } + + @Override + protected boolean isLoadOperator() { + return false; + } + } + + /** + * Update the points-to-set for a field to include a particular instance key. + */ + public final class InstancePutFieldOperator extends UnaryOperator implements IPointerOperator { + final private IField field; + + final private InstanceKey instance; + + protected final MutableIntSet priorInstances = rememberGetPutHistory ? IntSetUtil.make() : null; + + @Override + public String toString() { + return "InstancePutField" + field; + } + + public InstancePutFieldOperator(IField field, InstanceKey instance) { + this.field = field; + this.instance = instance; + } + + /** + * Simply add the instance to each relevant points-to set. + */ + @Override + public byte evaluate(PointsToSetVariable dummyLHS, PointsToSetVariable var) { + PointsToSetVariable ref = var; + if (ref.size() == 0) { + return NOT_CHANGED; + } + IntSet value = ref.getValue(); + final MutableBoolean sideEffect = new MutableBoolean(); + IntSetAction action = new IntSetAction() { + public void act(int i) { + InstanceKey I = system.getInstanceKey(i); + if (!representsNullType(I)) { + PointerKey p = getPointerKeyForInstanceField(I, field); + if (p != null) { + sideEffect.b |= system.newConstraint(p, instance); + } + } + } + }; + if (priorInstances != null) { + value.foreachExcluding(priorInstances, action); + priorInstances.addAll(value); + } else { + value.foreach(action); + } + byte sideEffectMask = sideEffect.b ? (byte) SIDE_EFFECT_MASK : 0; + return (byte) (NOT_CHANGED | sideEffectMask); + } + + @Override + public int hashCode() { + return field.hashCode() + 9839 * instance.hashCode(); + } + + @Override + public boolean equals(Object o) { + if (o instanceof InstancePutFieldOperator) { + InstancePutFieldOperator other = (InstancePutFieldOperator) o; + return field.equals(other.field) && instance.equals(other.instance); + } else { + return false; + } + } + + /* + * @see com.ibm.wala.ipa.callgraph.propagation.IPointerOperator#isComplex() + */ + public boolean isComplex() { + return true; + } + } + + /** + * Update the points-to-set for an array contents to include a particular instance key. + */ + public final class InstanceArrayStoreOperator extends UnaryOperator implements IPointerOperator { + final private InstanceKey instance; + + protected final MutableIntSet priorInstances = rememberGetPutHistory ? IntSetUtil.make() : null; + + @Override + public String toString() { + return "InstanceArrayStore "; + } + + public InstanceArrayStoreOperator(InstanceKey instance) { + this.instance = instance; + } + + /** + * Simply add the instance to each relevant points-to set. + */ + @Override + public byte evaluate(PointsToSetVariable dummyLHS, PointsToSetVariable var) { + PointsToSetVariable arrayref = var; + if (arrayref.size() == 0) { + return NOT_CHANGED; + } + IntSet value = arrayref.getValue(); + final MutableBoolean sideEffect = new MutableBoolean(); + IntSetAction action = new IntSetAction() { + public void act(int i) { + InstanceKey I = system.getInstanceKey(i); + if (!I.getConcreteType().isArrayClass()) { + return; + } + if (I instanceof ZeroLengthArrayInNode) { + return; + } + TypeReference C = I.getConcreteType().getReference().getArrayElementType(); + if (C.isPrimitiveType()) { + return; + } + IClass contents = getClassHierarchy().lookupClass(C); + if (contents == null) { + assert false : "null type for " + C + " " + I.getConcreteType(); + } + PointerKey p = getPointerKeyForArrayContents(I); + if (contents.isInterface()) { + if (getClassHierarchy().implementsInterface(instance.getConcreteType(), contents)) { + sideEffect.b |= system.newConstraint(p, instance); + } + } else { + if (getClassHierarchy().isSubclassOf(instance.getConcreteType(), contents)) { + sideEffect.b |= system.newConstraint(p, instance); + } + } + } + }; + if (priorInstances != null) { + value.foreachExcluding(priorInstances, action); + priorInstances.addAll(value); + } else { + value.foreach(action); + } + byte sideEffectMask = sideEffect.b ? (byte) SIDE_EFFECT_MASK : 0; + return (byte) (NOT_CHANGED | sideEffectMask); + } + + @Override + public int hashCode() { + return 9839 * instance.hashCode(); + } + + @Override + public boolean equals(Object o) { + if (o instanceof InstanceArrayStoreOperator) { + InstanceArrayStoreOperator other = (InstanceArrayStoreOperator) o; + return instance.equals(other.instance); + } else { + return false; + } + } + + /* + * @see com.ibm.wala.ipa.callgraph.propagation.IPointerOperator#isComplex() + */ + public boolean isComplex() { + return true; + } + } + + protected MutableIntSet getMutableInstanceKeysForClass(IClass klass) { + return system.cloneInstanceKeysForClass(klass); + } + + protected IntSet getInstanceKeysForClass(IClass klass) { + return system.getInstanceKeysForClass(klass); + } + + /** + * @param klass a class + * @return an int set which represents the subset of S that correspond to subtypes of klass + */ + protected IntSet filterForClass(IntSet S, IClass klass) { + MutableIntSet filter = null; + if (klass.getReference().equals(TypeReference.JavaLangObject)) { + return S; + } else { + filter = getMutableInstanceKeysForClass(klass); + + boolean debug = false; + if (DEBUG_FILTER) { + String s = "klass " + klass; + System.err.println(s); + System.err.println("initial filter " + filter); + } + filter.intersectWith(S); + + if (DEBUG_FILTER && debug) { + System.err.println("final filter " + filter); + } + } + return filter; + } + + protected class InverseFilterOperator extends FilterOperator { + public InverseFilterOperator() { + super(); + } + + @Override + public String toString() { + return "InverseFilter"; + } + + /* + * @see com.ibm.wala.ipa.callgraph.propagation.IPointerOperator#isComplex() + */ + @Override + public boolean isComplex() { + return false; + } + + /* + * simply check if rhs contains a malleable. + * + * @see com.ibm.wala.dataflow.UnaryOperator#evaluate(com.ibm.wala.dataflow.IVariable, com.ibm.wala.dataflow.IVariable) + */ + @Override + public byte evaluate(PointsToSetVariable lhs, PointsToSetVariable rhs) { + + FilteredPointerKey pk = (FilteredPointerKey) lhs.getPointerKey(); + FilteredPointerKey.TypeFilter filter = pk.getTypeFilter(); + + boolean debug = false; + if (DEBUG_FILTER) { + String S = "EVAL InverseFilter/" + filter + " " + lhs.getPointerKey() + " " + rhs.getPointerKey(); + S += "\nEVAL " + lhs + " " + rhs; + System.err.println(S); + } + if (rhs.size() == 0) { + return NOT_CHANGED; + } + + boolean changed = filter.addInverseFiltered(system, lhs, rhs); + + if (DEBUG_FILTER) { + if (debug) { + System.err.println("RESULT " + lhs + (changed ? " (changed)" : "")); + } + } + return changed ? CHANGED : NOT_CHANGED; + } + } + + protected IPointsToSolver getSolver() { + return solver; + } + + /** + * Add constraints when the interpretation of a node changes (e.g. reflection) + * @param monitor + * @throws CancelException + */ + public void addConstraintsFromChangedNode(CGNode node, IProgressMonitor monitor) throws CancelException { + unconditionallyAddConstraintsFromNode(node, monitor); + } + + protected abstract boolean unconditionallyAddConstraintsFromNode(CGNode node, IProgressMonitor monitor) throws CancelException; + + protected static class MutableBoolean { + // a horrendous hack since we don't have closures + boolean b = false; + } + + public AnalysisCache getAnalysisCache() { + return analysisCache; + }; + +} diff --git a/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/PropagationGraph.java b/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/PropagationGraph.java index cb53984d4..95032499f 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/PropagationGraph.java +++ b/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/PropagationGraph.java @@ -1,1088 +1,1088 @@ -/******************************************************************************* - * 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.ipa.callgraph.propagation; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashSet; -import java.util.Iterator; -import java.util.List; -import java.util.Map; - -import com.ibm.wala.fixedpoint.impl.GeneralStatement; -import com.ibm.wala.fixpoint.AbstractOperator; -import com.ibm.wala.fixpoint.AbstractStatement; -import com.ibm.wala.fixpoint.IFixedPointStatement; -import com.ibm.wala.fixpoint.IFixedPointSystem; -import com.ibm.wala.fixpoint.IVariable; -import com.ibm.wala.fixpoint.UnaryOperator; -import com.ibm.wala.fixpoint.UnaryStatement; -import com.ibm.wala.util.collections.CompoundIterator; -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.HashSetFactory; -import com.ibm.wala.util.collections.SmallMap; -import com.ibm.wala.util.debug.Assertions; -import com.ibm.wala.util.debug.UnimplementedError; -import com.ibm.wala.util.graph.AbstractNumberedGraph; -import com.ibm.wala.util.graph.Graph; -import com.ibm.wala.util.graph.INodeWithNumber; -import com.ibm.wala.util.graph.NumberedEdgeManager; -import com.ibm.wala.util.graph.NumberedGraph; -import com.ibm.wala.util.graph.NumberedNodeManager; -import com.ibm.wala.util.graph.impl.DelegatingNumberedNodeManager; -import com.ibm.wala.util.graph.impl.SparseNumberedEdgeManager; -import com.ibm.wala.util.graph.traverse.Topological; -import com.ibm.wala.util.heapTrace.HeapTracer; -import com.ibm.wala.util.intset.BasicNaturalRelation; -import com.ibm.wala.util.intset.IBinaryNaturalRelation; -import com.ibm.wala.util.intset.IntIterator; -import com.ibm.wala.util.intset.IntPair; -import com.ibm.wala.util.intset.IntSet; - -/** - * A dataflow graph implementation specialized for propagation-based pointer analysis - */ -public class PropagationGraph implements IFixedPointSystem { - - private final static boolean DEBUG = false; - - private final static boolean VERBOSE = false; - - /** - * Track nodes (PointsToSet Variables and AbstractEquations) - */ - private final NumberedNodeManager nodeManager = new DelegatingNumberedNodeManager(); - - /** - * Track edges (equations) that are not represented implicitly - */ - private final NumberedEdgeManager edgeManager = new SparseNumberedEdgeManager(nodeManager, 2, - BasicNaturalRelation.SIMPLE); - - private final DelegateGraph delegateGraph = new DelegateGraph(); - - private final HashSet delegateStatements = HashSetFactory.make(); - - /** - * special representation for implicitly represented unary equations. This is a map from UnaryOperator -> - * IBinaryNonNegativeIntRelation. - * - * for UnaryOperator op, let R be implicitMap.get(op) then (i,j) \in R implies i op j is an equation in the graph - * - */ - private final SmallMap, IBinaryNaturalRelation> implicitUnaryMap = new SmallMap, IBinaryNaturalRelation>(); - - /** - * The inverse of relations in the implicit map - * - * for UnaryOperator op, let R be invImplicitMap.get(op) then (i,j) \in R implies j op i is an equation in the graph - */ - private final SmallMap, IBinaryNaturalRelation> invImplicitUnaryMap = new SmallMap, IBinaryNaturalRelation>(); - - /** - * Number of implicit unary equations registered - */ - private int implicitUnaryCount = 0; - - /** - * @return a relation in map m corresponding to a key - */ - private IBinaryNaturalRelation findOrCreateRelation(Map, IBinaryNaturalRelation> m, - UnaryOperator key) { - IBinaryNaturalRelation result = m.get(key); - if (result == null) { - result = makeRelation(key); - m.put(key, result); - } - return result; - } - - /** - * @return a Relation object to track implicit equations using the operator - */ - private IBinaryNaturalRelation makeRelation(AbstractOperator op) { - byte[] implementation = null; - if (op instanceof AssignOperator) { - // lots of assignments. - implementation = new byte[] { BasicNaturalRelation.SIMPLE_SPACE_STINGY, BasicNaturalRelation.SIMPLE_SPACE_STINGY }; - } else { - // assume sparse assignments with any other operator. - implementation = new byte[] { BasicNaturalRelation.SIMPLE_SPACE_STINGY }; - } - return new BasicNaturalRelation(implementation, BasicNaturalRelation.SIMPLE); - } - - /** - * @author sfink - * - * A graph which tracks explicit equations. - * - * use this with care ... - */ - private class DelegateGraph extends AbstractNumberedGraph { - - private int equationCount = 0; - - private int varCount = 0; - - @Override - public void addNode(INodeWithNumber o) { - Assertions.UNREACHABLE("Don't call me"); - } - - public void addEquation(AbstractStatement eq) { - assert !containsStatement(eq); - equationCount++; - super.addNode(eq); - } - - public void addVariable(PointsToSetVariable v) { - if (!containsVariable(v)) { - varCount++; - super.addNode(v); - } - } - - /* - * @see com.ibm.wala.util.graph.AbstractGraph#getNodeManager() - */ - @Override - protected NumberedNodeManager getNodeManager() { - return nodeManager; - } - - /* - * @see com.ibm.wala.util.graph.AbstractGraph#getEdgeManager() - */ - @Override - protected NumberedEdgeManager getEdgeManager() { - return edgeManager; - } - - protected int getEquationCount() { - return equationCount; - } - - protected int getVarCount() { - return varCount; - } - - } - - /** - * @throws IllegalArgumentException if eq is null - */ - public void addStatement(GeneralStatement eq) { - if (eq == null) { - throw new IllegalArgumentException("eq is null"); - } - PointsToSetVariable lhs = eq.getLHS(); - delegateGraph.addEquation(eq); - delegateStatements.add(eq); - if (lhs != null) { - delegateGraph.addVariable(lhs); - delegateGraph.addEdge(eq, lhs); - } - for (int i = 0; i < eq.getRHS().length; i++) { - PointsToSetVariable v = (PointsToSetVariable) eq.getRHS()[i]; - if (v != null) { - delegateGraph.addVariable(v); - delegateGraph.addEdge(v, eq); - } - } - } - - public void addStatement(UnaryStatement eq) throws IllegalArgumentException { - if (eq == null) { - throw new IllegalArgumentException("eq == null"); - } - if (useImplicitRepresentation(eq)) { - addImplicitStatement(eq); - } else { - PointsToSetVariable lhs = eq.getLHS(); - PointsToSetVariable rhs = eq.getRightHandSide(); - delegateGraph.addEquation(eq); - delegateStatements.add(eq); - if (lhs != null) { - delegateGraph.addVariable(lhs); - delegateGraph.addEdge(eq, lhs); - } - delegateGraph.addVariable(rhs); - delegateGraph.addEdge(rhs, eq); - } - } - - /** - * @return true iff this equation should be represented implicitly in this data structure - */ - private boolean useImplicitRepresentation(IFixedPointStatement s) { - AbstractStatement eq = (AbstractStatement) s; - AbstractOperator op = eq.getOperator(); - return (op instanceof AssignOperator || op instanceof PropagationCallGraphBuilder.FilterOperator); - } - - public void removeVariable(PointsToSetVariable p) { - assert getNumberOfStatementsThatDef(p) == 0; - assert getNumberOfStatementsThatUse(p) == 0; - delegateGraph.removeNode(p); - } - - private void addImplicitStatement(UnaryStatement eq) { - if (DEBUG) { - System.err.println(("addImplicitStatement " + eq)); - } - delegateGraph.addVariable(eq.getLHS()); - delegateGraph.addVariable(eq.getRightHandSide()); - int lhs = eq.getLHS().getGraphNodeId(); - int rhs = eq.getRightHandSide().getGraphNodeId(); - if (DEBUG) { - System.err.println(("lhs rhs " + lhs + " " + rhs)); - } - IBinaryNaturalRelation R = findOrCreateRelation(implicitUnaryMap, eq.getOperator()); - boolean b = R.add(lhs, rhs); - if (b) { - implicitUnaryCount++; - IBinaryNaturalRelation iR = findOrCreateRelation(invImplicitUnaryMap, eq.getOperator()); - iR.add(rhs, lhs); - } - } - - private void removeImplicitStatement(UnaryStatement eq) { - if (DEBUG) { - System.err.println(("removeImplicitStatement " + eq)); - } - int lhs = eq.getLHS().getGraphNodeId(); - int rhs = eq.getRightHandSide().getGraphNodeId(); - if (DEBUG) { - System.err.println(("lhs rhs " + lhs + " " + rhs)); - } - IBinaryNaturalRelation R = findOrCreateRelation(implicitUnaryMap, eq.getOperator()); - R.remove(lhs, rhs); - IBinaryNaturalRelation iR = findOrCreateRelation(invImplicitUnaryMap, eq.getOperator()); - iR.remove(rhs, lhs); - implicitUnaryCount--; - } - - @SuppressWarnings("unchecked") - public Iterator getStatements() { - Iterator it = new FilterIterator(delegateGraph.iterator(), new Filter() { - public boolean accepts(Object x) { - return x instanceof AbstractStatement; - } - }); - return new CompoundIterator(it, new GlobalImplicitIterator()); - } - - /** - * Iterator of implicit equations that use a particular variable. - */ - private final class ImplicitUseIterator implements Iterator { - - final PointsToSetVariable use; - - final IntIterator defs; - - final UnaryOperator op; - - ImplicitUseIterator(UnaryOperator op, PointsToSetVariable use, IntSet defs) { - this.op = op; - this.use = use; - this.defs = defs.intIterator(); - } - - public boolean hasNext() { - return defs.hasNext(); - } - - public AbstractStatement next() { - int l = defs.next(); - PointsToSetVariable lhs = (PointsToSetVariable) delegateGraph.getNode(l); - UnaryStatement temp = op.makeEquation(lhs, use); - if (DEBUG) { - System.err.print(("XX Return temp: " + temp)); - System.err.println(("lhs rhs " + l + " " + use.getGraphNodeId())); - } - return temp; - } - - public void remove() { - // TODO Auto-generated method stub - Assertions.UNREACHABLE(); - } - } - - /** - * Iterator of implicit equations that def a particular variable. - */ - private final class ImplicitDefIterator implements Iterator { - - final PointsToSetVariable def; - - final IntIterator uses; - - final UnaryOperator op; - - ImplicitDefIterator(UnaryOperator op, IntSet uses, PointsToSetVariable def) { - this.op = op; - this.def = def; - this.uses = uses.intIterator(); - } - - public boolean hasNext() { - return uses.hasNext(); - } - - public AbstractStatement next() { - int r = uses.next(); - PointsToSetVariable rhs = (PointsToSetVariable) delegateGraph.getNode(r); - UnaryStatement temp = op.makeEquation(def, rhs); - if (DEBUG) { - System.err.print(("YY Return temp: " + temp)); - } - return temp; - } - - public void remove() { - // TODO Auto-generated method stub - Assertions.UNREACHABLE(); - } - } - - /** - * Iterator of all implicit equations - */ - private class GlobalImplicitIterator implements Iterator { - - private final Iterator> outerKeyDelegate = implicitUnaryMap.keySet().iterator(); - - private Iterator innerDelegate; - - private UnaryOperator currentOperator; - - GlobalImplicitIterator() { - advanceOuter(); - } - - /** - * advance to the next operator - */ - private void advanceOuter() { - innerDelegate = null; - while (outerKeyDelegate.hasNext()) { - currentOperator = outerKeyDelegate.next(); - IBinaryNaturalRelation R = implicitUnaryMap.get(currentOperator); - Iterator it = R.iterator(); - if (it.hasNext()) { - innerDelegate = it; - return; - } - } - } - - public boolean hasNext() { - return innerDelegate != null; - } - - public AbstractStatement next() { - IntPair p = (IntPair) innerDelegate.next(); - int lhs = p.getX(); - int rhs = p.getY(); - UnaryStatement result = currentOperator.makeEquation((PointsToSetVariable) delegateGraph.getNode(lhs), - (PointsToSetVariable) delegateGraph.getNode(rhs)); - if (!innerDelegate.hasNext()) { - advanceOuter(); - } - return result; - } - - public void remove() { - // TODO Auto-generated method stub - Assertions.UNREACHABLE(); - - } - } - - public void removeStatement(IFixedPointStatement eq) throws IllegalArgumentException { - if (eq == null) { - throw new IllegalArgumentException("eq == null"); - } - if (useImplicitRepresentation(eq)) { - removeImplicitStatement((UnaryStatement) eq); - } else { - delegateStatements.remove(eq); - delegateGraph.removeNodeAndEdges(eq); - } - } - - public void reorder() { - VariableGraphView graph = new VariableGraphView(); - - Iterator order = Topological.makeTopologicalIter(graph); - - int number = 0; - while (order.hasNext()) { - Object elt = order.next(); - if (elt instanceof IVariable) { - IVariable v = (IVariable) elt; - v.setOrderNumber(number++); - } - } - } - - /** - * A graph of just the variables in the system. v1 -> v2 iff there exists equation e s.t. e uses v1 and e defs v2. - * - * Note that this graph trickily and fragilely reuses the nodeManager from the delegateGraph, above. This will work ok as long as - * every variable is inserted in the delegateGraph. - */ - private class VariableGraphView extends AbstractNumberedGraph { - - /* - * @see com.ibm.wala.util.graph.Graph#removeNodeAndEdges(java.lang.Object) - */ - @Override - public void removeNodeAndEdges(PointsToSetVariable N) { - Assertions.UNREACHABLE(); - } - - /* - * @see com.ibm.wala.util.graph.NodeManager#iterateNodes() - */ - @Override - public Iterator iterator() { - return getVariables(); - } - - /* - * @see com.ibm.wala.util.graph.NodeManager#getNumberOfNodes() - */ - @Override - public int getNumberOfNodes() { - return delegateGraph.getVarCount(); - } - - /* - * @see com.ibm.wala.util.graph.NodeManager#addNode(java.lang.Object) - */ - @Override - public void addNode(PointsToSetVariable n) { - Assertions.UNREACHABLE(); - - } - - /* - * @see com.ibm.wala.util.graph.NodeManager#removeNode(java.lang.Object) - */ - @Override - public void removeNode(PointsToSetVariable n) { - Assertions.UNREACHABLE(); - - } - - /* - * @see com.ibm.wala.util.graph.NodeManager#containsNode(java.lang.Object) - */ - @Override - public boolean containsNode(PointsToSetVariable N) { - Assertions.UNREACHABLE(); - return false; - } - - /* - * @see com.ibm.wala.util.graph.EdgeManager#getPredNodes(java.lang.Object) - */ - @Override - public Iterator getPredNodes(PointsToSetVariable v) { - final Iterator eqs = getStatementsThatDef(v); - return new Iterator() { - Iterator inner; - - public boolean hasNext() { - return eqs.hasNext() || (inner != null); - } - - public PointsToSetVariable next() { - if (inner != null) { - PointsToSetVariable result = (PointsToSetVariable)inner.next(); - if (!inner.hasNext()) { - inner = null; - } - return result; - } else { - AbstractStatement eq = (AbstractStatement) eqs.next(); - if (useImplicitRepresentation(eq)) { - return (PointsToSetVariable) ((UnaryStatement) eq).getRightHandSide(); - } else { - inner = delegateGraph.getPredNodes(eq); - return next(); - } - } - } - - public void remove() { - // TODO Auto-generated method stub - Assertions.UNREACHABLE(); - } - }; - } - - /* - * @see com.ibm.wala.util.graph.EdgeManager#getPredNodeCount(java.lang.Object) - */ - @SuppressWarnings("unused") - public int getPredNodeCount(INodeWithNumber N) { - PointsToSetVariable v = (PointsToSetVariable) N; - int result = 0; - for (Iterator eqs = getStatementsThatDef(v); eqs.hasNext();) { - AbstractStatement eq = (AbstractStatement) eqs.next(); - if (useImplicitRepresentation(eq)) { - result++; - } else { - result += delegateGraph.getPredNodeCount(N); - } - } - return result; - } - - /* - * @see com.ibm.wala.util.graph.EdgeManager#getSuccNodes(java.lang.Object) - */ - @Override - public Iterator getSuccNodes(PointsToSetVariable v) { - final Iterator eqs = getStatementsThatUse(v); - return new Iterator() { - PointsToSetVariable nextResult; - { - advance(); - } - - public boolean hasNext() { - return nextResult != null; - } - - public PointsToSetVariable next() { - PointsToSetVariable result = nextResult; - advance(); - return result; - } - - private void advance() { - nextResult = null; - while (eqs.hasNext() && nextResult == null) { - AbstractStatement eq = (AbstractStatement) eqs.next(); - nextResult = (PointsToSetVariable) eq.getLHS(); - } - } - - public void remove() { - // TODO Auto-generated method stub - Assertions.UNREACHABLE(); - } - }; - } - - /* - * @see com.ibm.wala.util.graph.EdgeManager#getSuccNodeCount(java.lang.Object) - */ - @Override - public int getSuccNodeCount(PointsToSetVariable v) { - int result = 0; - for (Iterator eqs = getStatementsThatUse(v); eqs.hasNext();) { - AbstractStatement eq = (AbstractStatement) eqs.next(); - IVariable lhs = eq.getLHS(); - if (lhs != null) { - result++; - } - } - return result; - } - - /* - * @see com.ibm.wala.util.graph.EdgeManager#addEdge(java.lang.Object, java.lang.Object) - */ - @Override - public void addEdge(PointsToSetVariable src, PointsToSetVariable dst) { - Assertions.UNREACHABLE(); - } - - /* - * @see com.ibm.wala.util.graph.EdgeManager#removeAllIncidentEdges(java.lang.Object) - */ - @Override - public void removeAllIncidentEdges(PointsToSetVariable node) { - Assertions.UNREACHABLE(); - } - - /* - * @see com.ibm.wala.util.graph.AbstractGraph#getNodeManager() - */ - @Override - @SuppressWarnings("unchecked") - protected NumberedNodeManager getNodeManager() { - return nodeManager; - } - - /* - * @see com.ibm.wala.util.graph.AbstractGraph#getEdgeManager() - */ - @Override - @SuppressWarnings("unchecked") - protected NumberedEdgeManager getEdgeManager() { - // TODO Auto-generated method stub - Assertions.UNREACHABLE(); - return null; - } - - } - - @SuppressWarnings("unchecked") - public Iterator getStatementsThatUse(PointsToSetVariable v) { - if (v == null) { - throw new IllegalArgumentException("v is null"); - } - int number = v.getGraphNodeId(); - if (number == -1) { - return EmptyIterator.instance(); - } - Iterator result = delegateGraph.getSuccNodes(v); - for (int i = 0; i < invImplicitUnaryMap.size(); i++) { - UnaryOperator op = invImplicitUnaryMap.getKey(i); - IBinaryNaturalRelation R = (IBinaryNaturalRelation) invImplicitUnaryMap.getValue(i); - IntSet s = R.getRelated(number); - if (s != null) { - result = new CompoundIterator(new ImplicitUseIterator(op, v, s), result); - } - } - List list = new ArrayList(); - while (result.hasNext()) { - list.add((AbstractStatement) result.next()); - } - return list.iterator(); - } - - @SuppressWarnings("unchecked") - public Iterator getStatementsThatDef(PointsToSetVariable v) { - if (v == null) { - throw new IllegalArgumentException("v is null"); - } - int number = v.getGraphNodeId(); - if (number == -1) { - return EmptyIterator.instance(); - } - Iterator result = delegateGraph.getPredNodes(v); - for (int i = 0; i < implicitUnaryMap.size(); i++) { - UnaryOperator op = implicitUnaryMap.getKey(i); - IBinaryNaturalRelation R = (IBinaryNaturalRelation) implicitUnaryMap.getValue(i); - IntSet s = R.getRelated(number); - if (s != null) { - result = new CompoundIterator(new ImplicitDefIterator(op, s, v), result); - } - } - - List list = new ArrayList(); - while (result.hasNext()) { - list.add((AbstractStatement) result.next()); - } - return list.iterator(); - } - - /** - * Note that this implementation consults the implicit relation for each and every operator cached. This will be inefficient if - * there are many implicit operators. - * - * @throws IllegalArgumentException if v is null - * - */ - public int getNumberOfStatementsThatUse(PointsToSetVariable v) { - if (v == null) { - throw new IllegalArgumentException("v is null"); - } - int number = v.getGraphNodeId(); - if (number == -1) { - return 0; - } - int result = delegateGraph.getSuccNodeCount(v); - for (Iterator it = invImplicitUnaryMap.keySet().iterator(); it.hasNext();) { - UnaryOperator op = (UnaryOperator) it.next(); - IBinaryNaturalRelation R = invImplicitUnaryMap.get(op); - IntSet s = R.getRelated(number); - if (s != null) { - result += s.size(); - } - } - return result; - } - - public int getNumberOfStatementsThatDef(PointsToSetVariable v) { - if (v == null) { - throw new IllegalArgumentException("v is null"); - } - int number = v.getGraphNodeId(); - if (number == -1) { - return 0; - } - int result = delegateGraph.getPredNodeCount(v); - for (Iterator it = implicitUnaryMap.keySet().iterator(); it.hasNext();) { - UnaryOperator op = (UnaryOperator) it.next(); - IBinaryNaturalRelation R = implicitUnaryMap.get(op); - IntSet s = R.getRelated(number); - if (s != null) { - result += s.size(); - } - } - return result; - } - - @SuppressWarnings("unchecked") - public Iterator getVariables() { - Iterator it = new FilterIterator(delegateGraph.iterator(), new Filter() { - public boolean accepts(Object x) { - return x instanceof IVariable; - } - }); - return it; - } - - /* - * @see com.ibm.wala.util.debug.VerboseAction#performVerboseAction() - */ - public void performVerboseAction() { - if (VERBOSE) { - System.err.println(("stats for " + getClass())); - System.err.println(("number of variables: " + delegateGraph.getVarCount())); - System.err.println(("implicit equations: " + (implicitUnaryCount))); - System.err.println(("explicit equations: " + delegateGraph.getEquationCount())); - System.err.println("implicit map:"); - int count = 0; - int totalBytes = 0; - for (Iterator it = implicitUnaryMap.entrySet().iterator(); it.hasNext();) { - count++; - Map.Entry e = (Map.Entry) it.next(); - IBinaryNaturalRelation R = (IBinaryNaturalRelation) e.getValue(); - System.err.println(("entry " + count)); - R.performVerboseAction(); - HeapTracer.Result result = HeapTracer.traceHeap(Collections.singleton(R), false); - totalBytes += result.getTotalSize(); - } - System.err.println(("bytes in implicit map: " + totalBytes)); - } - } - - public boolean containsStatement(IFixedPointStatement eq) throws IllegalArgumentException { - if (eq == null) { - throw new IllegalArgumentException("eq == null"); - } - if (useImplicitRepresentation(eq)) { - UnaryStatement ueq = (UnaryStatement) eq; - return containsImplicitStatement(ueq); - } else { - return delegateStatements.contains(eq); - } - } - - /** - * @return true iff the graph already contains this equation - */ - private boolean containsImplicitStatement(UnaryStatement eq) { - if (!containsVariable(eq.getLHS())) { - return false; - } - if (!containsVariable(eq.getRightHandSide())) { - return false; - } - int lhs = eq.getLHS().getGraphNodeId(); - int rhs = eq.getRightHandSide().getGraphNodeId(); - UnaryOperator op = eq.getOperator(); - IBinaryNaturalRelation R = implicitUnaryMap.get(op); - if (R != null) { - return R.contains(lhs, rhs); - } else { - return false; - } - } - - public boolean containsVariable(PointsToSetVariable v) { - return delegateGraph.containsNode(v); - } - - public void addStatement(IFixedPointStatement statement) throws IllegalArgumentException, UnimplementedError { - if (statement == null) { - throw new IllegalArgumentException("statement == null"); - } - if (statement instanceof UnaryStatement) { - addStatement((UnaryStatement) statement); - } else if (statement instanceof GeneralStatement) { - addStatement((GeneralStatement) statement); - } else { - Assertions.UNREACHABLE("unexpected: " + statement.getClass()); - } - } - - /** - * A graph of just the variables in the system. v1 -> v2 iff there exists an assignment equation e s.t. e uses v1 and e defs v2. - * - */ - public NumberedGraph getAssignmentGraph() { - return new FilteredConstraintGraphView() { - - @Override - boolean isInteresting(AbstractStatement eq) { - return eq instanceof AssignEquation; - } - }; - } - - /** - * A graph of just the variables in the system. v1 -> v2 iff there exists an Assingnment or Filter equation e s.t. e uses v1 and e - * defs v2. - * - */ - public Graph getFilterAssignmentGraph() { - return new FilteredConstraintGraphView() { - - @Override - boolean isInteresting(AbstractStatement eq) { - return eq instanceof AssignEquation || eq.getOperator() instanceof PropagationCallGraphBuilder.FilterOperator; - } - }; - } - - /** - * NOTE: do not use this method unless you really know what you are doing. Functionality is fragile and may not work in the - * future. - */ - public Graph getFlowGraphIncludingImplicitConstraints() { - return new VariableGraphView(); - } - - /** - * A graph of just the variables in the system. v1 -> v2 that are related by def-use with "interesting" operators - * - */ - private abstract class FilteredConstraintGraphView extends AbstractNumberedGraph { - - abstract boolean isInteresting(AbstractStatement eq); - - /* - * @see com.ibm.wala.util.graph.Graph#removeNodeAndEdges(java.lang.Object) - */ - @Override - public void removeNodeAndEdges(PointsToSetVariable N) { - Assertions.UNREACHABLE(); - } - - /* - * @see com.ibm.wala.util.graph.NodeManager#iterateNodes() - */ - @Override - public Iterator iterator() { - return getVariables(); - } - - /* - * @see com.ibm.wala.util.graph.NodeManager#getNumberOfNodes() - */ - @Override - public int getNumberOfNodes() { - return delegateGraph.getVarCount(); - } - - /* - * @see com.ibm.wala.util.graph.NodeManager#addNode(java.lang.Object) - */ - @Override - public void addNode(PointsToSetVariable n) { - Assertions.UNREACHABLE(); - - } - - /* - * @see com.ibm.wala.util.graph.NodeManager#removeNode(java.lang.Object) - */ - @Override - public void removeNode(PointsToSetVariable n) { - Assertions.UNREACHABLE(); - - } - - /* - * @see com.ibm.wala.util.graph.NodeManager#containsNode(java.lang.Object) - */ - @Override - public boolean containsNode(PointsToSetVariable N) { - Assertions.UNREACHABLE(); - return false; - } - - /* - * @see com.ibm.wala.util.graph.EdgeManager#getPredNodes(java.lang.Object) - */ - @Override - public Iterator getPredNodes(PointsToSetVariable v) { - final Iterator eqs = getStatementsThatDef(v); - return new Iterator() { - PointsToSetVariable nextResult; - { - advance(); - } - - public boolean hasNext() { - return nextResult != null; - } - - public PointsToSetVariable next() { - PointsToSetVariable result = nextResult; - advance(); - return result; - } - - private void advance() { - nextResult = null; - while (eqs.hasNext() && nextResult == null) { - AbstractStatement eq = (AbstractStatement) eqs.next(); - if (isInteresting(eq)) { - nextResult = (PointsToSetVariable) ((UnaryStatement) eq).getRightHandSide(); - } - } - } - - public void remove() { - Assertions.UNREACHABLE(); - } - }; - } - - /* - * @see com.ibm.wala.util.graph.EdgeManager#getPredNodeCount(java.lang.Object) - */ - @Override - public int getPredNodeCount(PointsToSetVariable v) { - int result = 0; - for (Iterator eqs = getStatementsThatDef(v); eqs.hasNext();) { - AbstractStatement eq = (AbstractStatement) eqs.next(); - if (isInteresting(eq)) { - result++; - } - } - return result; - } - - /* - * @see com.ibm.wala.util.graph.EdgeManager#getSuccNodes(java.lang.Object) - */ - @Override - public Iterator getSuccNodes(PointsToSetVariable v) { - final Iterator eqs = getStatementsThatUse(v); - return new Iterator() { - PointsToSetVariable nextResult; - { - advance(); - } - - public boolean hasNext() { - return nextResult != null; - } - - public PointsToSetVariable next() { - PointsToSetVariable result = nextResult; - advance(); - return result; - } - - private void advance() { - nextResult = null; - while (eqs.hasNext() && nextResult == null) { - AbstractStatement eq = (AbstractStatement) eqs.next(); - if (isInteresting(eq)) { - nextResult = (PointsToSetVariable) ((UnaryStatement) eq).getLHS(); - } - } - } - - public void remove() { - // TODO Auto-generated method stub - Assertions.UNREACHABLE(); - } - }; - } - - /* - * @see com.ibm.wala.util.graph.EdgeManager#getSuccNodeCount(java.lang.Object) - */ - @Override - public int getSuccNodeCount(PointsToSetVariable v) { - int result = 0; - for (Iterator eqs = getStatementsThatUse(v); eqs.hasNext();) { - AbstractStatement eq = (AbstractStatement) eqs.next(); - if (isInteresting(eq)) { - result++; - } - } - return result; - } - - /* - * @see com.ibm.wala.util.graph.EdgeManager#addEdge(java.lang.Object, java.lang.Object) - */ - @Override - public void addEdge(PointsToSetVariable src, PointsToSetVariable dst) { - Assertions.UNREACHABLE(); - } - - /* - * @see com.ibm.wala.util.graph.EdgeManager#removeAllIncidentEdges(java.lang.Object) - */ - @Override - public void removeAllIncidentEdges(PointsToSetVariable node) { - Assertions.UNREACHABLE(); - } - - /* - * @see com.ibm.wala.util.graph.AbstractGraph#getNodeManager() - */ - @Override - @SuppressWarnings("unchecked") - protected NumberedNodeManager getNodeManager() { - return nodeManager; - } - - /* - * @see com.ibm.wala.util.graph.AbstractGraph#getEdgeManager() - */ - @Override - protected NumberedEdgeManager getEdgeManager() { - Assertions.UNREACHABLE(); - return null; - } - } - - public String spaceReport() { - StringBuffer result = new StringBuffer("PropagationGraph\n"); - result.append("ImplicitEdges:" + countImplicitEdges() + "\n"); - // for (Iterator it = implicitUnaryMap.values().iterator(); it.hasNext(); ) - // { - // result.append(it.next() + "\n"); - // } - return result.toString(); - } - - private int countImplicitEdges() { - int result = 0; - for (Iterator it = new GlobalImplicitIterator(); it.hasNext();) { - it.next(); - result++; - } - return result; - } - -} +/******************************************************************************* + * 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.ipa.callgraph.propagation; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Map; + +import com.ibm.wala.fixedpoint.impl.GeneralStatement; +import com.ibm.wala.fixpoint.AbstractOperator; +import com.ibm.wala.fixpoint.AbstractStatement; +import com.ibm.wala.fixpoint.IFixedPointStatement; +import com.ibm.wala.fixpoint.IFixedPointSystem; +import com.ibm.wala.fixpoint.IVariable; +import com.ibm.wala.fixpoint.UnaryOperator; +import com.ibm.wala.fixpoint.UnaryStatement; +import com.ibm.wala.util.collections.CompoundIterator; +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.HashSetFactory; +import com.ibm.wala.util.collections.SmallMap; +import com.ibm.wala.util.debug.Assertions; +import com.ibm.wala.util.debug.UnimplementedError; +import com.ibm.wala.util.graph.AbstractNumberedGraph; +import com.ibm.wala.util.graph.Graph; +import com.ibm.wala.util.graph.INodeWithNumber; +import com.ibm.wala.util.graph.NumberedEdgeManager; +import com.ibm.wala.util.graph.NumberedGraph; +import com.ibm.wala.util.graph.NumberedNodeManager; +import com.ibm.wala.util.graph.impl.DelegatingNumberedNodeManager; +import com.ibm.wala.util.graph.impl.SparseNumberedEdgeManager; +import com.ibm.wala.util.graph.traverse.Topological; +import com.ibm.wala.util.heapTrace.HeapTracer; +import com.ibm.wala.util.intset.BasicNaturalRelation; +import com.ibm.wala.util.intset.IBinaryNaturalRelation; +import com.ibm.wala.util.intset.IntIterator; +import com.ibm.wala.util.intset.IntPair; +import com.ibm.wala.util.intset.IntSet; + +/** + * A dataflow graph implementation specialized for propagation-based pointer analysis + */ +public class PropagationGraph implements IFixedPointSystem { + + private final static boolean DEBUG = false; + + private final static boolean VERBOSE = false; + + /** + * Track nodes (PointsToSet Variables and AbstractEquations) + */ + private final NumberedNodeManager nodeManager = new DelegatingNumberedNodeManager(); + + /** + * Track edges (equations) that are not represented implicitly + */ + private final NumberedEdgeManager edgeManager = new SparseNumberedEdgeManager(nodeManager, 2, + BasicNaturalRelation.SIMPLE); + + private final DelegateGraph delegateGraph = new DelegateGraph(); + + private final HashSet delegateStatements = HashSetFactory.make(); + + /** + * special representation for implicitly represented unary equations. This is a map from UnaryOperator -> + * IBinaryNonNegativeIntRelation. + * + * for UnaryOperator op, let R be implicitMap.get(op) then (i,j) \in R implies i op j is an equation in the graph + * + */ + private final SmallMap, IBinaryNaturalRelation> implicitUnaryMap = new SmallMap, IBinaryNaturalRelation>(); + + /** + * The inverse of relations in the implicit map + * + * for UnaryOperator op, let R be invImplicitMap.get(op) then (i,j) \in R implies j op i is an equation in the graph + */ + private final SmallMap, IBinaryNaturalRelation> invImplicitUnaryMap = new SmallMap, IBinaryNaturalRelation>(); + + /** + * Number of implicit unary equations registered + */ + private int implicitUnaryCount = 0; + + /** + * @return a relation in map m corresponding to a key + */ + private IBinaryNaturalRelation findOrCreateRelation(Map, IBinaryNaturalRelation> m, + UnaryOperator key) { + IBinaryNaturalRelation result = m.get(key); + if (result == null) { + result = makeRelation(key); + m.put(key, result); + } + return result; + } + + /** + * @return a Relation object to track implicit equations using the operator + */ + private IBinaryNaturalRelation makeRelation(AbstractOperator op) { + byte[] implementation = null; + if (op instanceof AssignOperator) { + // lots of assignments. + implementation = new byte[] { BasicNaturalRelation.SIMPLE_SPACE_STINGY, BasicNaturalRelation.SIMPLE_SPACE_STINGY }; + } else { + // assume sparse assignments with any other operator. + implementation = new byte[] { BasicNaturalRelation.SIMPLE_SPACE_STINGY }; + } + return new BasicNaturalRelation(implementation, BasicNaturalRelation.SIMPLE); + } + + /** + * @author sfink + * + * A graph which tracks explicit equations. + * + * use this with care ... + */ + private class DelegateGraph extends AbstractNumberedGraph { + + private int equationCount = 0; + + private int varCount = 0; + + @Override + public void addNode(INodeWithNumber o) { + Assertions.UNREACHABLE("Don't call me"); + } + + public void addEquation(AbstractStatement eq) { + assert !containsStatement(eq); + equationCount++; + super.addNode(eq); + } + + public void addVariable(PointsToSetVariable v) { + if (!containsVariable(v)) { + varCount++; + super.addNode(v); + } + } + + /* + * @see com.ibm.wala.util.graph.AbstractGraph#getNodeManager() + */ + @Override + protected NumberedNodeManager getNodeManager() { + return nodeManager; + } + + /* + * @see com.ibm.wala.util.graph.AbstractGraph#getEdgeManager() + */ + @Override + protected NumberedEdgeManager getEdgeManager() { + return edgeManager; + } + + protected int getEquationCount() { + return equationCount; + } + + protected int getVarCount() { + return varCount; + } + + } + + /** + * @throws IllegalArgumentException if eq is null + */ + public void addStatement(GeneralStatement eq) { + if (eq == null) { + throw new IllegalArgumentException("eq is null"); + } + PointsToSetVariable lhs = eq.getLHS(); + delegateGraph.addEquation(eq); + delegateStatements.add(eq); + if (lhs != null) { + delegateGraph.addVariable(lhs); + delegateGraph.addEdge(eq, lhs); + } + for (int i = 0; i < eq.getRHS().length; i++) { + PointsToSetVariable v = (PointsToSetVariable) eq.getRHS()[i]; + if (v != null) { + delegateGraph.addVariable(v); + delegateGraph.addEdge(v, eq); + } + } + } + + public void addStatement(UnaryStatement eq) throws IllegalArgumentException { + if (eq == null) { + throw new IllegalArgumentException("eq == null"); + } + if (useImplicitRepresentation(eq)) { + addImplicitStatement(eq); + } else { + PointsToSetVariable lhs = eq.getLHS(); + PointsToSetVariable rhs = eq.getRightHandSide(); + delegateGraph.addEquation(eq); + delegateStatements.add(eq); + if (lhs != null) { + delegateGraph.addVariable(lhs); + delegateGraph.addEdge(eq, lhs); + } + delegateGraph.addVariable(rhs); + delegateGraph.addEdge(rhs, eq); + } + } + + /** + * @return true iff this equation should be represented implicitly in this data structure + */ + private boolean useImplicitRepresentation(IFixedPointStatement s) { + AbstractStatement eq = (AbstractStatement) s; + AbstractOperator op = eq.getOperator(); + return (op instanceof AssignOperator || op instanceof PropagationCallGraphBuilder.FilterOperator); + } + + public void removeVariable(PointsToSetVariable p) { + assert getNumberOfStatementsThatDef(p) == 0; + assert getNumberOfStatementsThatUse(p) == 0; + delegateGraph.removeNode(p); + } + + private void addImplicitStatement(UnaryStatement eq) { + if (DEBUG) { + System.err.println(("addImplicitStatement " + eq)); + } + delegateGraph.addVariable(eq.getLHS()); + delegateGraph.addVariable(eq.getRightHandSide()); + int lhs = eq.getLHS().getGraphNodeId(); + int rhs = eq.getRightHandSide().getGraphNodeId(); + if (DEBUG) { + System.err.println(("lhs rhs " + lhs + " " + rhs)); + } + IBinaryNaturalRelation R = findOrCreateRelation(implicitUnaryMap, eq.getOperator()); + boolean b = R.add(lhs, rhs); + if (b) { + implicitUnaryCount++; + IBinaryNaturalRelation iR = findOrCreateRelation(invImplicitUnaryMap, eq.getOperator()); + iR.add(rhs, lhs); + } + } + + private void removeImplicitStatement(UnaryStatement eq) { + if (DEBUG) { + System.err.println(("removeImplicitStatement " + eq)); + } + int lhs = eq.getLHS().getGraphNodeId(); + int rhs = eq.getRightHandSide().getGraphNodeId(); + if (DEBUG) { + System.err.println(("lhs rhs " + lhs + " " + rhs)); + } + IBinaryNaturalRelation R = findOrCreateRelation(implicitUnaryMap, eq.getOperator()); + R.remove(lhs, rhs); + IBinaryNaturalRelation iR = findOrCreateRelation(invImplicitUnaryMap, eq.getOperator()); + iR.remove(rhs, lhs); + implicitUnaryCount--; + } + + @SuppressWarnings("unchecked") + public Iterator getStatements() { + Iterator it = new FilterIterator(delegateGraph.iterator(), new Filter() { + public boolean accepts(Object x) { + return x instanceof AbstractStatement; + } + }); + return new CompoundIterator(it, new GlobalImplicitIterator()); + } + + /** + * Iterator of implicit equations that use a particular variable. + */ + private final class ImplicitUseIterator implements Iterator { + + final PointsToSetVariable use; + + final IntIterator defs; + + final UnaryOperator op; + + ImplicitUseIterator(UnaryOperator op, PointsToSetVariable use, IntSet defs) { + this.op = op; + this.use = use; + this.defs = defs.intIterator(); + } + + public boolean hasNext() { + return defs.hasNext(); + } + + public AbstractStatement next() { + int l = defs.next(); + PointsToSetVariable lhs = (PointsToSetVariable) delegateGraph.getNode(l); + UnaryStatement temp = op.makeEquation(lhs, use); + if (DEBUG) { + System.err.print(("XX Return temp: " + temp)); + System.err.println(("lhs rhs " + l + " " + use.getGraphNodeId())); + } + return temp; + } + + public void remove() { + // TODO Auto-generated method stub + Assertions.UNREACHABLE(); + } + } + + /** + * Iterator of implicit equations that def a particular variable. + */ + private final class ImplicitDefIterator implements Iterator { + + final PointsToSetVariable def; + + final IntIterator uses; + + final UnaryOperator op; + + ImplicitDefIterator(UnaryOperator op, IntSet uses, PointsToSetVariable def) { + this.op = op; + this.def = def; + this.uses = uses.intIterator(); + } + + public boolean hasNext() { + return uses.hasNext(); + } + + public AbstractStatement next() { + int r = uses.next(); + PointsToSetVariable rhs = (PointsToSetVariable) delegateGraph.getNode(r); + UnaryStatement temp = op.makeEquation(def, rhs); + if (DEBUG) { + System.err.print(("YY Return temp: " + temp)); + } + return temp; + } + + public void remove() { + // TODO Auto-generated method stub + Assertions.UNREACHABLE(); + } + } + + /** + * Iterator of all implicit equations + */ + private class GlobalImplicitIterator implements Iterator { + + private final Iterator> outerKeyDelegate = implicitUnaryMap.keySet().iterator(); + + private Iterator innerDelegate; + + private UnaryOperator currentOperator; + + GlobalImplicitIterator() { + advanceOuter(); + } + + /** + * advance to the next operator + */ + private void advanceOuter() { + innerDelegate = null; + while (outerKeyDelegate.hasNext()) { + currentOperator = outerKeyDelegate.next(); + IBinaryNaturalRelation R = implicitUnaryMap.get(currentOperator); + Iterator it = R.iterator(); + if (it.hasNext()) { + innerDelegate = it; + return; + } + } + } + + public boolean hasNext() { + return innerDelegate != null; + } + + public AbstractStatement next() { + IntPair p = (IntPair) innerDelegate.next(); + int lhs = p.getX(); + int rhs = p.getY(); + UnaryStatement result = currentOperator.makeEquation((PointsToSetVariable) delegateGraph.getNode(lhs), + (PointsToSetVariable) delegateGraph.getNode(rhs)); + if (!innerDelegate.hasNext()) { + advanceOuter(); + } + return result; + } + + public void remove() { + // TODO Auto-generated method stub + Assertions.UNREACHABLE(); + + } + } + + public void removeStatement(IFixedPointStatement eq) throws IllegalArgumentException { + if (eq == null) { + throw new IllegalArgumentException("eq == null"); + } + if (useImplicitRepresentation(eq)) { + removeImplicitStatement((UnaryStatement) eq); + } else { + delegateStatements.remove(eq); + delegateGraph.removeNodeAndEdges(eq); + } + } + + public void reorder() { + VariableGraphView graph = new VariableGraphView(); + + Iterator order = Topological.makeTopologicalIter(graph); + + int number = 0; + while (order.hasNext()) { + Object elt = order.next(); + if (elt instanceof IVariable) { + IVariable v = (IVariable) elt; + v.setOrderNumber(number++); + } + } + } + + /** + * A graph of just the variables in the system. v1 -> v2 iff there exists equation e s.t. e uses v1 and e defs v2. + * + * Note that this graph trickily and fragilely reuses the nodeManager from the delegateGraph, above. This will work ok as long as + * every variable is inserted in the delegateGraph. + */ + private class VariableGraphView extends AbstractNumberedGraph { + + /* + * @see com.ibm.wala.util.graph.Graph#removeNodeAndEdges(java.lang.Object) + */ + @Override + public void removeNodeAndEdges(PointsToSetVariable N) { + Assertions.UNREACHABLE(); + } + + /* + * @see com.ibm.wala.util.graph.NodeManager#iterateNodes() + */ + @Override + public Iterator iterator() { + return getVariables(); + } + + /* + * @see com.ibm.wala.util.graph.NodeManager#getNumberOfNodes() + */ + @Override + public int getNumberOfNodes() { + return delegateGraph.getVarCount(); + } + + /* + * @see com.ibm.wala.util.graph.NodeManager#addNode(java.lang.Object) + */ + @Override + public void addNode(PointsToSetVariable n) { + Assertions.UNREACHABLE(); + + } + + /* + * @see com.ibm.wala.util.graph.NodeManager#removeNode(java.lang.Object) + */ + @Override + public void removeNode(PointsToSetVariable n) { + Assertions.UNREACHABLE(); + + } + + /* + * @see com.ibm.wala.util.graph.NodeManager#containsNode(java.lang.Object) + */ + @Override + public boolean containsNode(PointsToSetVariable N) { + Assertions.UNREACHABLE(); + return false; + } + + /* + * @see com.ibm.wala.util.graph.EdgeManager#getPredNodes(java.lang.Object) + */ + @Override + public Iterator getPredNodes(PointsToSetVariable v) { + final Iterator eqs = getStatementsThatDef(v); + return new Iterator() { + Iterator inner; + + public boolean hasNext() { + return eqs.hasNext() || (inner != null); + } + + public PointsToSetVariable next() { + if (inner != null) { + PointsToSetVariable result = (PointsToSetVariable)inner.next(); + if (!inner.hasNext()) { + inner = null; + } + return result; + } else { + AbstractStatement eq = (AbstractStatement) eqs.next(); + if (useImplicitRepresentation(eq)) { + return (PointsToSetVariable) ((UnaryStatement) eq).getRightHandSide(); + } else { + inner = delegateGraph.getPredNodes(eq); + return next(); + } + } + } + + public void remove() { + // TODO Auto-generated method stub + Assertions.UNREACHABLE(); + } + }; + } + + /* + * @see com.ibm.wala.util.graph.EdgeManager#getPredNodeCount(java.lang.Object) + */ + @SuppressWarnings("unused") + public int getPredNodeCount(INodeWithNumber N) { + PointsToSetVariable v = (PointsToSetVariable) N; + int result = 0; + for (Iterator eqs = getStatementsThatDef(v); eqs.hasNext();) { + AbstractStatement eq = (AbstractStatement) eqs.next(); + if (useImplicitRepresentation(eq)) { + result++; + } else { + result += delegateGraph.getPredNodeCount(N); + } + } + return result; + } + + /* + * @see com.ibm.wala.util.graph.EdgeManager#getSuccNodes(java.lang.Object) + */ + @Override + public Iterator getSuccNodes(PointsToSetVariable v) { + final Iterator eqs = getStatementsThatUse(v); + return new Iterator() { + PointsToSetVariable nextResult; + { + advance(); + } + + public boolean hasNext() { + return nextResult != null; + } + + public PointsToSetVariable next() { + PointsToSetVariable result = nextResult; + advance(); + return result; + } + + private void advance() { + nextResult = null; + while (eqs.hasNext() && nextResult == null) { + AbstractStatement eq = (AbstractStatement) eqs.next(); + nextResult = (PointsToSetVariable) eq.getLHS(); + } + } + + public void remove() { + // TODO Auto-generated method stub + Assertions.UNREACHABLE(); + } + }; + } + + /* + * @see com.ibm.wala.util.graph.EdgeManager#getSuccNodeCount(java.lang.Object) + */ + @Override + public int getSuccNodeCount(PointsToSetVariable v) { + int result = 0; + for (Iterator eqs = getStatementsThatUse(v); eqs.hasNext();) { + AbstractStatement eq = (AbstractStatement) eqs.next(); + IVariable lhs = eq.getLHS(); + if (lhs != null) { + result++; + } + } + return result; + } + + /* + * @see com.ibm.wala.util.graph.EdgeManager#addEdge(java.lang.Object, java.lang.Object) + */ + @Override + public void addEdge(PointsToSetVariable src, PointsToSetVariable dst) { + Assertions.UNREACHABLE(); + } + + /* + * @see com.ibm.wala.util.graph.EdgeManager#removeAllIncidentEdges(java.lang.Object) + */ + @Override + public void removeAllIncidentEdges(PointsToSetVariable node) { + Assertions.UNREACHABLE(); + } + + /* + * @see com.ibm.wala.util.graph.AbstractGraph#getNodeManager() + */ + @Override + @SuppressWarnings("unchecked") + protected NumberedNodeManager getNodeManager() { + return nodeManager; + } + + /* + * @see com.ibm.wala.util.graph.AbstractGraph#getEdgeManager() + */ + @Override + @SuppressWarnings("unchecked") + protected NumberedEdgeManager getEdgeManager() { + // TODO Auto-generated method stub + Assertions.UNREACHABLE(); + return null; + } + + } + + @SuppressWarnings("unchecked") + public Iterator getStatementsThatUse(PointsToSetVariable v) { + if (v == null) { + throw new IllegalArgumentException("v is null"); + } + int number = v.getGraphNodeId(); + if (number == -1) { + return EmptyIterator.instance(); + } + Iterator result = delegateGraph.getSuccNodes(v); + for (int i = 0; i < invImplicitUnaryMap.size(); i++) { + UnaryOperator op = invImplicitUnaryMap.getKey(i); + IBinaryNaturalRelation R = (IBinaryNaturalRelation) invImplicitUnaryMap.getValue(i); + IntSet s = R.getRelated(number); + if (s != null) { + result = new CompoundIterator(new ImplicitUseIterator(op, v, s), result); + } + } + List list = new ArrayList(); + while (result.hasNext()) { + list.add((AbstractStatement) result.next()); + } + return list.iterator(); + } + + @SuppressWarnings("unchecked") + public Iterator getStatementsThatDef(PointsToSetVariable v) { + if (v == null) { + throw new IllegalArgumentException("v is null"); + } + int number = v.getGraphNodeId(); + if (number == -1) { + return EmptyIterator.instance(); + } + Iterator result = delegateGraph.getPredNodes(v); + for (int i = 0; i < implicitUnaryMap.size(); i++) { + UnaryOperator op = implicitUnaryMap.getKey(i); + IBinaryNaturalRelation R = (IBinaryNaturalRelation) implicitUnaryMap.getValue(i); + IntSet s = R.getRelated(number); + if (s != null) { + result = new CompoundIterator(new ImplicitDefIterator(op, s, v), result); + } + } + + List list = new ArrayList(); + while (result.hasNext()) { + list.add((AbstractStatement) result.next()); + } + return list.iterator(); + } + + /** + * Note that this implementation consults the implicit relation for each and every operator cached. This will be inefficient if + * there are many implicit operators. + * + * @throws IllegalArgumentException if v is null + * + */ + public int getNumberOfStatementsThatUse(PointsToSetVariable v) { + if (v == null) { + throw new IllegalArgumentException("v is null"); + } + int number = v.getGraphNodeId(); + if (number == -1) { + return 0; + } + int result = delegateGraph.getSuccNodeCount(v); + for (Iterator it = invImplicitUnaryMap.keySet().iterator(); it.hasNext();) { + UnaryOperator op = (UnaryOperator) it.next(); + IBinaryNaturalRelation R = invImplicitUnaryMap.get(op); + IntSet s = R.getRelated(number); + if (s != null) { + result += s.size(); + } + } + return result; + } + + public int getNumberOfStatementsThatDef(PointsToSetVariable v) { + if (v == null) { + throw new IllegalArgumentException("v is null"); + } + int number = v.getGraphNodeId(); + if (number == -1) { + return 0; + } + int result = delegateGraph.getPredNodeCount(v); + for (Iterator it = implicitUnaryMap.keySet().iterator(); it.hasNext();) { + UnaryOperator op = (UnaryOperator) it.next(); + IBinaryNaturalRelation R = implicitUnaryMap.get(op); + IntSet s = R.getRelated(number); + if (s != null) { + result += s.size(); + } + } + return result; + } + + @SuppressWarnings("unchecked") + public Iterator getVariables() { + Iterator it = new FilterIterator(delegateGraph.iterator(), new Filter() { + public boolean accepts(Object x) { + return x instanceof IVariable; + } + }); + return it; + } + + /* + * @see com.ibm.wala.util.debug.VerboseAction#performVerboseAction() + */ + public void performVerboseAction() { + if (VERBOSE) { + System.err.println(("stats for " + getClass())); + System.err.println(("number of variables: " + delegateGraph.getVarCount())); + System.err.println(("implicit equations: " + (implicitUnaryCount))); + System.err.println(("explicit equations: " + delegateGraph.getEquationCount())); + System.err.println("implicit map:"); + int count = 0; + int totalBytes = 0; + for (Iterator it = implicitUnaryMap.entrySet().iterator(); it.hasNext();) { + count++; + Map.Entry e = (Map.Entry) it.next(); + IBinaryNaturalRelation R = (IBinaryNaturalRelation) e.getValue(); + System.err.println(("entry " + count)); + R.performVerboseAction(); + HeapTracer.Result result = HeapTracer.traceHeap(Collections.singleton(R), false); + totalBytes += result.getTotalSize(); + } + System.err.println(("bytes in implicit map: " + totalBytes)); + } + } + + public boolean containsStatement(IFixedPointStatement eq) throws IllegalArgumentException { + if (eq == null) { + throw new IllegalArgumentException("eq == null"); + } + if (useImplicitRepresentation(eq)) { + UnaryStatement ueq = (UnaryStatement) eq; + return containsImplicitStatement(ueq); + } else { + return delegateStatements.contains(eq); + } + } + + /** + * @return true iff the graph already contains this equation + */ + private boolean containsImplicitStatement(UnaryStatement eq) { + if (!containsVariable(eq.getLHS())) { + return false; + } + if (!containsVariable(eq.getRightHandSide())) { + return false; + } + int lhs = eq.getLHS().getGraphNodeId(); + int rhs = eq.getRightHandSide().getGraphNodeId(); + UnaryOperator op = eq.getOperator(); + IBinaryNaturalRelation R = implicitUnaryMap.get(op); + if (R != null) { + return R.contains(lhs, rhs); + } else { + return false; + } + } + + public boolean containsVariable(PointsToSetVariable v) { + return delegateGraph.containsNode(v); + } + + public void addStatement(IFixedPointStatement statement) throws IllegalArgumentException, UnimplementedError { + if (statement == null) { + throw new IllegalArgumentException("statement == null"); + } + if (statement instanceof UnaryStatement) { + addStatement((UnaryStatement) statement); + } else if (statement instanceof GeneralStatement) { + addStatement((GeneralStatement) statement); + } else { + Assertions.UNREACHABLE("unexpected: " + statement.getClass()); + } + } + + /** + * A graph of just the variables in the system. v1 -> v2 iff there exists an assignment equation e s.t. e uses v1 and e defs v2. + * + */ + public NumberedGraph getAssignmentGraph() { + return new FilteredConstraintGraphView() { + + @Override + boolean isInteresting(AbstractStatement eq) { + return eq instanceof AssignEquation; + } + }; + } + + /** + * A graph of just the variables in the system. v1 -> v2 iff there exists an Assingnment or Filter equation e s.t. e uses v1 and e + * defs v2. + * + */ + public Graph getFilterAssignmentGraph() { + return new FilteredConstraintGraphView() { + + @Override + boolean isInteresting(AbstractStatement eq) { + return eq instanceof AssignEquation || eq.getOperator() instanceof PropagationCallGraphBuilder.FilterOperator; + } + }; + } + + /** + * NOTE: do not use this method unless you really know what you are doing. Functionality is fragile and may not work in the + * future. + */ + public Graph getFlowGraphIncludingImplicitConstraints() { + return new VariableGraphView(); + } + + /** + * A graph of just the variables in the system. v1 -> v2 that are related by def-use with "interesting" operators + * + */ + private abstract class FilteredConstraintGraphView extends AbstractNumberedGraph { + + abstract boolean isInteresting(AbstractStatement eq); + + /* + * @see com.ibm.wala.util.graph.Graph#removeNodeAndEdges(java.lang.Object) + */ + @Override + public void removeNodeAndEdges(PointsToSetVariable N) { + Assertions.UNREACHABLE(); + } + + /* + * @see com.ibm.wala.util.graph.NodeManager#iterateNodes() + */ + @Override + public Iterator iterator() { + return getVariables(); + } + + /* + * @see com.ibm.wala.util.graph.NodeManager#getNumberOfNodes() + */ + @Override + public int getNumberOfNodes() { + return delegateGraph.getVarCount(); + } + + /* + * @see com.ibm.wala.util.graph.NodeManager#addNode(java.lang.Object) + */ + @Override + public void addNode(PointsToSetVariable n) { + Assertions.UNREACHABLE(); + + } + + /* + * @see com.ibm.wala.util.graph.NodeManager#removeNode(java.lang.Object) + */ + @Override + public void removeNode(PointsToSetVariable n) { + Assertions.UNREACHABLE(); + + } + + /* + * @see com.ibm.wala.util.graph.NodeManager#containsNode(java.lang.Object) + */ + @Override + public boolean containsNode(PointsToSetVariable N) { + Assertions.UNREACHABLE(); + return false; + } + + /* + * @see com.ibm.wala.util.graph.EdgeManager#getPredNodes(java.lang.Object) + */ + @Override + public Iterator getPredNodes(PointsToSetVariable v) { + final Iterator eqs = getStatementsThatDef(v); + return new Iterator() { + PointsToSetVariable nextResult; + { + advance(); + } + + public boolean hasNext() { + return nextResult != null; + } + + public PointsToSetVariable next() { + PointsToSetVariable result = nextResult; + advance(); + return result; + } + + private void advance() { + nextResult = null; + while (eqs.hasNext() && nextResult == null) { + AbstractStatement eq = (AbstractStatement) eqs.next(); + if (isInteresting(eq)) { + nextResult = (PointsToSetVariable) ((UnaryStatement) eq).getRightHandSide(); + } + } + } + + public void remove() { + Assertions.UNREACHABLE(); + } + }; + } + + /* + * @see com.ibm.wala.util.graph.EdgeManager#getPredNodeCount(java.lang.Object) + */ + @Override + public int getPredNodeCount(PointsToSetVariable v) { + int result = 0; + for (Iterator eqs = getStatementsThatDef(v); eqs.hasNext();) { + AbstractStatement eq = (AbstractStatement) eqs.next(); + if (isInteresting(eq)) { + result++; + } + } + return result; + } + + /* + * @see com.ibm.wala.util.graph.EdgeManager#getSuccNodes(java.lang.Object) + */ + @Override + public Iterator getSuccNodes(PointsToSetVariable v) { + final Iterator eqs = getStatementsThatUse(v); + return new Iterator() { + PointsToSetVariable nextResult; + { + advance(); + } + + public boolean hasNext() { + return nextResult != null; + } + + public PointsToSetVariable next() { + PointsToSetVariable result = nextResult; + advance(); + return result; + } + + private void advance() { + nextResult = null; + while (eqs.hasNext() && nextResult == null) { + AbstractStatement eq = (AbstractStatement) eqs.next(); + if (isInteresting(eq)) { + nextResult = (PointsToSetVariable) ((UnaryStatement) eq).getLHS(); + } + } + } + + public void remove() { + // TODO Auto-generated method stub + Assertions.UNREACHABLE(); + } + }; + } + + /* + * @see com.ibm.wala.util.graph.EdgeManager#getSuccNodeCount(java.lang.Object) + */ + @Override + public int getSuccNodeCount(PointsToSetVariable v) { + int result = 0; + for (Iterator eqs = getStatementsThatUse(v); eqs.hasNext();) { + AbstractStatement eq = (AbstractStatement) eqs.next(); + if (isInteresting(eq)) { + result++; + } + } + return result; + } + + /* + * @see com.ibm.wala.util.graph.EdgeManager#addEdge(java.lang.Object, java.lang.Object) + */ + @Override + public void addEdge(PointsToSetVariable src, PointsToSetVariable dst) { + Assertions.UNREACHABLE(); + } + + /* + * @see com.ibm.wala.util.graph.EdgeManager#removeAllIncidentEdges(java.lang.Object) + */ + @Override + public void removeAllIncidentEdges(PointsToSetVariable node) { + Assertions.UNREACHABLE(); + } + + /* + * @see com.ibm.wala.util.graph.AbstractGraph#getNodeManager() + */ + @Override + @SuppressWarnings("unchecked") + protected NumberedNodeManager getNodeManager() { + return nodeManager; + } + + /* + * @see com.ibm.wala.util.graph.AbstractGraph#getEdgeManager() + */ + @Override + protected NumberedEdgeManager getEdgeManager() { + Assertions.UNREACHABLE(); + return null; + } + } + + public String spaceReport() { + StringBuffer result = new StringBuffer("PropagationGraph\n"); + result.append("ImplicitEdges:" + countImplicitEdges() + "\n"); + // for (Iterator it = implicitUnaryMap.values().iterator(); it.hasNext(); ) + // { + // result.append(it.next() + "\n"); + // } + return result.toString(); + } + + private int countImplicitEdges() { + int result = 0; + for (Iterator it = new GlobalImplicitIterator(); it.hasNext();) { + it.next(); + result++; + } + return result; + } + +} diff --git a/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/PropagationSystem.java b/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/PropagationSystem.java index 5642d6dad..80bb74d37 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/PropagationSystem.java +++ b/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/PropagationSystem.java @@ -1,915 +1,915 @@ -/******************************************************************************* - * 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.ipa.callgraph.propagation; - -import java.util.Collection; -import java.util.Collections; -import java.util.HashSet; -import java.util.Iterator; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; -import java.util.Set; - -import com.ibm.wala.classLoader.ArrayClass; -import com.ibm.wala.classLoader.IClass; -import com.ibm.wala.fixedpoint.impl.DefaultFixedPointSolver; -import com.ibm.wala.fixedpoint.impl.Worklist; -import com.ibm.wala.fixpoint.AbstractOperator; -import com.ibm.wala.fixpoint.AbstractStatement; -import com.ibm.wala.fixpoint.IFixedPointSystem; -import com.ibm.wala.fixpoint.IVariable; -import com.ibm.wala.fixpoint.UnaryOperator; -import com.ibm.wala.fixpoint.UnaryStatement; -import com.ibm.wala.ipa.callgraph.CallGraph; -import com.ibm.wala.ipa.callgraph.propagation.PropagationCallGraphBuilder.FilterOperator; -import com.ibm.wala.ipa.cha.ClassHierarchyException; -import com.ibm.wala.ipa.cha.ClassHierarchyWarning; -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.collections.Iterator2Collection; -import com.ibm.wala.util.collections.MapUtil; -import com.ibm.wala.util.debug.Assertions; -import com.ibm.wala.util.debug.VerboseAction; -import com.ibm.wala.util.graph.Graph; -import com.ibm.wala.util.graph.NumberedGraph; -import com.ibm.wala.util.heapTrace.HeapTracer; -import com.ibm.wala.util.intset.IntIterator; -import com.ibm.wala.util.intset.IntSet; -import com.ibm.wala.util.intset.IntSetAction; -import com.ibm.wala.util.intset.IntSetUtil; -import com.ibm.wala.util.intset.MutableIntSet; -import com.ibm.wala.util.intset.MutableMapping; -import com.ibm.wala.util.ref.ReferenceCleanser; -import com.ibm.wala.util.warnings.Warnings; - -/** - * System of constraints that define propagation for call graph construction - */ -public class PropagationSystem extends DefaultFixedPointSolver { - - private final static boolean DEBUG = false; - - private final static boolean DEBUG_MEMORY = false; - - private static int DEBUG_MEM_COUNTER = 0; - - private final static int DEBUG_MEM_INTERVAL = 5; - - /** - * object that tracks points-to sets - */ - protected final PointsToMap pointsToMap = new PointsToMap(); - - /** - * Implementation of the underlying dataflow graph - */ - private final PropagationGraph flowGraph = new PropagationGraph(); - - /** - * bijection from InstanceKey <=>Integer - */ - protected final MutableMapping instanceKeys = MutableMapping.make(); - - /** - * A mapping from IClass -> MutableSharedBitVectorIntSet The range represents the instance keys that correspond to a given class. - * This mapping is used to filter sets based on declared types; e.g., in cast constraints - */ - final private Map class2InstanceKey = HashMapFactory.make(); - - /** - * An abstraction of the pointer analysis result - */ - private PointerAnalysis pointerAnalysis; - - /** - * Meta-data regarding how pointers are modelled. - */ - private final PointerKeyFactory pointerKeyFactory; - - /** - * Meta-data regarding how instances are modelled. - */ - private final InstanceKeyFactory instanceKeyFactory; - - /** - * When doing unification, we must also updated the fixed sets in unary side effects. - * - * This maintains a map from PointsToSetVariable -> Set - */ - final private Map> fixedSetMap = HashMapFactory.make(); - - /** - * Governing call graph; - */ - protected final CallGraph cg; - - private int verboseInterval = DEFAULT_VERBOSE_INTERVAL; - - private int periodicMaintainInterval = DEFAULT_PERIODIC_MAINTENANCE_INTERVAL; - - public PropagationSystem(CallGraph cg, PointerKeyFactory pointerKeyFactory, InstanceKeyFactory instanceKeyFactory) { - if (cg == null) { - throw new IllegalArgumentException("null cg"); - } - this.cg = cg; - this.pointerKeyFactory = pointerKeyFactory; - this.instanceKeyFactory = instanceKeyFactory; - // when doing paranoid checking of points-to sets, code in PointsToSetVariable needs to know about the instance key - // mapping - if (PointsToSetVariable.PARANOID) { - PointsToSetVariable.instanceKeys = instanceKeys; - } - } - - /** - * @return an object which encapsulates the pointer analysis result - */ - public PointerAnalysis makePointerAnalysis(PropagationCallGraphBuilder builder) { - return new PointerAnalysisImpl(builder, cg, pointsToMap, instanceKeys, pointerKeyFactory, instanceKeyFactory); - } - - protected void registerFixedSet(PointsToSetVariable p, UnarySideEffect s) { - Set set = MapUtil.findOrCreateSet(fixedSetMap, p); - set.add(s); - } - - protected void updateSideEffects(PointsToSetVariable p, PointsToSetVariable rep) { - Set set = fixedSetMap.get(p); - if (set != null) { - for (Iterator it = set.iterator(); it.hasNext();) { - UnarySideEffect s = (UnarySideEffect) it.next(); - s.replaceFixedSet(rep); - } - Set s2 = MapUtil.findOrCreateSet(fixedSetMap, rep); - s2.addAll(set); - fixedSetMap.remove(p); - } - } - - /** - * Keep this method private .. this returns the actual backing set for the class, which we do not want to expose to clients. - */ - private MutableIntSet findOrCreateSparseSetForClass(IClass klass) { - assert klass.getReference() != TypeReference.JavaLangObject; - MutableIntSet result = class2InstanceKey.get(klass); - if (result == null) { - result = IntSetUtil.getDefaultIntSetFactory().make(); - class2InstanceKey.put(klass, result); - } - return result; - } - - /** - * @return a set of integers representing the instance keys that correspond to a given class. This method creates a new set, which - * the caller may bash at will. - */ - MutableIntSet cloneInstanceKeysForClass(IClass klass) { - assert klass.getReference() != TypeReference.JavaLangObject; - MutableIntSet set = class2InstanceKey.get(klass); - if (set == null) { - return IntSetUtil.getDefaultIntSetFactory().make(); - } else { - // return a copy. - return IntSetUtil.getDefaultIntSetFactory().makeCopy(set); - } - } - - /** - * @return a set of integers representing the instance keys that correspond to a given class, or null if there are none. - * @throws IllegalArgumentException if klass is null - */ - public IntSet getInstanceKeysForClass(IClass klass) { - if (klass == null) { - throw new IllegalArgumentException("klass is null"); - } - assert klass != klass.getClassHierarchy().getRootClass(); - return class2InstanceKey.get(klass); - } - - /** - * @return the instance key numbered with index i - */ - public InstanceKey getInstanceKey(int i) { - return instanceKeys.getMappedObject(i); - } - - public int getInstanceIndex(InstanceKey ik) { - return instanceKeys.getMappedIndex(ik); - } - - /** - * TODO: optimize; this may be inefficient; - * - * @return an List of instance keys corresponding to the integers in a set - */ - List getInstances(IntSet set) { - LinkedList result = new LinkedList(); - int i = 0; - for (IntIterator it = set.intIterator(); it.hasNext(); i++) { - int j = it.next(); - result.add(getInstanceKey(j)); - } - return result; - } - - @Override - protected void initializeVariables() { - // don't have to do anything; all variables initialized - // by default to TOP (the empty set); - } - - /** - * record that a particular points-to-set is represented implicitly. - */ - public void recordImplicitPointsToSet(PointerKey key) { - if (key == null) { - throw new IllegalArgumentException("null key"); - } - if (key instanceof LocalPointerKey) { - LocalPointerKey lpk = (LocalPointerKey) key; - if (lpk.isParameter()) { - System.err.println(lpk); - System.err.println("Constant? " + lpk.getNode().getIR().getSymbolTable().isConstant(lpk.getValueNumber())); - System.err.println(lpk.getNode().getIR()); - Assertions.UNREACHABLE("How can parameter be implicit?"); - } - } - pointsToMap.recordImplicit(key); - } - - /** - * If key is unified, returns the representative - * - * @param key - * @return the dataflow variable that tracks the points-to set for key - */ - public PointsToSetVariable findOrCreatePointsToSet(PointerKey key) { - - if (key == null) { - throw new IllegalArgumentException("null key"); - } - - if (pointsToMap.isImplicit(key)) { - System.err.println("Did not expect to findOrCreatePointsToSet for implicitly represented PointerKey"); - System.err.println(key); - Assertions.UNREACHABLE(); - } - PointsToSetVariable result = pointsToMap.getPointsToSet(key); - if (result == null) { - result = new PointsToSetVariable(key); - pointsToMap.put(key, result); - } else { - // check that the filter for this variable remains unique - if (!pointsToMap.isUnified(key) && key instanceof FilteredPointerKey) { - PointerKey pk = result.getPointerKey(); - if (!(pk instanceof FilteredPointerKey)) { - // add a filter for all future evaluations. - // this is tricky, but the logic is OK .. any constraints that need - // the filter will see it ... - // CALLERS MUST BE EXTRA CAREFUL WHEN DEALING WITH UNIFICATION! - result.setPointerKey(key); - pk = key; - } - FilteredPointerKey fpk = (FilteredPointerKey) pk; - if (fpk == null) { - Assertions.UNREACHABLE("fpk is null"); - } - if (key == null) { - Assertions.UNREACHABLE("key is null"); - } - if (fpk.getTypeFilter() == null) { - Assertions.UNREACHABLE("fpk.getTypeFilter() is null"); - } - if (!fpk.getTypeFilter().equals(((FilteredPointerKey) key).getTypeFilter())) { - Assertions.UNREACHABLE("Cannot use filter " + ((FilteredPointerKey) key).getTypeFilter() + " for " + key - + ": previously created different filter " + fpk.getTypeFilter()); - } - } - } - return result; - } - - public int findOrCreateIndexForInstanceKey(InstanceKey key) { - int result = instanceKeys.getMappedIndex(key); - if (result == -1) { - result = instanceKeys.add(key); - } - if (DEBUG) { - System.err.println("getIndexForInstanceKey " + key + " " + result); - } - return result; - } - - /** - * NB: this is idempotent ... if the given constraint exists, it will not be added to the system; however, this will be more - * expensive since it must check if the constraint pre-exits. - * - * @return true iff the system changes - */ - public boolean newConstraint(PointerKey lhs, UnaryOperator op, PointerKey rhs) { - if (lhs == null) { - throw new IllegalArgumentException("null lhs"); - } - if (op == null) { - throw new IllegalArgumentException("op null"); - } - if (rhs == null) { - throw new IllegalArgumentException("rhs null"); - } - if (DEBUG) { - System.err.println("Add constraint A: " + lhs + " " + op + " " + rhs); - } - PointsToSetVariable L = findOrCreatePointsToSet(lhs); - PointsToSetVariable R = findOrCreatePointsToSet(rhs); - if (op instanceof FilterOperator) { - // we do not want to revert the lhs to pre-transitive form; - // we instead want to check in the outer loop of the pre-transitive - // solver if the value of L changes. - pointsToMap.recordTransitiveRoot(L.getPointerKey()); - if (!(L.getPointerKey() instanceof FilteredPointerKey)) { - Assertions.UNREACHABLE("expected filtered lhs " + L.getPointerKey() + " " + L.getPointerKey().getClass() + " " + lhs + " " - + lhs.getClass()); - } - } - return newStatement(L, op, R, true, true); - } - - public boolean newConstraint(PointerKey lhs, AbstractOperator op, PointerKey rhs) { - if (lhs == null) { - throw new IllegalArgumentException("lhs null"); - } - if (op == null) { - throw new IllegalArgumentException("op null"); - } - if (rhs == null) { - throw new IllegalArgumentException("rhs null"); - } - if (DEBUG) { - System.err.println("Add constraint A: " + lhs + " " + op + " " + rhs); - } - assert !pointsToMap.isUnified(lhs); - assert !pointsToMap.isUnified(rhs); - PointsToSetVariable L = findOrCreatePointsToSet(lhs); - PointsToSetVariable R = findOrCreatePointsToSet(rhs); - return newStatement(L, op, new PointsToSetVariable[] { R }, true, true); - } - - public boolean newConstraint(PointerKey lhs, AbstractOperator op, PointerKey rhs1, PointerKey rhs2) { - if (lhs == null) { - throw new IllegalArgumentException("null lhs"); - } - if (op == null) { - throw new IllegalArgumentException("null op"); - } - if (rhs1 == null) { - throw new IllegalArgumentException("null rhs1"); - } - if (rhs2 == null) { - throw new IllegalArgumentException("null rhs2"); - } - if (DEBUG) { - System.err.println("Add constraint A: " + lhs + " " + op + " " + rhs1 + ", " + rhs2); - } - assert !pointsToMap.isUnified(lhs); - assert !pointsToMap.isUnified(rhs1); - assert !pointsToMap.isUnified(rhs2); - PointsToSetVariable L = findOrCreatePointsToSet(lhs); - PointsToSetVariable R1 = findOrCreatePointsToSet(rhs1); - PointsToSetVariable R2 = findOrCreatePointsToSet(rhs2); - return newStatement(L, op, R1, R2, true, true); - } - - /** - * @return true iff the system changes - */ - public boolean newFieldWrite(PointerKey lhs, UnaryOperator op, PointerKey rhs, PointerKey container) { - return newConstraint(lhs, op, rhs); - } - - /** - * @return true iff the system changes - */ - public boolean newFieldRead(PointerKey lhs, UnaryOperator op, PointerKey rhs, PointerKey container) { - return newConstraint(lhs, op, rhs); - } - - /** - * @return true iff the system changes - */ - public boolean newConstraint(PointerKey lhs, InstanceKey value) { - if (DEBUG) { - System.err.println("Add constraint B: " + lhs + " U= " + value); - } - pointsToMap.recordTransitiveRoot(lhs); - - // we don't actually add a constraint. - // instead, we immediately add the value to the points-to set. - // This works since the solver is monotonic with TOP = {} - PointsToSetVariable L = findOrCreatePointsToSet(lhs); - int index = findOrCreateIndexForInstanceKey(value); - if (L.contains(index)) { - // a no-op - return false; - } else { - L.add(index); - - // also register that we have an instanceKey for the klass - assert value.getConcreteType() != null; - - if (!value.getConcreteType().getReference().equals(TypeReference.JavaLangObject)) { - registerInstanceOfClass(value.getConcreteType(), index); - } - - // we'd better update the worklist appropriately - // if graphNodeId == -1, then there are no equations that use this - // variable. - if (L.getGraphNodeId() > -1) { - changedVariable(L); - } - return true; - } - - } - - /** - * Record that we have a new instanceKey for a given declared type. - */ - private void registerInstanceOfClass(IClass klass, int index) { - - if (DEBUG) { - System.err.println("registerInstanceOfClass " + klass + " " + index); - } - - assert !klass.getReference().equals(TypeReference.JavaLangObject); - - try { - IClass T = klass; - registerInstanceWithAllSuperclasses(index, T); - registerInstanceWithAllInterfaces(klass, index); - - if (klass.isArrayClass()) { - ArrayClass aClass = (ArrayClass) klass; - int dim = aClass.getDimensionality(); - registerMultiDimArraysForArrayOfObjectTypes(dim, index, aClass); - - IClass elementClass = aClass.getInnermostElementClass(); - if (elementClass != null) { - registerArrayInstanceWithAllSuperclassesOfElement(index, elementClass, dim); - registerArrayInstanceWithAllInterfacesOfElement(index, elementClass, dim); - } - } - } catch (ClassHierarchyException e) { - Warnings.add(ClassHierarchyWarning.create(e.getMessage())); - } - } - - private int registerMultiDimArraysForArrayOfObjectTypes(int dim, int index, ArrayClass aClass) { - - for (int i = 1; i < dim; i++) { - TypeReference jlo = makeArray(TypeReference.JavaLangObject, i); - IClass jloClass = null; - jloClass = aClass.getClassLoader().lookupClass(jlo.getName()); - MutableIntSet set = findOrCreateSparseSetForClass(jloClass); - set.add(index); - } - return dim; - } - - private void registerArrayInstanceWithAllInterfacesOfElement(int index, IClass elementClass, int dim) { - Collection ifaces = null; - ifaces = elementClass.getAllImplementedInterfaces(); - for (Iterator it = ifaces.iterator(); it.hasNext();) { - IClass I = (IClass) it.next(); - TypeReference iArrayRef = makeArray(I.getReference(), dim); - IClass iArrayClass = null; - iArrayClass = I.getClassLoader().lookupClass(iArrayRef.getName()); - MutableIntSet set = findOrCreateSparseSetForClass(iArrayClass); - set.add(index); - if (DEBUG) { - System.err.println("dense filter for interface " + iArrayClass + " " + set); - } - } - } - - private TypeReference makeArray(TypeReference element, int dim) { - TypeReference iArrayRef = element; - for (int i = 0; i < dim; i++) { - iArrayRef = TypeReference.findOrCreateArrayOf(iArrayRef); - } - return iArrayRef; - } - - private void registerArrayInstanceWithAllSuperclassesOfElement(int index, IClass elementClass, int dim) - throws ClassHierarchyException { - IClass T; - // register the array with each supertype of the element class - T = elementClass.getSuperclass(); - while (T != null) { - TypeReference tArrayRef = makeArray(T.getReference(), dim); - IClass tArrayClass = null; - tArrayClass = T.getClassLoader().lookupClass(tArrayRef.getName()); - MutableIntSet set = findOrCreateSparseSetForClass(tArrayClass); - set.add(index); - if (DEBUG) { - System.err.println("dense filter for class " + tArrayClass + " " + set); - } - T = T.getSuperclass(); - } - } - - /** - * @param klass - * @param index - * @throws ClassHierarchyException - */ - private void registerInstanceWithAllInterfaces(IClass klass, int index) throws ClassHierarchyException { - Collection ifaces = klass.getAllImplementedInterfaces(); - for (Iterator it = ifaces.iterator(); it.hasNext();) { - IClass I = (IClass) it.next(); - MutableIntSet set = findOrCreateSparseSetForClass(I); - set.add(index); - if (DEBUG) { - System.err.println("dense filter for interface " + I + " " + set); - } - } - } - - /** - * @param index - * @param T - * @throws ClassHierarchyException - */ - private void registerInstanceWithAllSuperclasses(int index, IClass T) throws ClassHierarchyException { - while (T != null && !T.getReference().equals(TypeReference.JavaLangObject)) { - MutableIntSet set = findOrCreateSparseSetForClass(T); - set.add(index); - if (DEBUG) { - System.err.println("dense filter for class " + T + " " + set); - } - T = T.getSuperclass(); - } - } - - public void newSideEffect(UnaryOperator op, PointerKey arg0) { - if (arg0 == null) { - throw new IllegalArgumentException("null arg0"); - } - if (DEBUG) { - System.err.println("add constraint D: " + op + " " + arg0); - } - assert !pointsToMap.isUnified(arg0); - PointsToSetVariable v1 = findOrCreatePointsToSet(arg0); - newStatement(null, op, v1, true, true); - } - - public void newSideEffect(AbstractOperator op, PointerKey[] arg0) { - if (arg0 == null) { - throw new IllegalArgumentException("null arg0"); - } - if (DEBUG) { - System.err.println("add constraint D: " + op + " " + arg0); - } - PointsToSetVariable[] vs = new PointsToSetVariable[ arg0.length ]; - for(int i = 0; i < arg0.length; i++) { - assert !pointsToMap.isUnified(arg0[i]); - vs[i] = findOrCreatePointsToSet(arg0[i]); - } - newStatement(null, op, vs, true, true); - } - - public void newSideEffect(AbstractOperator op, PointerKey arg0, PointerKey arg1) { - if (DEBUG) { - System.err.println("add constraint D: " + op + " " + arg0); - } - assert !pointsToMap.isUnified(arg0); - assert !pointsToMap.isUnified(arg1); - PointsToSetVariable v1 = findOrCreatePointsToSet(arg0); - PointsToSetVariable v2 = findOrCreatePointsToSet(arg1); - newStatement(null, op, v1, v2, true, true); - } - - @Override - protected void initializeWorkList() { - addAllStatementsToWorkList(); - } - - /** - * @return an object that encapsulates the pointer analysis results - */ - public PointerAnalysis extractPointerAnalysis(PropagationCallGraphBuilder builder) { - if (pointerAnalysis == null) { - pointerAnalysis = makePointerAnalysis(builder); - } - return pointerAnalysis; - } - - @Override - public void performVerboseAction() { - super.performVerboseAction(); - if (DEBUG_MEMORY) { - DEBUG_MEM_COUNTER++; - if (DEBUG_MEM_COUNTER % DEBUG_MEM_INTERVAL == 0) { - DEBUG_MEM_COUNTER = 0; - ReferenceCleanser.clearSoftCaches(); - - System.err.println(flowGraph.spaceReport()); - - System.err.println("Analyze leaks.."); - HeapTracer.traceHeap(Collections.singleton(this), true); - System.err.println("done analyzing leaks"); - } - } - if (getFixedPointSystem() instanceof VerboseAction) { - ((VerboseAction) getFixedPointSystem()).performVerboseAction(); - } - AbstractStatement s = workList.takeStatement(); - System.err.println(printRHSInstances(s)); - workList.insertStatement(s); - System.err.println("CGNodes: " + cg.getNumberOfNodes()); - - } - - private String printRHSInstances(AbstractStatement s) { - if (s instanceof UnaryStatement) { - UnaryStatement u = (UnaryStatement) s; - PointsToSetVariable rhs = (PointsToSetVariable) u.getRightHandSide(); - IntSet value = rhs.getValue(); - final int[] topFive = new int[5]; - value.foreach(new IntSetAction() { - public void act(int x) { - for (int i = 0; i < 4; i++) { - topFive[i] = topFive[i + 1]; - } - topFive[4] = x; - } - }); - StringBuffer result = new StringBuffer(); - for (int i = 0; i < 5; i++) { - int p = topFive[i]; - if (p != 0) { - InstanceKey ik = getInstanceKey(p); - result.append(p).append(" ").append(ik).append("\n"); - } - } - return result.toString(); - } else { - return s.getClass().toString(); - } - } - - @Override - public IFixedPointSystem getFixedPointSystem() { - return flowGraph; - } - - /* - * @see com.ibm.wala.ipa.callgraph.propagation.HeapModel#iteratePointerKeys() - */ - public Iterator iteratePointerKeys() { - return pointsToMap.iterateKeys(); - } - - /** - * warning: this is _real_ slow; don't use it anywhere performance critical - */ - public int getNumberOfPointerKeys() { - return pointsToMap.getNumberOfPointerKeys(); - } - - /** - * Use with care. - */ - Worklist getWorklist() { - return workList; - } - - public Iterator getStatementsThatUse(PointsToSetVariable v) { - return flowGraph.getStatementsThatUse(v); - } - - public Iterator getStatementsThatDef(PointsToSetVariable v) { - return flowGraph.getStatementsThatDef(v); - } - - public NumberedGraph getAssignmentGraph() { - return flowGraph.getAssignmentGraph(); - } - - public Graph getFilterAsssignmentGraph() { - return flowGraph.getFilterAssignmentGraph(); - } - - /** - * NOTE: do not use this method unless you really know what you are doing. Functionality is fragile and may not work in the - * future. - */ - public Graph getFlowGraphIncludingImplicitConstraints() { - return flowGraph.getFlowGraphIncludingImplicitConstraints(); - } - - /** - * - */ - public void revertToPreTransitive() { - pointsToMap.revertToPreTransitive(); - } - - public Iterator getTransitiveRoots() { - return pointsToMap.getTransitiveRoots(); - } - - public boolean isTransitiveRoot(PointerKey key) { - return pointsToMap.isTransitiveRoot(key); - } - - @Override - protected void periodicMaintenance() { - super.periodicMaintenance(); - ReferenceCleanser.clearSoftCaches(); - } - - @Override - public int getVerboseInterval() { - return verboseInterval; - } - - /** - * @param verboseInterval The verboseInterval to set. - */ - public void setVerboseInterval(int verboseInterval) { - this.verboseInterval = verboseInterval; - } - - @Override - public int getPeriodicMaintainInterval() { - return periodicMaintainInterval; - } - - /** - * @param periodicMaintainInteval - */ - public void setPeriodicMaintainInterval(int periodicMaintainInteval) { - this.periodicMaintainInterval = periodicMaintainInteval; - } - - /** - * Unify the points-to-sets for the variables identified by the set s - * - * @param s numbers of points-to-set variables - * @throws IllegalArgumentException if s is null - */ - public void unify(IntSet s) { - if (s == null) { - throw new IllegalArgumentException("s is null"); - } - // cache the variables represented - HashSet cache = HashSetFactory.make(s.size()); - for (IntIterator it = s.intIterator(); it.hasNext();) { - int i = it.next(); - cache.add(pointsToMap.getPointsToSet(i)); - } - - // unify the variables - pointsToMap.unify(s); - int rep = pointsToMap.getRepresentative(s.intIterator().next()); - - // clean up the equations - updateEquationsForUnification(cache, rep); - - // special logic to clean up side effects - updateSideEffectsForUnification(cache, rep); - } - - /** - * Update side effect after unification - * - * @param s set of PointsToSetVariables that have been unified - * @param rep number of the representative variable for the unified set. - */ - private void updateSideEffectsForUnification(HashSet s, int rep) { - PointsToSetVariable pRef = pointsToMap.getPointsToSet(rep); - for (Iterator it = s.iterator(); it.hasNext();) { - PointsToSetVariable p = it.next(); - updateSideEffects(p, pRef); - } - } - - /** - * Update equation def/uses after unification - * - * @param s set of PointsToSetVariables that have been unified - * @param rep number of the representative variable for the unified set. - */ - @SuppressWarnings("unchecked") - private void updateEquationsForUnification(HashSet s, int rep) { - PointsToSetVariable pRef = pointsToMap.getPointsToSet(rep); - for (Iterator it = s.iterator(); it.hasNext();) { - PointsToSetVariable p = it.next(); - - if (p != pRef) { - // pRef is the representative for p. - // be careful: cache the defs before mucking with the underlying system - for (Iterator d = Iterator2Collection.toSet(getStatementsThatDef(p)).iterator(); d.hasNext();) { - AbstractStatement as = (AbstractStatement) d.next(); - - if (as instanceof AssignEquation) { - AssignEquation assign = (AssignEquation) as; - PointsToSetVariable rhs = assign.getRightHandSide(); - int rhsRep = pointsToMap.getRepresentative(pointsToMap.getIndex(rhs.getPointerKey())); - if (rhsRep == rep) { - flowGraph.removeStatement(as); - } else { - replaceLHS(pRef, p, as); - } - } else { - replaceLHS(pRef, p, as); - } - } - // be careful: cache the defs before mucking with the underlying system - for (Iterator u = Iterator2Collection.toSet(getStatementsThatUse(p)).iterator(); u.hasNext();) { - AbstractStatement as = (AbstractStatement) u.next(); - if (as instanceof AssignEquation) { - AssignEquation assign = (AssignEquation) as; - PointsToSetVariable lhs = assign.getLHS(); - int lhsRep = pointsToMap.getRepresentative(pointsToMap.getIndex(lhs.getPointerKey())); - if (lhsRep == rep) { - flowGraph.removeStatement(as); - } else { - replaceRHS(pRef, p, as); - } - } else { - replaceRHS(pRef, p, as); - } - } - if (flowGraph.getNumberOfStatementsThatDef(p) == 0 && flowGraph.getNumberOfStatementsThatUse(p) == 0) { - flowGraph.removeVariable(p); - } - } - } - } - - /** - * replace all occurrences of p on the rhs of a statement with pRef - * - * @param as a statement that uses p in it's right-hand side - */ - private void replaceRHS(PointsToSetVariable pRef, PointsToSetVariable p, - AbstractStatement> as) { - if (as instanceof UnaryStatement) { - assert ((UnaryStatement) as).getRightHandSide() == p; - newStatement(as.getLHS(), (UnaryOperator) as.getOperator(), pRef, false, false); - } else { - IVariable[] rhs = as.getRHS(); - PointsToSetVariable[] newRHS = new PointsToSetVariable[rhs.length]; - for (int i = 0; i < rhs.length; i++) { - if (rhs[i].equals(p)) { - newRHS[i] = pRef; - } else { - newRHS[i] = (PointsToSetVariable) rhs[i]; - } - } - newStatement(as.getLHS(), as.getOperator(), newRHS, false, false); - } - flowGraph.removeStatement(as); - } - - /** - * replace all occurences of p on the lhs of a statement with pRef - * - * @param as a statement that defs p - */ - private void replaceLHS(PointsToSetVariable pRef, PointsToSetVariable p, - AbstractStatement> as) { - assert as.getLHS() == p; - if (as instanceof UnaryStatement) { - newStatement(pRef, (UnaryOperator) as.getOperator(), (PointsToSetVariable) ((UnaryStatement) as) - .getRightHandSide(), false, false); - } else { - newStatement(pRef, as.getOperator(), as.getRHS(), false, false); - } - flowGraph.removeStatement(as); - } - - public boolean isUnified(PointerKey result) { - return pointsToMap.isUnified(result); - } - - public int getNumber(PointerKey p) { - return pointsToMap.getIndex(p); - } - - @Override - protected PointsToSetVariable[] makeStmtRHS(int size) { - return new PointsToSetVariable[size]; - } -} +/******************************************************************************* + * 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.ipa.callgraph.propagation; + +import java.util.Collection; +import java.util.Collections; +import java.util.HashSet; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import com.ibm.wala.classLoader.ArrayClass; +import com.ibm.wala.classLoader.IClass; +import com.ibm.wala.fixedpoint.impl.DefaultFixedPointSolver; +import com.ibm.wala.fixedpoint.impl.Worklist; +import com.ibm.wala.fixpoint.AbstractOperator; +import com.ibm.wala.fixpoint.AbstractStatement; +import com.ibm.wala.fixpoint.IFixedPointSystem; +import com.ibm.wala.fixpoint.IVariable; +import com.ibm.wala.fixpoint.UnaryOperator; +import com.ibm.wala.fixpoint.UnaryStatement; +import com.ibm.wala.ipa.callgraph.CallGraph; +import com.ibm.wala.ipa.callgraph.propagation.PropagationCallGraphBuilder.FilterOperator; +import com.ibm.wala.ipa.cha.ClassHierarchyException; +import com.ibm.wala.ipa.cha.ClassHierarchyWarning; +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.collections.Iterator2Collection; +import com.ibm.wala.util.collections.MapUtil; +import com.ibm.wala.util.debug.Assertions; +import com.ibm.wala.util.debug.VerboseAction; +import com.ibm.wala.util.graph.Graph; +import com.ibm.wala.util.graph.NumberedGraph; +import com.ibm.wala.util.heapTrace.HeapTracer; +import com.ibm.wala.util.intset.IntIterator; +import com.ibm.wala.util.intset.IntSet; +import com.ibm.wala.util.intset.IntSetAction; +import com.ibm.wala.util.intset.IntSetUtil; +import com.ibm.wala.util.intset.MutableIntSet; +import com.ibm.wala.util.intset.MutableMapping; +import com.ibm.wala.util.ref.ReferenceCleanser; +import com.ibm.wala.util.warnings.Warnings; + +/** + * System of constraints that define propagation for call graph construction + */ +public class PropagationSystem extends DefaultFixedPointSolver { + + private final static boolean DEBUG = false; + + private final static boolean DEBUG_MEMORY = false; + + private static int DEBUG_MEM_COUNTER = 0; + + private final static int DEBUG_MEM_INTERVAL = 5; + + /** + * object that tracks points-to sets + */ + protected final PointsToMap pointsToMap = new PointsToMap(); + + /** + * Implementation of the underlying dataflow graph + */ + private final PropagationGraph flowGraph = new PropagationGraph(); + + /** + * bijection from InstanceKey <=>Integer + */ + protected final MutableMapping instanceKeys = MutableMapping.make(); + + /** + * A mapping from IClass -> MutableSharedBitVectorIntSet The range represents the instance keys that correspond to a given class. + * This mapping is used to filter sets based on declared types; e.g., in cast constraints + */ + final private Map class2InstanceKey = HashMapFactory.make(); + + /** + * An abstraction of the pointer analysis result + */ + private PointerAnalysis pointerAnalysis; + + /** + * Meta-data regarding how pointers are modelled. + */ + private final PointerKeyFactory pointerKeyFactory; + + /** + * Meta-data regarding how instances are modelled. + */ + private final InstanceKeyFactory instanceKeyFactory; + + /** + * When doing unification, we must also updated the fixed sets in unary side effects. + * + * This maintains a map from PointsToSetVariable -> Set + */ + final private Map> fixedSetMap = HashMapFactory.make(); + + /** + * Governing call graph; + */ + protected final CallGraph cg; + + private int verboseInterval = DEFAULT_VERBOSE_INTERVAL; + + private int periodicMaintainInterval = DEFAULT_PERIODIC_MAINTENANCE_INTERVAL; + + public PropagationSystem(CallGraph cg, PointerKeyFactory pointerKeyFactory, InstanceKeyFactory instanceKeyFactory) { + if (cg == null) { + throw new IllegalArgumentException("null cg"); + } + this.cg = cg; + this.pointerKeyFactory = pointerKeyFactory; + this.instanceKeyFactory = instanceKeyFactory; + // when doing paranoid checking of points-to sets, code in PointsToSetVariable needs to know about the instance key + // mapping + if (PointsToSetVariable.PARANOID) { + PointsToSetVariable.instanceKeys = instanceKeys; + } + } + + /** + * @return an object which encapsulates the pointer analysis result + */ + public PointerAnalysis makePointerAnalysis(PropagationCallGraphBuilder builder) { + return new PointerAnalysisImpl(builder, cg, pointsToMap, instanceKeys, pointerKeyFactory, instanceKeyFactory); + } + + protected void registerFixedSet(PointsToSetVariable p, UnarySideEffect s) { + Set set = MapUtil.findOrCreateSet(fixedSetMap, p); + set.add(s); + } + + protected void updateSideEffects(PointsToSetVariable p, PointsToSetVariable rep) { + Set set = fixedSetMap.get(p); + if (set != null) { + for (Iterator it = set.iterator(); it.hasNext();) { + UnarySideEffect s = (UnarySideEffect) it.next(); + s.replaceFixedSet(rep); + } + Set s2 = MapUtil.findOrCreateSet(fixedSetMap, rep); + s2.addAll(set); + fixedSetMap.remove(p); + } + } + + /** + * Keep this method private .. this returns the actual backing set for the class, which we do not want to expose to clients. + */ + private MutableIntSet findOrCreateSparseSetForClass(IClass klass) { + assert klass.getReference() != TypeReference.JavaLangObject; + MutableIntSet result = class2InstanceKey.get(klass); + if (result == null) { + result = IntSetUtil.getDefaultIntSetFactory().make(); + class2InstanceKey.put(klass, result); + } + return result; + } + + /** + * @return a set of integers representing the instance keys that correspond to a given class. This method creates a new set, which + * the caller may bash at will. + */ + MutableIntSet cloneInstanceKeysForClass(IClass klass) { + assert klass.getReference() != TypeReference.JavaLangObject; + MutableIntSet set = class2InstanceKey.get(klass); + if (set == null) { + return IntSetUtil.getDefaultIntSetFactory().make(); + } else { + // return a copy. + return IntSetUtil.getDefaultIntSetFactory().makeCopy(set); + } + } + + /** + * @return a set of integers representing the instance keys that correspond to a given class, or null if there are none. + * @throws IllegalArgumentException if klass is null + */ + public IntSet getInstanceKeysForClass(IClass klass) { + if (klass == null) { + throw new IllegalArgumentException("klass is null"); + } + assert klass != klass.getClassHierarchy().getRootClass(); + return class2InstanceKey.get(klass); + } + + /** + * @return the instance key numbered with index i + */ + public InstanceKey getInstanceKey(int i) { + return instanceKeys.getMappedObject(i); + } + + public int getInstanceIndex(InstanceKey ik) { + return instanceKeys.getMappedIndex(ik); + } + + /** + * TODO: optimize; this may be inefficient; + * + * @return an List of instance keys corresponding to the integers in a set + */ + List getInstances(IntSet set) { + LinkedList result = new LinkedList(); + int i = 0; + for (IntIterator it = set.intIterator(); it.hasNext(); i++) { + int j = it.next(); + result.add(getInstanceKey(j)); + } + return result; + } + + @Override + protected void initializeVariables() { + // don't have to do anything; all variables initialized + // by default to TOP (the empty set); + } + + /** + * record that a particular points-to-set is represented implicitly. + */ + public void recordImplicitPointsToSet(PointerKey key) { + if (key == null) { + throw new IllegalArgumentException("null key"); + } + if (key instanceof LocalPointerKey) { + LocalPointerKey lpk = (LocalPointerKey) key; + if (lpk.isParameter()) { + System.err.println(lpk); + System.err.println("Constant? " + lpk.getNode().getIR().getSymbolTable().isConstant(lpk.getValueNumber())); + System.err.println(lpk.getNode().getIR()); + Assertions.UNREACHABLE("How can parameter be implicit?"); + } + } + pointsToMap.recordImplicit(key); + } + + /** + * If key is unified, returns the representative + * + * @param key + * @return the dataflow variable that tracks the points-to set for key + */ + public PointsToSetVariable findOrCreatePointsToSet(PointerKey key) { + + if (key == null) { + throw new IllegalArgumentException("null key"); + } + + if (pointsToMap.isImplicit(key)) { + System.err.println("Did not expect to findOrCreatePointsToSet for implicitly represented PointerKey"); + System.err.println(key); + Assertions.UNREACHABLE(); + } + PointsToSetVariable result = pointsToMap.getPointsToSet(key); + if (result == null) { + result = new PointsToSetVariable(key); + pointsToMap.put(key, result); + } else { + // check that the filter for this variable remains unique + if (!pointsToMap.isUnified(key) && key instanceof FilteredPointerKey) { + PointerKey pk = result.getPointerKey(); + if (!(pk instanceof FilteredPointerKey)) { + // add a filter for all future evaluations. + // this is tricky, but the logic is OK .. any constraints that need + // the filter will see it ... + // CALLERS MUST BE EXTRA CAREFUL WHEN DEALING WITH UNIFICATION! + result.setPointerKey(key); + pk = key; + } + FilteredPointerKey fpk = (FilteredPointerKey) pk; + if (fpk == null) { + Assertions.UNREACHABLE("fpk is null"); + } + if (key == null) { + Assertions.UNREACHABLE("key is null"); + } + if (fpk.getTypeFilter() == null) { + Assertions.UNREACHABLE("fpk.getTypeFilter() is null"); + } + if (!fpk.getTypeFilter().equals(((FilteredPointerKey) key).getTypeFilter())) { + Assertions.UNREACHABLE("Cannot use filter " + ((FilteredPointerKey) key).getTypeFilter() + " for " + key + + ": previously created different filter " + fpk.getTypeFilter()); + } + } + } + return result; + } + + public int findOrCreateIndexForInstanceKey(InstanceKey key) { + int result = instanceKeys.getMappedIndex(key); + if (result == -1) { + result = instanceKeys.add(key); + } + if (DEBUG) { + System.err.println("getIndexForInstanceKey " + key + " " + result); + } + return result; + } + + /** + * NB: this is idempotent ... if the given constraint exists, it will not be added to the system; however, this will be more + * expensive since it must check if the constraint pre-exits. + * + * @return true iff the system changes + */ + public boolean newConstraint(PointerKey lhs, UnaryOperator op, PointerKey rhs) { + if (lhs == null) { + throw new IllegalArgumentException("null lhs"); + } + if (op == null) { + throw new IllegalArgumentException("op null"); + } + if (rhs == null) { + throw new IllegalArgumentException("rhs null"); + } + if (DEBUG) { + System.err.println("Add constraint A: " + lhs + " " + op + " " + rhs); + } + PointsToSetVariable L = findOrCreatePointsToSet(lhs); + PointsToSetVariable R = findOrCreatePointsToSet(rhs); + if (op instanceof FilterOperator) { + // we do not want to revert the lhs to pre-transitive form; + // we instead want to check in the outer loop of the pre-transitive + // solver if the value of L changes. + pointsToMap.recordTransitiveRoot(L.getPointerKey()); + if (!(L.getPointerKey() instanceof FilteredPointerKey)) { + Assertions.UNREACHABLE("expected filtered lhs " + L.getPointerKey() + " " + L.getPointerKey().getClass() + " " + lhs + " " + + lhs.getClass()); + } + } + return newStatement(L, op, R, true, true); + } + + public boolean newConstraint(PointerKey lhs, AbstractOperator op, PointerKey rhs) { + if (lhs == null) { + throw new IllegalArgumentException("lhs null"); + } + if (op == null) { + throw new IllegalArgumentException("op null"); + } + if (rhs == null) { + throw new IllegalArgumentException("rhs null"); + } + if (DEBUG) { + System.err.println("Add constraint A: " + lhs + " " + op + " " + rhs); + } + assert !pointsToMap.isUnified(lhs); + assert !pointsToMap.isUnified(rhs); + PointsToSetVariable L = findOrCreatePointsToSet(lhs); + PointsToSetVariable R = findOrCreatePointsToSet(rhs); + return newStatement(L, op, new PointsToSetVariable[] { R }, true, true); + } + + public boolean newConstraint(PointerKey lhs, AbstractOperator op, PointerKey rhs1, PointerKey rhs2) { + if (lhs == null) { + throw new IllegalArgumentException("null lhs"); + } + if (op == null) { + throw new IllegalArgumentException("null op"); + } + if (rhs1 == null) { + throw new IllegalArgumentException("null rhs1"); + } + if (rhs2 == null) { + throw new IllegalArgumentException("null rhs2"); + } + if (DEBUG) { + System.err.println("Add constraint A: " + lhs + " " + op + " " + rhs1 + ", " + rhs2); + } + assert !pointsToMap.isUnified(lhs); + assert !pointsToMap.isUnified(rhs1); + assert !pointsToMap.isUnified(rhs2); + PointsToSetVariable L = findOrCreatePointsToSet(lhs); + PointsToSetVariable R1 = findOrCreatePointsToSet(rhs1); + PointsToSetVariable R2 = findOrCreatePointsToSet(rhs2); + return newStatement(L, op, R1, R2, true, true); + } + + /** + * @return true iff the system changes + */ + public boolean newFieldWrite(PointerKey lhs, UnaryOperator op, PointerKey rhs, PointerKey container) { + return newConstraint(lhs, op, rhs); + } + + /** + * @return true iff the system changes + */ + public boolean newFieldRead(PointerKey lhs, UnaryOperator op, PointerKey rhs, PointerKey container) { + return newConstraint(lhs, op, rhs); + } + + /** + * @return true iff the system changes + */ + public boolean newConstraint(PointerKey lhs, InstanceKey value) { + if (DEBUG) { + System.err.println("Add constraint B: " + lhs + " U= " + value); + } + pointsToMap.recordTransitiveRoot(lhs); + + // we don't actually add a constraint. + // instead, we immediately add the value to the points-to set. + // This works since the solver is monotonic with TOP = {} + PointsToSetVariable L = findOrCreatePointsToSet(lhs); + int index = findOrCreateIndexForInstanceKey(value); + if (L.contains(index)) { + // a no-op + return false; + } else { + L.add(index); + + // also register that we have an instanceKey for the klass + assert value.getConcreteType() != null; + + if (!value.getConcreteType().getReference().equals(TypeReference.JavaLangObject)) { + registerInstanceOfClass(value.getConcreteType(), index); + } + + // we'd better update the worklist appropriately + // if graphNodeId == -1, then there are no equations that use this + // variable. + if (L.getGraphNodeId() > -1) { + changedVariable(L); + } + return true; + } + + } + + /** + * Record that we have a new instanceKey for a given declared type. + */ + private void registerInstanceOfClass(IClass klass, int index) { + + if (DEBUG) { + System.err.println("registerInstanceOfClass " + klass + " " + index); + } + + assert !klass.getReference().equals(TypeReference.JavaLangObject); + + try { + IClass T = klass; + registerInstanceWithAllSuperclasses(index, T); + registerInstanceWithAllInterfaces(klass, index); + + if (klass.isArrayClass()) { + ArrayClass aClass = (ArrayClass) klass; + int dim = aClass.getDimensionality(); + registerMultiDimArraysForArrayOfObjectTypes(dim, index, aClass); + + IClass elementClass = aClass.getInnermostElementClass(); + if (elementClass != null) { + registerArrayInstanceWithAllSuperclassesOfElement(index, elementClass, dim); + registerArrayInstanceWithAllInterfacesOfElement(index, elementClass, dim); + } + } + } catch (ClassHierarchyException e) { + Warnings.add(ClassHierarchyWarning.create(e.getMessage())); + } + } + + private int registerMultiDimArraysForArrayOfObjectTypes(int dim, int index, ArrayClass aClass) { + + for (int i = 1; i < dim; i++) { + TypeReference jlo = makeArray(TypeReference.JavaLangObject, i); + IClass jloClass = null; + jloClass = aClass.getClassLoader().lookupClass(jlo.getName()); + MutableIntSet set = findOrCreateSparseSetForClass(jloClass); + set.add(index); + } + return dim; + } + + private void registerArrayInstanceWithAllInterfacesOfElement(int index, IClass elementClass, int dim) { + Collection ifaces = null; + ifaces = elementClass.getAllImplementedInterfaces(); + for (Iterator it = ifaces.iterator(); it.hasNext();) { + IClass I = (IClass) it.next(); + TypeReference iArrayRef = makeArray(I.getReference(), dim); + IClass iArrayClass = null; + iArrayClass = I.getClassLoader().lookupClass(iArrayRef.getName()); + MutableIntSet set = findOrCreateSparseSetForClass(iArrayClass); + set.add(index); + if (DEBUG) { + System.err.println("dense filter for interface " + iArrayClass + " " + set); + } + } + } + + private TypeReference makeArray(TypeReference element, int dim) { + TypeReference iArrayRef = element; + for (int i = 0; i < dim; i++) { + iArrayRef = TypeReference.findOrCreateArrayOf(iArrayRef); + } + return iArrayRef; + } + + private void registerArrayInstanceWithAllSuperclassesOfElement(int index, IClass elementClass, int dim) + throws ClassHierarchyException { + IClass T; + // register the array with each supertype of the element class + T = elementClass.getSuperclass(); + while (T != null) { + TypeReference tArrayRef = makeArray(T.getReference(), dim); + IClass tArrayClass = null; + tArrayClass = T.getClassLoader().lookupClass(tArrayRef.getName()); + MutableIntSet set = findOrCreateSparseSetForClass(tArrayClass); + set.add(index); + if (DEBUG) { + System.err.println("dense filter for class " + tArrayClass + " " + set); + } + T = T.getSuperclass(); + } + } + + /** + * @param klass + * @param index + * @throws ClassHierarchyException + */ + private void registerInstanceWithAllInterfaces(IClass klass, int index) throws ClassHierarchyException { + Collection ifaces = klass.getAllImplementedInterfaces(); + for (Iterator it = ifaces.iterator(); it.hasNext();) { + IClass I = (IClass) it.next(); + MutableIntSet set = findOrCreateSparseSetForClass(I); + set.add(index); + if (DEBUG) { + System.err.println("dense filter for interface " + I + " " + set); + } + } + } + + /** + * @param index + * @param T + * @throws ClassHierarchyException + */ + private void registerInstanceWithAllSuperclasses(int index, IClass T) throws ClassHierarchyException { + while (T != null && !T.getReference().equals(TypeReference.JavaLangObject)) { + MutableIntSet set = findOrCreateSparseSetForClass(T); + set.add(index); + if (DEBUG) { + System.err.println("dense filter for class " + T + " " + set); + } + T = T.getSuperclass(); + } + } + + public void newSideEffect(UnaryOperator op, PointerKey arg0) { + if (arg0 == null) { + throw new IllegalArgumentException("null arg0"); + } + if (DEBUG) { + System.err.println("add constraint D: " + op + " " + arg0); + } + assert !pointsToMap.isUnified(arg0); + PointsToSetVariable v1 = findOrCreatePointsToSet(arg0); + newStatement(null, op, v1, true, true); + } + + public void newSideEffect(AbstractOperator op, PointerKey[] arg0) { + if (arg0 == null) { + throw new IllegalArgumentException("null arg0"); + } + if (DEBUG) { + System.err.println("add constraint D: " + op + " " + arg0); + } + PointsToSetVariable[] vs = new PointsToSetVariable[ arg0.length ]; + for(int i = 0; i < arg0.length; i++) { + assert !pointsToMap.isUnified(arg0[i]); + vs[i] = findOrCreatePointsToSet(arg0[i]); + } + newStatement(null, op, vs, true, true); + } + + public void newSideEffect(AbstractOperator op, PointerKey arg0, PointerKey arg1) { + if (DEBUG) { + System.err.println("add constraint D: " + op + " " + arg0); + } + assert !pointsToMap.isUnified(arg0); + assert !pointsToMap.isUnified(arg1); + PointsToSetVariable v1 = findOrCreatePointsToSet(arg0); + PointsToSetVariable v2 = findOrCreatePointsToSet(arg1); + newStatement(null, op, v1, v2, true, true); + } + + @Override + protected void initializeWorkList() { + addAllStatementsToWorkList(); + } + + /** + * @return an object that encapsulates the pointer analysis results + */ + public PointerAnalysis extractPointerAnalysis(PropagationCallGraphBuilder builder) { + if (pointerAnalysis == null) { + pointerAnalysis = makePointerAnalysis(builder); + } + return pointerAnalysis; + } + + @Override + public void performVerboseAction() { + super.performVerboseAction(); + if (DEBUG_MEMORY) { + DEBUG_MEM_COUNTER++; + if (DEBUG_MEM_COUNTER % DEBUG_MEM_INTERVAL == 0) { + DEBUG_MEM_COUNTER = 0; + ReferenceCleanser.clearSoftCaches(); + + System.err.println(flowGraph.spaceReport()); + + System.err.println("Analyze leaks.."); + HeapTracer.traceHeap(Collections.singleton(this), true); + System.err.println("done analyzing leaks"); + } + } + if (getFixedPointSystem() instanceof VerboseAction) { + ((VerboseAction) getFixedPointSystem()).performVerboseAction(); + } + AbstractStatement s = workList.takeStatement(); + System.err.println(printRHSInstances(s)); + workList.insertStatement(s); + System.err.println("CGNodes: " + cg.getNumberOfNodes()); + + } + + private String printRHSInstances(AbstractStatement s) { + if (s instanceof UnaryStatement) { + UnaryStatement u = (UnaryStatement) s; + PointsToSetVariable rhs = (PointsToSetVariable) u.getRightHandSide(); + IntSet value = rhs.getValue(); + final int[] topFive = new int[5]; + value.foreach(new IntSetAction() { + public void act(int x) { + for (int i = 0; i < 4; i++) { + topFive[i] = topFive[i + 1]; + } + topFive[4] = x; + } + }); + StringBuffer result = new StringBuffer(); + for (int i = 0; i < 5; i++) { + int p = topFive[i]; + if (p != 0) { + InstanceKey ik = getInstanceKey(p); + result.append(p).append(" ").append(ik).append("\n"); + } + } + return result.toString(); + } else { + return s.getClass().toString(); + } + } + + @Override + public IFixedPointSystem getFixedPointSystem() { + return flowGraph; + } + + /* + * @see com.ibm.wala.ipa.callgraph.propagation.HeapModel#iteratePointerKeys() + */ + public Iterator iteratePointerKeys() { + return pointsToMap.iterateKeys(); + } + + /** + * warning: this is _real_ slow; don't use it anywhere performance critical + */ + public int getNumberOfPointerKeys() { + return pointsToMap.getNumberOfPointerKeys(); + } + + /** + * Use with care. + */ + Worklist getWorklist() { + return workList; + } + + public Iterator getStatementsThatUse(PointsToSetVariable v) { + return flowGraph.getStatementsThatUse(v); + } + + public Iterator getStatementsThatDef(PointsToSetVariable v) { + return flowGraph.getStatementsThatDef(v); + } + + public NumberedGraph getAssignmentGraph() { + return flowGraph.getAssignmentGraph(); + } + + public Graph getFilterAsssignmentGraph() { + return flowGraph.getFilterAssignmentGraph(); + } + + /** + * NOTE: do not use this method unless you really know what you are doing. Functionality is fragile and may not work in the + * future. + */ + public Graph getFlowGraphIncludingImplicitConstraints() { + return flowGraph.getFlowGraphIncludingImplicitConstraints(); + } + + /** + * + */ + public void revertToPreTransitive() { + pointsToMap.revertToPreTransitive(); + } + + public Iterator getTransitiveRoots() { + return pointsToMap.getTransitiveRoots(); + } + + public boolean isTransitiveRoot(PointerKey key) { + return pointsToMap.isTransitiveRoot(key); + } + + @Override + protected void periodicMaintenance() { + super.periodicMaintenance(); + ReferenceCleanser.clearSoftCaches(); + } + + @Override + public int getVerboseInterval() { + return verboseInterval; + } + + /** + * @param verboseInterval The verboseInterval to set. + */ + public void setVerboseInterval(int verboseInterval) { + this.verboseInterval = verboseInterval; + } + + @Override + public int getPeriodicMaintainInterval() { + return periodicMaintainInterval; + } + + /** + * @param periodicMaintainInteval + */ + public void setPeriodicMaintainInterval(int periodicMaintainInteval) { + this.periodicMaintainInterval = periodicMaintainInteval; + } + + /** + * Unify the points-to-sets for the variables identified by the set s + * + * @param s numbers of points-to-set variables + * @throws IllegalArgumentException if s is null + */ + public void unify(IntSet s) { + if (s == null) { + throw new IllegalArgumentException("s is null"); + } + // cache the variables represented + HashSet cache = HashSetFactory.make(s.size()); + for (IntIterator it = s.intIterator(); it.hasNext();) { + int i = it.next(); + cache.add(pointsToMap.getPointsToSet(i)); + } + + // unify the variables + pointsToMap.unify(s); + int rep = pointsToMap.getRepresentative(s.intIterator().next()); + + // clean up the equations + updateEquationsForUnification(cache, rep); + + // special logic to clean up side effects + updateSideEffectsForUnification(cache, rep); + } + + /** + * Update side effect after unification + * + * @param s set of PointsToSetVariables that have been unified + * @param rep number of the representative variable for the unified set. + */ + private void updateSideEffectsForUnification(HashSet s, int rep) { + PointsToSetVariable pRef = pointsToMap.getPointsToSet(rep); + for (Iterator it = s.iterator(); it.hasNext();) { + PointsToSetVariable p = it.next(); + updateSideEffects(p, pRef); + } + } + + /** + * Update equation def/uses after unification + * + * @param s set of PointsToSetVariables that have been unified + * @param rep number of the representative variable for the unified set. + */ + @SuppressWarnings("unchecked") + private void updateEquationsForUnification(HashSet s, int rep) { + PointsToSetVariable pRef = pointsToMap.getPointsToSet(rep); + for (Iterator it = s.iterator(); it.hasNext();) { + PointsToSetVariable p = it.next(); + + if (p != pRef) { + // pRef is the representative for p. + // be careful: cache the defs before mucking with the underlying system + for (Iterator d = Iterator2Collection.toSet(getStatementsThatDef(p)).iterator(); d.hasNext();) { + AbstractStatement as = (AbstractStatement) d.next(); + + if (as instanceof AssignEquation) { + AssignEquation assign = (AssignEquation) as; + PointsToSetVariable rhs = assign.getRightHandSide(); + int rhsRep = pointsToMap.getRepresentative(pointsToMap.getIndex(rhs.getPointerKey())); + if (rhsRep == rep) { + flowGraph.removeStatement(as); + } else { + replaceLHS(pRef, p, as); + } + } else { + replaceLHS(pRef, p, as); + } + } + // be careful: cache the defs before mucking with the underlying system + for (Iterator u = Iterator2Collection.toSet(getStatementsThatUse(p)).iterator(); u.hasNext();) { + AbstractStatement as = (AbstractStatement) u.next(); + if (as instanceof AssignEquation) { + AssignEquation assign = (AssignEquation) as; + PointsToSetVariable lhs = assign.getLHS(); + int lhsRep = pointsToMap.getRepresentative(pointsToMap.getIndex(lhs.getPointerKey())); + if (lhsRep == rep) { + flowGraph.removeStatement(as); + } else { + replaceRHS(pRef, p, as); + } + } else { + replaceRHS(pRef, p, as); + } + } + if (flowGraph.getNumberOfStatementsThatDef(p) == 0 && flowGraph.getNumberOfStatementsThatUse(p) == 0) { + flowGraph.removeVariable(p); + } + } + } + } + + /** + * replace all occurrences of p on the rhs of a statement with pRef + * + * @param as a statement that uses p in it's right-hand side + */ + private void replaceRHS(PointsToSetVariable pRef, PointsToSetVariable p, + AbstractStatement> as) { + if (as instanceof UnaryStatement) { + assert ((UnaryStatement) as).getRightHandSide() == p; + newStatement(as.getLHS(), (UnaryOperator) as.getOperator(), pRef, false, false); + } else { + IVariable[] rhs = as.getRHS(); + PointsToSetVariable[] newRHS = new PointsToSetVariable[rhs.length]; + for (int i = 0; i < rhs.length; i++) { + if (rhs[i].equals(p)) { + newRHS[i] = pRef; + } else { + newRHS[i] = (PointsToSetVariable) rhs[i]; + } + } + newStatement(as.getLHS(), as.getOperator(), newRHS, false, false); + } + flowGraph.removeStatement(as); + } + + /** + * replace all occurences of p on the lhs of a statement with pRef + * + * @param as a statement that defs p + */ + private void replaceLHS(PointsToSetVariable pRef, PointsToSetVariable p, + AbstractStatement> as) { + assert as.getLHS() == p; + if (as instanceof UnaryStatement) { + newStatement(pRef, (UnaryOperator) as.getOperator(), (PointsToSetVariable) ((UnaryStatement) as) + .getRightHandSide(), false, false); + } else { + newStatement(pRef, as.getOperator(), as.getRHS(), false, false); + } + flowGraph.removeStatement(as); + } + + public boolean isUnified(PointerKey result) { + return pointsToMap.isUnified(result); + } + + public int getNumber(PointerKey p) { + return pointsToMap.getIndex(p); + } + + @Override + protected PointsToSetVariable[] makeStmtRHS(int size) { + return new PointsToSetVariable[size]; + } +} diff --git a/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/ReceiverInstanceContext.java b/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/ReceiverInstanceContext.java index 7545222f2..de1d04aef 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/ReceiverInstanceContext.java +++ b/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/ReceiverInstanceContext.java @@ -1,77 +1,77 @@ -/******************************************************************************* - * Copyright (c) 2002 - 2006 IBM Corporation. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * IBM Corporation - initial API and implementation - *******************************************************************************/ -package com.ibm.wala.ipa.callgraph.propagation; - -import com.ibm.wala.ipa.callgraph.Context; -import com.ibm.wala.ipa.callgraph.ContextItem; -import com.ibm.wala.ipa.callgraph.ContextKey; - -/** - * This is a context which is customized for the {@link InstanceKey} of the receiver. - */ -public class ReceiverInstanceContext implements Context { - - private final InstanceKey ik; - - /** - * @param I the instance key that represents the receiver - */ - public ReceiverInstanceContext(InstanceKey I) { - if (I == null) { - throw new IllegalArgumentException("null I"); - } - this.ik = I; - } - - public ContextItem get(ContextKey name) { - if (name == ContextKey.RECEIVER) - return ik; - else if (name == ContextKey.PARAMETERS[0]) - return new FilteredPointerKey.SingleInstanceFilter(ik); - else { - return null; - } - } - - @Override - public String toString() { - return "ReceiverInstanceContext<" + ik + ">"; - } - - @Override - public int hashCode() { - final int prime = 31; - int result = 1; - result = prime * result + ((ik == null) ? 0 : ik.hashCode()); - return result; - } - - @Override - public boolean equals(Object obj) { - if (this == obj) - return true; - if (obj == null) - return false; - if (getClass() != obj.getClass()) - return false; - final ReceiverInstanceContext other = (ReceiverInstanceContext) obj; - if (ik == null) { - if (other.ik != null) - return false; - } else if (!ik.equals(other.ik)) - return false; - return true; - } - - public InstanceKey getReceiver() { - return ik; - } -} +/******************************************************************************* + * 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.ipa.callgraph.propagation; + +import com.ibm.wala.ipa.callgraph.Context; +import com.ibm.wala.ipa.callgraph.ContextItem; +import com.ibm.wala.ipa.callgraph.ContextKey; + +/** + * This is a context which is customized for the {@link InstanceKey} of the receiver. + */ +public class ReceiverInstanceContext implements Context { + + private final InstanceKey ik; + + /** + * @param I the instance key that represents the receiver + */ + public ReceiverInstanceContext(InstanceKey I) { + if (I == null) { + throw new IllegalArgumentException("null I"); + } + this.ik = I; + } + + public ContextItem get(ContextKey name) { + if (name == ContextKey.RECEIVER) + return ik; + else if (name == ContextKey.PARAMETERS[0]) + return new FilteredPointerKey.SingleInstanceFilter(ik); + else { + return null; + } + } + + @Override + public String toString() { + return "ReceiverInstanceContext<" + ik + ">"; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((ik == null) ? 0 : ik.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + final ReceiverInstanceContext other = (ReceiverInstanceContext) obj; + if (ik == null) { + if (other.ik != null) + return false; + } else if (!ik.equals(other.ik)) + return false; + return true; + } + + public InstanceKey getReceiver() { + return ik; + } +} diff --git a/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/ReceiverTypeContextSelector.java b/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/ReceiverTypeContextSelector.java index ec41c16b4..d4a3adf1e 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/ReceiverTypeContextSelector.java +++ b/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/ReceiverTypeContextSelector.java @@ -1,55 +1,55 @@ -/******************************************************************************* - * Copyright (c) 2002 - 2006 IBM Corporation. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * IBM Corporation - initial API and implementation - *******************************************************************************/ -package com.ibm.wala.ipa.callgraph.propagation; - -import com.ibm.wala.analysis.reflection.JavaTypeContext; -import com.ibm.wala.analysis.typeInference.PointType; -import com.ibm.wala.classLoader.CallSiteReference; -import com.ibm.wala.classLoader.IMethod; -import com.ibm.wala.ipa.callgraph.CGNode; -import com.ibm.wala.ipa.callgraph.Context; -import com.ibm.wala.ipa.callgraph.ContextSelector; -import com.ibm.wala.ipa.callgraph.impl.Everywhere; -import com.ibm.wala.util.intset.EmptyIntSet; -import com.ibm.wala.util.intset.IntSet; -import com.ibm.wala.util.intset.IntSetUtil; - -/** - * This context selector selects a context based on the concrete type of the receiver. - */ -public class ReceiverTypeContextSelector implements ContextSelector { - - public ReceiverTypeContextSelector() { - } - - public Context getCalleeTarget(CGNode caller, CallSiteReference site, IMethod callee, InstanceKey[] receiver) { - if (site.isStatic()) { - return Everywhere.EVERYWHERE; - } else { - if (receiver == null) { - throw new IllegalArgumentException("receiver is null"); - } - PointType P = new PointType(receiver[0].getConcreteType()); - return new JavaTypeContext(P); - } - } - - private static final IntSet receiver = IntSetUtil.make(new int[]{ 0 }); - - public IntSet getRelevantParameters(CGNode caller, CallSiteReference site) { - if (site.isStatic()) { - return EmptyIntSet.instance; - } else { - return receiver; - } - } - -} +/******************************************************************************* + * 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.ipa.callgraph.propagation; + +import com.ibm.wala.analysis.reflection.JavaTypeContext; +import com.ibm.wala.analysis.typeInference.PointType; +import com.ibm.wala.classLoader.CallSiteReference; +import com.ibm.wala.classLoader.IMethod; +import com.ibm.wala.ipa.callgraph.CGNode; +import com.ibm.wala.ipa.callgraph.Context; +import com.ibm.wala.ipa.callgraph.ContextSelector; +import com.ibm.wala.ipa.callgraph.impl.Everywhere; +import com.ibm.wala.util.intset.EmptyIntSet; +import com.ibm.wala.util.intset.IntSet; +import com.ibm.wala.util.intset.IntSetUtil; + +/** + * This context selector selects a context based on the concrete type of the receiver. + */ +public class ReceiverTypeContextSelector implements ContextSelector { + + public ReceiverTypeContextSelector() { + } + + public Context getCalleeTarget(CGNode caller, CallSiteReference site, IMethod callee, InstanceKey[] receiver) { + if (site.isStatic()) { + return Everywhere.EVERYWHERE; + } else { + if (receiver == null) { + throw new IllegalArgumentException("receiver is null"); + } + PointType P = new PointType(receiver[0].getConcreteType()); + return new JavaTypeContext(P); + } + } + + private static final IntSet receiver = IntSetUtil.make(new int[]{ 0 }); + + public IntSet getRelevantParameters(CGNode caller, CallSiteReference site) { + if (site.isStatic()) { + return EmptyIntSet.instance; + } else { + return receiver; + } + } + +} diff --git a/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/ReflectionHandler.java b/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/ReflectionHandler.java index 7cad67d53..c727c75c5 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/ReflectionHandler.java +++ b/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/ReflectionHandler.java @@ -1,130 +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.ipa.callgraph.propagation; - -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.SyntheticMethod; -import com.ibm.wala.ipa.callgraph.CGNode; -import com.ibm.wala.ipa.callgraph.propagation.rta.RTAContextInterpreter; -import com.ibm.wala.ipa.cha.IClassHierarchy; -import com.ibm.wala.ipa.slicer.NormalReturnCallee; -import com.ibm.wala.ipa.slicer.NormalStatement; -import com.ibm.wala.ipa.slicer.Slicer; -import com.ibm.wala.ipa.slicer.Slicer.ControlDependenceOptions; -import com.ibm.wala.ipa.slicer.Slicer.DataDependenceOptions; -import com.ibm.wala.ipa.slicer.Statement; -import com.ibm.wala.ipa.slicer.Statement.Kind; -import com.ibm.wala.ssa.SSACheckCastInstruction; -import com.ibm.wala.types.TypeReference; -import com.ibm.wala.util.CancelException; -import com.ibm.wala.util.MonitorUtil.IProgressMonitor; -import com.ibm.wala.util.Predicate; -import com.ibm.wala.util.collections.HashSetFactory; - -/** - * a helper class which can modify a {@link PropagationCallGraphBuilder} to deal with reflective factory methods. - */ -public class ReflectionHandler { - private final static boolean VERBOSE = false; - - private final PropagationCallGraphBuilder builder; - - public ReflectionHandler(PropagationCallGraphBuilder builder) { - this.builder = builder; - } - - /** - * update the pointer analysis solver based on flow of reflective factory results to checkcasts - * @param monitor - * - * @return true if anything has changed - * @throws CancelException - * @throws IllegalArgumentException - */ - protected boolean updateForReflection(IProgressMonitor monitor) throws IllegalArgumentException, CancelException { - - Collection returnStatements = computeFactoryReturnStatements(); - Set changedNodes = HashSetFactory.make(); - for (Statement st : returnStatements) { - if (VERBOSE) { - System.err.println("Slice " + st); - } - Collection slice = Slicer.computeForwardSlice(st, builder.callGraph, null, DataDependenceOptions.REFLECTION, - ControlDependenceOptions.NONE); - if (VERBOSE) { - for (Statement x : slice) { - System.err.println(" " + x); - } - } - Predicate f = new Predicate() { - @Override - public boolean test(Statement s) { - if (s.getKind() == Kind.NORMAL) { - return ((NormalStatement) s).getInstruction() instanceof SSACheckCastInstruction; - } else { - return false; - } - } - }; - Collection casts = Predicate.filter(slice.iterator(), f); - changedNodes.addAll(modifyFactoryInterpreter(st, casts, builder.getContextInterpreter(), builder.getClassHierarchy())); - } - for (Iterator it = changedNodes.iterator(); it.hasNext();) { - builder.addConstraintsFromChangedNode(it.next(), monitor); - } - return changedNodes.size() > 0; - - } - - private Collection computeFactoryReturnStatements() { - // todo: clean up logic with inheritance, delegation. - HashSet result = HashSetFactory.make(); - for (Iterator it = builder.getCallGraph().iterator(); it.hasNext();) { - CGNode n = (CGNode) it.next(); - if (n.getMethod() instanceof SyntheticMethod) { - SyntheticMethod m = (SyntheticMethod) n.getMethod(); - if (m.isFactoryMethod()) { - result.add(new NormalReturnCallee(n)); - } - } - } - return result; - } - - /** - * modify the contextInterpreter to account for new interpretations of factory methods. - * - * @return set of nodes whose interpretation has changed. - */ - private Set modifyFactoryInterpreter(Statement returnStatement, Collection casts, - RTAContextInterpreter contextInterpreter, IClassHierarchy cha) { - HashSet result = HashSetFactory.make(); - - for (Statement st : casts) { - SSACheckCastInstruction c = (SSACheckCastInstruction) ((NormalStatement) st).getInstruction(); - - for (TypeReference type : c.getDeclaredResultTypes()) { - IClass klass = cha.lookupClass(type); - if (klass != null) { - if (contextInterpreter.recordFactoryType(returnStatement.getNode(), klass)) { - result.add(returnStatement.getNode()); - } - } - } - } - return result; - } -} +/******************************************************************************* + * 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.ipa.callgraph.propagation; + +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.SyntheticMethod; +import com.ibm.wala.ipa.callgraph.CGNode; +import com.ibm.wala.ipa.callgraph.propagation.rta.RTAContextInterpreter; +import com.ibm.wala.ipa.cha.IClassHierarchy; +import com.ibm.wala.ipa.slicer.NormalReturnCallee; +import com.ibm.wala.ipa.slicer.NormalStatement; +import com.ibm.wala.ipa.slicer.Slicer; +import com.ibm.wala.ipa.slicer.Slicer.ControlDependenceOptions; +import com.ibm.wala.ipa.slicer.Slicer.DataDependenceOptions; +import com.ibm.wala.ipa.slicer.Statement; +import com.ibm.wala.ipa.slicer.Statement.Kind; +import com.ibm.wala.ssa.SSACheckCastInstruction; +import com.ibm.wala.types.TypeReference; +import com.ibm.wala.util.CancelException; +import com.ibm.wala.util.MonitorUtil.IProgressMonitor; +import com.ibm.wala.util.Predicate; +import com.ibm.wala.util.collections.HashSetFactory; + +/** + * a helper class which can modify a {@link PropagationCallGraphBuilder} to deal with reflective factory methods. + */ +public class ReflectionHandler { + private final static boolean VERBOSE = false; + + private final PropagationCallGraphBuilder builder; + + public ReflectionHandler(PropagationCallGraphBuilder builder) { + this.builder = builder; + } + + /** + * update the pointer analysis solver based on flow of reflective factory results to checkcasts + * @param monitor + * + * @return true if anything has changed + * @throws CancelException + * @throws IllegalArgumentException + */ + protected boolean updateForReflection(IProgressMonitor monitor) throws IllegalArgumentException, CancelException { + + Collection returnStatements = computeFactoryReturnStatements(); + Set changedNodes = HashSetFactory.make(); + for (Statement st : returnStatements) { + if (VERBOSE) { + System.err.println("Slice " + st); + } + Collection slice = Slicer.computeForwardSlice(st, builder.callGraph, null, DataDependenceOptions.REFLECTION, + ControlDependenceOptions.NONE); + if (VERBOSE) { + for (Statement x : slice) { + System.err.println(" " + x); + } + } + Predicate f = new Predicate() { + @Override + public boolean test(Statement s) { + if (s.getKind() == Kind.NORMAL) { + return ((NormalStatement) s).getInstruction() instanceof SSACheckCastInstruction; + } else { + return false; + } + } + }; + Collection casts = Predicate.filter(slice.iterator(), f); + changedNodes.addAll(modifyFactoryInterpreter(st, casts, builder.getContextInterpreter(), builder.getClassHierarchy())); + } + for (Iterator it = changedNodes.iterator(); it.hasNext();) { + builder.addConstraintsFromChangedNode(it.next(), monitor); + } + return changedNodes.size() > 0; + + } + + private Collection computeFactoryReturnStatements() { + // todo: clean up logic with inheritance, delegation. + HashSet result = HashSetFactory.make(); + for (Iterator it = builder.getCallGraph().iterator(); it.hasNext();) { + CGNode n = (CGNode) it.next(); + if (n.getMethod() instanceof SyntheticMethod) { + SyntheticMethod m = (SyntheticMethod) n.getMethod(); + if (m.isFactoryMethod()) { + result.add(new NormalReturnCallee(n)); + } + } + } + return result; + } + + /** + * modify the contextInterpreter to account for new interpretations of factory methods. + * + * @return set of nodes whose interpretation has changed. + */ + private Set modifyFactoryInterpreter(Statement returnStatement, Collection casts, + RTAContextInterpreter contextInterpreter, IClassHierarchy cha) { + HashSet result = HashSetFactory.make(); + + for (Statement st : casts) { + SSACheckCastInstruction c = (SSACheckCastInstruction) ((NormalStatement) st).getInstruction(); + + for (TypeReference type : c.getDeclaredResultTypes()) { + IClass klass = cha.lookupClass(type); + if (klass != null) { + if (contextInterpreter.recordFactoryType(returnStatement.getNode(), klass)) { + result.add(returnStatement.getNode()); + } + } + } + } + return result; + } +} diff --git a/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/ReturnValueKey.java b/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/ReturnValueKey.java index f6a936626..3ba7e0366 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/ReturnValueKey.java +++ b/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/ReturnValueKey.java @@ -1,37 +1,37 @@ -/******************************************************************************* - * 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.ipa.callgraph.propagation; - -import com.ibm.wala.ipa.callgraph.CGNode; - -/** - * A key which represents the return value for a node - */ -public class ReturnValueKey extends NodeKey { - public ReturnValueKey(CGNode node) { - super(node); - } - - @Override - public String toString() { - return "[Ret-V:" + getNode() + "]"; - } - - @Override - public boolean equals(Object obj) { - return (obj instanceof ReturnValueKey) && super.internalEquals(obj); - } - - @Override - public int hashCode() { - return 1283 * super.internalHashCode(); - } +/******************************************************************************* + * 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.ipa.callgraph.propagation; + +import com.ibm.wala.ipa.callgraph.CGNode; + +/** + * A key which represents the return value for a node + */ +public class ReturnValueKey extends NodeKey { + public ReturnValueKey(CGNode node) { + super(node); + } + + @Override + public String toString() { + return "[Ret-V:" + getNode() + "]"; + } + + @Override + public boolean equals(Object obj) { + return (obj instanceof ReturnValueKey) && super.internalEquals(obj); + } + + @Override + public int hashCode() { + return 1283 * super.internalHashCode(); + } } \ No newline at end of file diff --git a/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/ReturnValueKeyWithFilter.java b/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/ReturnValueKeyWithFilter.java index 1e8938b94..68e6f419b 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/ReturnValueKeyWithFilter.java +++ b/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/ReturnValueKeyWithFilter.java @@ -1,35 +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.ipa.callgraph.propagation; - -import com.ibm.wala.ipa.callgraph.CGNode; - -/** - * a helper class which can modify a PropagationCallGraphBuilder to deal with - * reflective factory methods. - */ -public class ReturnValueKeyWithFilter extends ReturnValueKey implements FilteredPointerKey { - - private final TypeFilter typeFilter; - - public ReturnValueKeyWithFilter(CGNode node, TypeFilter typeFilter) { - super(node); - if (typeFilter == null) { - throw new IllegalArgumentException("null typeFilter"); - } - this.typeFilter = typeFilter; - } - - public TypeFilter getTypeFilter() { - return typeFilter; - } - -} +/******************************************************************************* + * 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.ipa.callgraph.propagation; + +import com.ibm.wala.ipa.callgraph.CGNode; + +/** + * a helper class which can modify a PropagationCallGraphBuilder to deal with + * reflective factory methods. + */ +public class ReturnValueKeyWithFilter extends ReturnValueKey implements FilteredPointerKey { + + private final TypeFilter typeFilter; + + public ReturnValueKeyWithFilter(CGNode node, TypeFilter typeFilter) { + super(node); + if (typeFilter == null) { + throw new IllegalArgumentException("null typeFilter"); + } + this.typeFilter = typeFilter; + } + + public TypeFilter getTypeFilter() { + return typeFilter; + } + +} diff --git a/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/SSAContextInterpreter.java b/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/SSAContextInterpreter.java index 9cf4fa88d..042ed63ff 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/SSAContextInterpreter.java +++ b/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/SSAContextInterpreter.java @@ -1,43 +1,43 @@ -/******************************************************************************* - * 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.ipa.callgraph.propagation; - -import com.ibm.wala.cfg.ControlFlowGraph; -import com.ibm.wala.ipa.callgraph.CGNode; -import com.ibm.wala.ipa.callgraph.propagation.rta.RTAContextInterpreter; -import com.ibm.wala.ssa.DefUse; -import com.ibm.wala.ssa.IR; -import com.ibm.wala.ssa.ISSABasicBlock; -import com.ibm.wala.ssa.SSAInstruction; - -/** - * An object that provides an interface to local method information needed for CFA. - */ -public interface SSAContextInterpreter extends RTAContextInterpreter { - - /** - * @return the IR that models the method context, or null if it's an unmodelled native method - */ - public IR getIR(CGNode node); - - /** - * @return DefUse for the IR that models the method context, or null if it's an unmodelled native method - */ - public DefUse getDU(CGNode node); - - /** - * @return the number of the statements in the IR, or -1 if it's an unmodelled native method. - */ - public int getNumberOfStatements(CGNode node); - - public ControlFlowGraph getCFG(CGNode n); - -} +/******************************************************************************* + * 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.ipa.callgraph.propagation; + +import com.ibm.wala.cfg.ControlFlowGraph; +import com.ibm.wala.ipa.callgraph.CGNode; +import com.ibm.wala.ipa.callgraph.propagation.rta.RTAContextInterpreter; +import com.ibm.wala.ssa.DefUse; +import com.ibm.wala.ssa.IR; +import com.ibm.wala.ssa.ISSABasicBlock; +import com.ibm.wala.ssa.SSAInstruction; + +/** + * An object that provides an interface to local method information needed for CFA. + */ +public interface SSAContextInterpreter extends RTAContextInterpreter { + + /** + * @return the IR that models the method context, or null if it's an unmodelled native method + */ + public IR getIR(CGNode node); + + /** + * @return DefUse for the IR that models the method context, or null if it's an unmodelled native method + */ + public DefUse getDU(CGNode node); + + /** + * @return the number of the statements in the IR, or -1 if it's an unmodelled native method. + */ + public int getNumberOfStatements(CGNode node); + + public ControlFlowGraph getCFG(CGNode n); + +} diff --git a/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/SSAPropagationCallGraphBuilder.java b/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/SSAPropagationCallGraphBuilder.java index b7130494a..6f1517dca 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/SSAPropagationCallGraphBuilder.java +++ b/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/SSAPropagationCallGraphBuilder.java @@ -1,2267 +1,2267 @@ -/******************************************************************************* - * 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.ipa.callgraph.propagation; - -import java.util.ArrayList; -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.analysis.reflection.CloneInterpreter; -import com.ibm.wala.cfg.ControlFlowGraph; -import com.ibm.wala.cfg.IBasicBlock; -import com.ibm.wala.classLoader.ArrayClass; -import com.ibm.wala.classLoader.CallSiteReference; -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.classLoader.ProgramCounter; -import com.ibm.wala.fixpoint.AbstractOperator; -import com.ibm.wala.ipa.callgraph.AnalysisCache; -import com.ibm.wala.ipa.callgraph.AnalysisOptions; -import com.ibm.wala.ipa.callgraph.CGNode; -import com.ibm.wala.ipa.callgraph.ContextKey; -import com.ibm.wala.ipa.callgraph.ContextSelector; -import com.ibm.wala.ipa.callgraph.impl.AbstractRootMethod; -import com.ibm.wala.ipa.callgraph.impl.ExplicitCallGraph; -import com.ibm.wala.ipa.callgraph.impl.FakeRootMethod; -import com.ibm.wala.ipa.cha.IClassHierarchy; -import com.ibm.wala.shrikeBT.ConditionalBranchInstruction; -import com.ibm.wala.shrikeBT.IInvokeInstruction; -import com.ibm.wala.ssa.DefUse; -import com.ibm.wala.ssa.IR; -import com.ibm.wala.ssa.ISSABasicBlock; -import com.ibm.wala.ssa.SSAAbstractInvokeInstruction; -import com.ibm.wala.ssa.SSAAbstractThrowInstruction; -import com.ibm.wala.ssa.SSAArrayLoadInstruction; -import com.ibm.wala.ssa.SSAArrayStoreInstruction; -import com.ibm.wala.ssa.SSACFG; -import com.ibm.wala.ssa.SSACFG.BasicBlock; -import com.ibm.wala.ssa.SSACFG.ExceptionHandlerBasicBlock; -import com.ibm.wala.ssa.SSACheckCastInstruction; -import com.ibm.wala.ssa.SSAConditionalBranchInstruction; -import com.ibm.wala.ssa.SSAGetCaughtExceptionInstruction; -import com.ibm.wala.ssa.SSAGetInstruction; -import com.ibm.wala.ssa.SSAInstanceofInstruction; -import com.ibm.wala.ssa.SSAInstruction; -import com.ibm.wala.ssa.SSAInvokeInstruction; -import com.ibm.wala.ssa.SSALoadMetadataInstruction; -import com.ibm.wala.ssa.SSANewInstruction; -import com.ibm.wala.ssa.SSAPhiInstruction; -import com.ibm.wala.ssa.SSAPiInstruction; -import com.ibm.wala.ssa.SSAPutInstruction; -import com.ibm.wala.ssa.SSAReturnInstruction; -import com.ibm.wala.ssa.SSAThrowInstruction; -import com.ibm.wala.ssa.SymbolTable; -import com.ibm.wala.types.FieldReference; -import com.ibm.wala.types.MethodReference; -import com.ibm.wala.types.Selector; -import com.ibm.wala.types.TypeReference; -import com.ibm.wala.util.CancelException; -import com.ibm.wala.util.CancelRuntimeException; -import com.ibm.wala.util.MonitorUtil; -import com.ibm.wala.util.MonitorUtil.IProgressMonitor; -import com.ibm.wala.util.collections.HashSetFactory; -import com.ibm.wala.util.debug.Assertions; -import com.ibm.wala.util.functions.VoidFunction; -import com.ibm.wala.util.intset.IntIterator; -import com.ibm.wala.util.intset.IntSet; -import com.ibm.wala.util.intset.IntSetAction; -import com.ibm.wala.util.intset.IntSetUtil; -import com.ibm.wala.util.intset.MutableIntSet; -import com.ibm.wala.util.ref.ReferenceCleanser; -import com.ibm.wala.util.warnings.Warning; -import com.ibm.wala.util.warnings.Warnings; - -/** - * This abstract base class provides the general algorithm for a call graph builder that relies on propagation through an iterative - * dataflow solver, and constraints generated by statements in SSA form. - * - * TODO: This implementation currently keeps all points to sets live ... even those for local variables that do not span - * interprocedural boundaries. This may be too space-inefficient .. we can consider recomputing local sets on demand. - */ -public abstract class SSAPropagationCallGraphBuilder extends PropagationCallGraphBuilder implements HeapModel { - private final static boolean DEBUG = false; - - private final static boolean DEBUG_MULTINEWARRAY = DEBUG | false; - - /** - * Should we periodically clear out soft reference caches in an attempt to help the GC? - */ - public final static boolean PERIODIC_WIPE_SOFT_CACHES = true; - - /** - * Interval which defines the period to clear soft reference caches - */ - public final static int WIPE_SOFT_CACHE_INTERVAL = 2500; - - /** - * Counter for wiping soft caches - */ - private static int wipeCount = 0; - - /** - * use type inference to avoid unnecessary filter constraints? - */ - // private final static boolean OPTIMIZE_WITH_TYPE_INFERENCE = true; - /** - * An optimization: if we can locally determine the final solution for a points-to set, then don't actually create the points-to - * set, but instead short circuit by propagating the final solution to all such uses. - * - * String constants are ALWAYS considered invariant, regardless of the value of this flag. - * - * However, if this flag is set, then the solver is more aggressive identifying invariants. - * - * Doesn't play well with pre-transitive solver; turning off for now. - */ - private final static boolean SHORT_CIRCUIT_INVARIANT_SETS = true; - - /** - * An optimization: if we can locally determine that a particular pointer p has exactly one use, then we don't actually create the - * points-to-set for p, but instead short-circuit by propagating the final solution to the unique use. - * - * Doesn't play well with pre-transitive solver; turning off for now. - */ - protected final static boolean SHORT_CIRCUIT_SINGLE_USES = true; - - /** - * Should we change calls to clone() to assignments? - */ - private final boolean clone2Assign = false; - - /** - * Cache for efficiency - */ - private final static Selector cloneSelector = CloneInterpreter.CLONE.getSelector(); - - /** - * set of class whose clinits have already been processed - */ - private final Set clinitVisited = HashSetFactory.make(); - - private IProgressMonitor monitor; - - protected SSAPropagationCallGraphBuilder(IClassHierarchy cha, AnalysisOptions options, AnalysisCache cache, - PointerKeyFactory pointerKeyFactory) { - super(cha, options, cache, pointerKeyFactory); - // this.usePreTransitiveSolver = options.usePreTransitiveSolver(); - } - - public SSAContextInterpreter getCFAContextInterpreter() { - return (SSAContextInterpreter) getContextInterpreter(); - } - - /** - * @param node - * @param x - * @param type - * @return the instance key that represents the exception of type _type_ thrown by a particular PEI. - * @throws IllegalArgumentException if ikFactory is null - */ - public static InstanceKey getInstanceKeyForPEI(CGNode node, ProgramCounter x, TypeReference type, InstanceKeyFactory ikFactory) { - if (ikFactory == null) { - throw new IllegalArgumentException("ikFactory is null"); - } - return ikFactory.getInstanceKeyForPEI(node, x, type); - } - - /** - * Visit all instructions in a node, and add dataflow constraints induced by each statement in the SSA form. - * @throws CancelException - * - * @see com.ibm.wala.ipa.callgraph.propagation.PropagationCallGraphBuilder#addConstraintsFromNode(com.ibm.wala.ipa.callgraph.CGNode) - */ - @Override - protected boolean addConstraintsFromNode(CGNode node, IProgressMonitor monitor) throws CancelException { - this.monitor = monitor; - if (haveAlreadyVisited(node)) { - return false; - } else { - markAlreadyVisited(node); - } - return unconditionallyAddConstraintsFromNode(node, monitor); - } - - @Override - protected boolean unconditionallyAddConstraintsFromNode(CGNode node, IProgressMonitor monitor) throws CancelException { - this.monitor = monitor; - if (PERIODIC_WIPE_SOFT_CACHES) { - wipeCount++; - if (wipeCount >= WIPE_SOFT_CACHE_INTERVAL) { - wipeCount = 0; - ReferenceCleanser.clearSoftCaches(); - } - } - - if (DEBUG) { - System.err.println("\n\nAdd constraints from node " + node); - } - IR ir = getCFAContextInterpreter().getIR(node); - if (DEBUG) { - if (ir == null) { - System.err.println("\n No statements\n"); - } else { - try { - System.err.println(ir.toString()); - } catch (Error e) { - e.printStackTrace(); - } - } - } - - if (ir == null) { - return false; - } - - addNodeInstructionConstraints(node, monitor); - - DefUse du = getCFAContextInterpreter().getDU(node); - addNodePassthruExceptionConstraints(node, ir, du); - // conservatively assume something changed - return true; - } - - /** - * @return a visitor to examine instructions in the ir - */ - protected ConstraintVisitor makeVisitor(CGNode node) { - return new ConstraintVisitor(this, node); - } - - /** - * Add pointer flow constraints based on instructions in a given node - * @throws CancelException - */ - protected void addNodeInstructionConstraints(CGNode node, IProgressMonitor monitor) throws CancelException { - this.monitor = monitor; - ConstraintVisitor v = makeVisitor(node); - - IR ir = v.ir; - ControlFlowGraph cfg = ir.getControlFlowGraph(); - for (Iterator x = cfg.iterator(); x.hasNext();) { - BasicBlock b = (BasicBlock) x.next(); - addBlockInstructionConstraints(node, cfg, b, v, monitor); - if (wasChanged(node)) { - return; - } - } - } - - /** - * Add constraints for a particular basic block. - * @throws CancelException - */ - protected void addBlockInstructionConstraints(CGNode node, ControlFlowGraph cfg, BasicBlock b, - ConstraintVisitor v, IProgressMonitor monitor) throws CancelException { - this.monitor = monitor; - v.setBasicBlock(b); - - // visit each instruction in the basic block. - for (Iterator it = b.iterator(); it.hasNext();) { - MonitorUtil.throwExceptionIfCanceled(monitor); - SSAInstruction s = it.next(); - if (s != null) { - s.visit(v); - if (wasChanged(node)) { - return; - } - } - } - - addPhiConstraints(node, cfg, b, v); - } - - private void addPhiConstraints(CGNode node, ControlFlowGraph cfg, BasicBlock b, - ConstraintVisitor v) { - // visit each phi instruction in each successor block - for (Iterator sbs = cfg.getSuccNodes(b); sbs.hasNext();) { - BasicBlock sb = (BasicBlock) sbs.next(); - if (!sb.hasPhi()) { - continue; - } - int n = 0; - for (Iterator back = cfg.getPredNodes(sb); back.hasNext(); n++) { - if (back.next() == b) { - break; - } - } - assert n < cfg.getPredNodeCount(sb); - for (Iterator phis = sb.iteratePhis(); phis.hasNext();) { - SSAPhiInstruction phi = (SSAPhiInstruction) phis.next(); - if (phi == null) { - continue; - } - PointerKey def = getPointerKeyForLocal(node, phi.getDef()); - if (hasNoInterestingUses(node, phi.getDef(), v.du)) { - system.recordImplicitPointsToSet(def); - } else { - // the following test restricts the constraints to reachable - // paths, according to verification constraints - if (phi.getUse(n) > 0) { - PointerKey use = getPointerKeyForLocal(node, phi.getUse(n)); - if (contentsAreInvariant(v.symbolTable, v.du, phi.getUse(n))) { - system.recordImplicitPointsToSet(use); - InstanceKey[] ik = getInvariantContents(v.symbolTable, v.du, node, phi.getUse(n), this); - for (int i = 0; i < ik.length; i++) { - system.newConstraint(def, ik[i]); - } - } else { - system.newConstraint(def, assignOperator, use); - } - } - } - } - } - } - - /** - * Add constraints to represent the flow of exceptions to the exceptional return value for this node - * - * @param node - * @param ir - */ - protected void addNodePassthruExceptionConstraints(CGNode node, IR ir, DefUse du) { - // add constraints relating to thrown exceptions that reach the exit block. - List peis = getIncomingPEIs(ir, ir.getExitBlock()); - PointerKey exception = getPointerKeyForExceptionalReturnValue(node); - - TypeReference throwableType = node.getMethod().getDeclaringClass().getClassLoader().getLanguage().getThrowableType(); - IClass c = node.getClassHierarchy().lookupClass(throwableType); - addExceptionDefConstraints(ir, du, node, peis, exception, Collections.singleton(c)); - } - - /** - * Generate constraints which assign exception values into an exception pointer - * - * @param node governing node - * @param peis list of PEI instructions - * @param exceptionVar PointerKey representing a pointer to an exception value - * @param catchClasses the types "caught" by the exceptionVar - */ - private void addExceptionDefConstraints(IR ir, DefUse du, CGNode node, List peis, PointerKey exceptionVar, - Set catchClasses) { - if (DEBUG) { - System.err.println("Add exception def constraints for node " + node); - } - for (Iterator it = peis.iterator(); it.hasNext();) { - ProgramCounter peiLoc = it.next(); - if (DEBUG) { - System.err.println("peiLoc: " + peiLoc); - } - SSAInstruction pei = ir.getPEI(peiLoc); - - if (DEBUG) { - System.err.println("Add exceptions from pei " + pei); - } - - if (pei instanceof SSAAbstractInvokeInstruction) { - SSAAbstractInvokeInstruction s = (SSAAbstractInvokeInstruction) pei; - PointerKey e = getPointerKeyForLocal(node, s.getException()); - - if (!SHORT_CIRCUIT_SINGLE_USES || !hasUniqueCatchBlock(s, ir)) { - addAssignmentsForCatchPointerKey(exceptionVar, catchClasses, e); - }// else { - // System.err.println("SKIPPING ASSIGNMENTS TO " + exceptionVar + " FROM " + - // e); - // } - } else if (pei instanceof SSAAbstractThrowInstruction) { - SSAAbstractThrowInstruction s = (SSAAbstractThrowInstruction) pei; - PointerKey e = getPointerKeyForLocal(node, s.getException()); - - if (contentsAreInvariant(ir.getSymbolTable(), du, s.getException())) { - InstanceKey[] ik = getInvariantContents(ir.getSymbolTable(), du, node, s.getException(), this); - for (int i = 0; i < ik.length; i++) { - system.findOrCreateIndexForInstanceKey(ik[i]); - assignInstanceToCatch(exceptionVar, catchClasses, ik[i]); - } - } else { - addAssignmentsForCatchPointerKey(exceptionVar, catchClasses, e); - } - } - - // Account for those exceptions for which we do not actually have a - // points-to set for - // the pei, but just instance keys - Collection types = pei.getExceptionTypes(); - if (types != null) { - for (Iterator it2 = types.iterator(); it2.hasNext();) { - TypeReference type = it2.next(); - if (type != null) { - InstanceKey ik = getInstanceKeyForPEI(node, peiLoc, type, instanceKeyFactory); - if (ik == null) { - continue; - } - assert ik instanceof ConcreteTypeKey : "uh oh: need to implement getCaughtException constraints for instance " + ik; - ConcreteTypeKey ck = (ConcreteTypeKey) ik; - IClass klass = ck.getType(); - if (PropagationCallGraphBuilder.catches(catchClasses, klass, cha)) { - system.newConstraint(exceptionVar, getInstanceKeyForPEI(node, peiLoc, type, instanceKeyFactory)); - } - } - } - } - } - } - - /** - * @return true iff there's a unique catch block which catches all exceptions thrown by a certain call site. - */ - protected static boolean hasUniqueCatchBlock(SSAAbstractInvokeInstruction call, IR ir) { - ISSABasicBlock[] bb = ir.getBasicBlocksForCall(call.getCallSite()); - if (bb.length == 1) { - Iterator it = ir.getControlFlowGraph().getExceptionalSuccessors(bb[0]).iterator(); - // check that there's exactly one element in the iterator - if (it.hasNext()) { - it.next(); - return (!it.hasNext()); - } - } - return false; - } - - /** - * precondition: hasUniqueCatchBlock(call,node,cg) - * - * @return the unique pointer key which catches the exceptions thrown by a call - * @throws IllegalArgumentException if ir == null - * @throws IllegalArgumentException if call == null - */ - public PointerKey getUniqueCatchKey(SSAAbstractInvokeInstruction call, IR ir, CGNode node) throws IllegalArgumentException, - IllegalArgumentException { - if (call == null) { - throw new IllegalArgumentException("call == null"); - } - if (ir == null) { - throw new IllegalArgumentException("ir == null"); - } - ISSABasicBlock[] bb = ir.getBasicBlocksForCall(call.getCallSite()); - assert bb.length == 1; - SSACFG.BasicBlock cb = (BasicBlock) ir.getControlFlowGraph().getExceptionalSuccessors(bb[0]).iterator().next(); - if (cb.isExitBlock()) { - return getPointerKeyForExceptionalReturnValue(node); - } else { - SSACFG.ExceptionHandlerBasicBlock ehbb = (ExceptionHandlerBasicBlock) cb; - SSAGetCaughtExceptionInstruction ci = ehbb.getCatchInstruction(); - return getPointerKeyForLocal(node, ci.getDef()); - } - } - - /** - * @return a List of Instructions that may transfer control to bb via an exceptional edge - * @throws IllegalArgumentException if ir is null - */ - public static List getIncomingPEIs(IR ir, ISSABasicBlock bb) { - if (ir == null) { - throw new IllegalArgumentException("ir is null"); - } - if (DEBUG) { - System.err.println("getIncomingPEIs " + bb); - } - ControlFlowGraph g = ir.getControlFlowGraph(); - List result = new ArrayList(g.getPredNodeCount(bb)); - for (Iterator it = g.getPredNodes(bb); it.hasNext();) { - BasicBlock pred = (BasicBlock) it.next(); - if (DEBUG) { - System.err.println("pred: " + pred); - } - if (pred.isEntryBlock()) - continue; - int index = pred.getLastInstructionIndex(); - SSAInstruction pei = ir.getInstructions()[index]; - // Note: pei might be null if pred is unreachable. - // TODO: consider pruning CFG for unreachable blocks. - if (pei != null && pei.isPEI()) { - if (DEBUG) { - System.err.println("PEI: " + pei + " index " + index + " PC " + g.getProgramCounter(index)); - } - result.add(new ProgramCounter(g.getProgramCounter(index))); - } - } - return result; - } - - /** - * A visitor that generates constraints based on statements in SSA form. - */ - protected static class ConstraintVisitor extends SSAInstruction.Visitor { - - /** - * The governing call graph builder. This field is used instead of an inner class in order to allow more flexible reuse of this - * visitor in subclasses - */ - protected final SSAPropagationCallGraphBuilder builder; - - /** - * The node whose statements we are currently traversing - */ - protected final CGNode node; - - /** - * The governing call graph. - */ - private final ExplicitCallGraph callGraph; - - /** - * The governing IR - */ - protected final IR ir; - - /** - * The governing propagation system, into which constraints are added - */ - protected final PropagationSystem system; - - /** - * The basic block currently being processed - */ - protected ISSABasicBlock basicBlock; - - /** - * Governing symbol table - */ - protected final SymbolTable symbolTable; - - /** - * Def-use information - */ - protected final DefUse du; - - public ConstraintVisitor(SSAPropagationCallGraphBuilder builder, CGNode node) { - this.builder = builder; - this.node = node; - - this.callGraph = builder.getCallGraph(); - - this.system = builder.getPropagationSystem(); - - this.ir = builder.getCFAContextInterpreter().getIR(node); - this.symbolTable = this.ir.getSymbolTable(); - - this.du = builder.getCFAContextInterpreter().getDU(node); - - assert symbolTable != null; - } - - protected SSAPropagationCallGraphBuilder getBuilder() { - return builder; - } - - protected AnalysisOptions getOptions() { - return builder.options; - } - - protected AnalysisCache getAnalysisCache() { - return builder.getAnalysisCache(); - } - - public PointerKey getPointerKeyForLocal(int valueNumber) { - return getBuilder().getPointerKeyForLocal(node, valueNumber); - } - - public FilteredPointerKey getFilteredPointerKeyForLocal(int valueNumber, FilteredPointerKey.TypeFilter filter) { - return getBuilder().getFilteredPointerKeyForLocal(node, valueNumber, filter); - } - - public PointerKey getPointerKeyForReturnValue() { - return getBuilder().getPointerKeyForReturnValue(node); - } - - public PointerKey getPointerKeyForExceptionalReturnValue() { - return getBuilder().getPointerKeyForExceptionalReturnValue(node); - } - - public PointerKey getPointerKeyForStaticField(IField f) { - return getBuilder().getPointerKeyForStaticField(f); - } - - public PointerKey getPointerKeyForInstanceField(InstanceKey I, IField f) { - return getBuilder().getPointerKeyForInstanceField(I, f); - } - - public PointerKey getPointerKeyForArrayContents(InstanceKey I) { - return getBuilder().getPointerKeyForArrayContents(I); - } - - public InstanceKey getInstanceKeyForAllocation(NewSiteReference allocation) { - return getBuilder().getInstanceKeyForAllocation(node, allocation); - } - - public InstanceKey getInstanceKeyForMultiNewArray(NewSiteReference allocation, int dim) { - return getBuilder().getInstanceKeyForMultiNewArray(node, allocation, dim); - } - - public InstanceKey getInstanceKeyForConstant(T S) { - TypeReference type = node.getMethod().getDeclaringClass().getClassLoader().getLanguage().getConstantType(S); - return getBuilder().getInstanceKeyForConstant(type, S); - } - - public InstanceKey getInstanceKeyForPEI(ProgramCounter instr, TypeReference type) { - return getBuilder().getInstanceKeyForPEI(node, instr, type); - } - - public InstanceKey getInstanceKeyForClassObject(TypeReference type) { - return getBuilder().getInstanceKeyForClassObject(type); - } - - public CGNode getTargetForCall(CGNode caller, CallSiteReference site, IClass recv, InstanceKey iKey[]) { - return getBuilder().getTargetForCall(caller, site, recv, iKey); - } - - protected boolean contentsAreInvariant(SymbolTable symbolTable, DefUse du, int valueNumber) { - return getBuilder().contentsAreInvariant(symbolTable, du, valueNumber); - } - - protected boolean contentsAreInvariant(SymbolTable symbolTable, DefUse du, int valueNumber[]) { - return getBuilder().contentsAreInvariant(symbolTable, du, valueNumber); - } - - protected InstanceKey[] getInvariantContents(int valueNumber) { - return getInvariantContents(ir.getSymbolTable(), du, node, valueNumber); - } - - protected InstanceKey[] getInvariantContents(SymbolTable symbolTable, DefUse du, CGNode node, int valueNumber) { - return getBuilder().getInvariantContents(symbolTable, du, node, valueNumber, getBuilder()); - } - - protected IClassHierarchy getClassHierarchy() { - return getBuilder().getClassHierarchy(); - } - - protected boolean hasNoInterestingUses(int vn) { - return getBuilder().hasNoInterestingUses(node, vn, du); - } - - protected boolean isRootType(IClass klass) { - return getBuilder().isRootType(klass); - } - - /* - * @see com.ibm.wala.ssa.SSAInstruction.Visitor#visitArrayLoad(com.ibm.wala.ssa.SSAArrayLoadInstruction) - */ - @Override - public void visitArrayLoad(SSAArrayLoadInstruction instruction) { - // skip arrays of primitive type - if (instruction.typeIsPrimitive()) { - return; - } - doVisitArrayLoad(instruction.getDef(), instruction.getArrayRef()); - } - - protected void doVisitArrayLoad(int def, int arrayRef) { - PointerKey result = getPointerKeyForLocal(def); - PointerKey arrayRefPtrKey = getPointerKeyForLocal(arrayRef); - if (hasNoInterestingUses(def)) { - system.recordImplicitPointsToSet(result); - } else { - if (contentsAreInvariant(symbolTable, du, arrayRef)) { - system.recordImplicitPointsToSet(arrayRefPtrKey); - InstanceKey[] ik = getInvariantContents(arrayRef); - for (int i = 0; i < ik.length; i++) { - if (!representsNullType(ik[i])) { - system.findOrCreateIndexForInstanceKey(ik[i]); - PointerKey p = getPointerKeyForArrayContents(ik[i]); - if (p == null) { - } else { - system.newConstraint(result, assignOperator, p); - } - } - } - } else { - assert !system.isUnified(result); - assert !system.isUnified(arrayRefPtrKey); - system.newSideEffect(getBuilder().new ArrayLoadOperator(system.findOrCreatePointsToSet(result)), arrayRefPtrKey); - } - } - } - - /* - * @see com.ibm.wala.ssa.SSAInstruction.Visitor#visitArrayStore(com.ibm.wala.ssa.SSAArrayStoreInstruction) - */ - public void doVisitArrayStore(int arrayRef, int value) { - // (requires the creation of assign constraints as - // the set points-to(a[]) grows.) - PointerKey valuePtrKey = getPointerKeyForLocal(value); - PointerKey arrayRefPtrKey = getPointerKeyForLocal(arrayRef); - // if (!supportFullPointerFlowGraph && - // contentsAreInvariant(instruction.getArrayRef())) { - if (contentsAreInvariant(symbolTable, du, arrayRef)) { - system.recordImplicitPointsToSet(arrayRefPtrKey); - InstanceKey[] ik = getInvariantContents(arrayRef); - - for (int i = 0; i < ik.length; i++) { - if (!representsNullType(ik[i]) && !(ik[i] instanceof ZeroLengthArrayInNode)) { - system.findOrCreateIndexForInstanceKey(ik[i]); - PointerKey p = getPointerKeyForArrayContents(ik[i]); - IClass contents = ((ArrayClass) ik[i].getConcreteType()).getElementClass(); - if (p == null) { - } else { - if (contentsAreInvariant(symbolTable, du, value)) { - system.recordImplicitPointsToSet(valuePtrKey); - InstanceKey[] vk = getInvariantContents(value); - for (int j = 0; j < vk.length; j++) { - system.findOrCreateIndexForInstanceKey(vk[j]); - if (vk[j].getConcreteType() != null) { - if (getClassHierarchy().isAssignableFrom(contents, vk[j].getConcreteType())) { - system.newConstraint(p, vk[j]); - } - } - } - } else { - if (isRootType(contents)) { - system.newConstraint(p, assignOperator, valuePtrKey); - } else { - system.newConstraint(p, getBuilder().filterOperator, valuePtrKey); - } - } - } - } - } - } else { - if (contentsAreInvariant(symbolTable, du, value)) { - system.recordImplicitPointsToSet(valuePtrKey); - InstanceKey[] ik = getInvariantContents(value); - for (int i = 0; i < ik.length; i++) { - system.findOrCreateIndexForInstanceKey(ik[i]); - assert !system.isUnified(arrayRefPtrKey); - system.newSideEffect(getBuilder().new InstanceArrayStoreOperator(ik[i]), arrayRefPtrKey); - } - } else { - system.newSideEffect(getBuilder().new ArrayStoreOperator(system.findOrCreatePointsToSet(valuePtrKey)), arrayRefPtrKey); - } - } - } - - @Override - public void visitArrayStore(SSAArrayStoreInstruction instruction) { - // skip arrays of primitive type - if (instruction.typeIsPrimitive()) { - return; - } - doVisitArrayStore(instruction.getArrayRef(), instruction.getValue()); - } - - /* - * @see com.ibm.wala.ssa.SSAInstruction.Visitor#visitCheckCast(com.ibm.wala.ssa.SSACheckCastInstruction) - */ - @Override - public void visitCheckCast(SSACheckCastInstruction instruction) { - - boolean isRoot = false; - Set types = HashSetFactory.make(); - - for(TypeReference t : instruction.getDeclaredResultTypes()) { - IClass cls = getClassHierarchy().lookupClass(t); - if (cls == null) { - Warnings.add(CheckcastFailure.create(t)); - return; - } else { - if (isRootType(cls)) { - isRoot = true; - } - types.add(cls); - } - } - - PointerKey result = getFilteredPointerKeyForLocal(instruction.getResult(), new FilteredPointerKey.MultipleClassesFilter(types.toArray(new IClass[ types.size() ]))); - PointerKey value = getPointerKeyForLocal(instruction.getVal()); - - if (hasNoInterestingUses(instruction.getDef())) { - system.recordImplicitPointsToSet(result); - } else { - if (contentsAreInvariant(symbolTable, du, instruction.getVal())) { - system.recordImplicitPointsToSet(value); - InstanceKey[] ik = getInvariantContents(instruction.getVal()); - for(TypeReference t : instruction.getDeclaredResultTypes()) { - IClass cls = getClassHierarchy().lookupClass(t); - - if (cls.isInterface()) { - for (int i = 0; i < ik.length; i++) { - system.findOrCreateIndexForInstanceKey(ik[i]); - if (getClassHierarchy().implementsInterface(ik[i].getConcreteType(), cls)) { - system.newConstraint(result, ik[i]); - } - } - } else { - for (int i = 0; i < ik.length; i++) { - system.findOrCreateIndexForInstanceKey(ik[i]); - if (getClassHierarchy().isSubclassOf(ik[i].getConcreteType(), cls)) { - system.newConstraint(result, ik[i]); - } - } - } - } - } else { - if (isRoot) { - system.newConstraint(result, assignOperator, value); - } else { - system.newConstraint(result, getBuilder().filterOperator, value); - } - } - } - } - - /* - * @see com.ibm.wala.ssa.SSAInstruction.Visitor#visitReturn(com.ibm.wala.ssa.SSAReturnInstruction) - */ - @Override - public void visitReturn(SSAReturnInstruction instruction) { - - // skip returns of primitive type - if (instruction.returnsPrimitiveType() || instruction.returnsVoid()) { - return; - } - if (DEBUG) { - System.err.println("visitReturn: " + instruction); - } - - PointerKey returnValue = getPointerKeyForReturnValue(); - PointerKey result = getPointerKeyForLocal(instruction.getResult()); - if (contentsAreInvariant(symbolTable, du, instruction.getResult())) { - system.recordImplicitPointsToSet(result); - InstanceKey[] ik = getInvariantContents(instruction.getResult()); - for (int i = 0; i < ik.length; i++) { - if (DEBUG) { - System.err.println("invariant contents: " + returnValue + " " + ik[i]); - } - system.newConstraint(returnValue, ik[i]); - } - } else { - system.newConstraint(returnValue, assignOperator, result); - } - } - - /* - * @see com.ibm.wala.ssa.SSAInstruction.Visitor#visitGet(com.ibm.wala.ssa.SSAGetInstruction) - */ - @Override - public void visitGet(SSAGetInstruction instruction) { - visitGetInternal(instruction.getDef(), instruction.getRef(), instruction.isStatic(), instruction.getDeclaredField()); - } - - protected void visitGetInternal(int lval, int ref, boolean isStatic, FieldReference field) { - if (DEBUG) { - System.err.println("visitGet " + field); - } - - // skip getfields of primitive type (optimisation) - if (field.getFieldType().isPrimitiveType()) { - return; - } - PointerKey def = getPointerKeyForLocal(lval); - assert def != null; - - IField f = getClassHierarchy().resolveField(field); - if (f == null && callGraph.getFakeRootNode().getMethod().getDeclaringClass().getReference().equals(field.getDeclaringClass())) { - f = callGraph.getFakeRootNode().getMethod().getDeclaringClass().getField(field.getName()); - } - - if (f == null) { - return; - } - - if (hasNoInterestingUses(lval)) { - system.recordImplicitPointsToSet(def); - } else { - if (isStatic) { - PointerKey fKey = getPointerKeyForStaticField(f); - system.newConstraint(def, assignOperator, fKey); - IClass klass = getClassHierarchy().lookupClass(field.getDeclaringClass()); - if (klass == null) { - } else { - // side effect of getstatic: may call class initializer - if (DEBUG) { - System.err.println("getstatic call class init " + klass); - } - processClassInitializer(klass); - } - } else { - PointerKey refKey = getPointerKeyForLocal(ref); - // if (!supportFullPointerFlowGraph && - // contentsAreInvariant(ref)) { - if (contentsAreInvariant(symbolTable, du, ref)) { - system.recordImplicitPointsToSet(refKey); - InstanceKey[] ik = getInvariantContents(ref); - for (int i = 0; i < ik.length; i++) { - if (!representsNullType(ik[i])) { - system.findOrCreateIndexForInstanceKey(ik[i]); - PointerKey p = getPointerKeyForInstanceField(ik[i], f); - system.newConstraint(def, assignOperator, p); - } - } - } else { - system.newSideEffect(getBuilder().new GetFieldOperator(f, system.findOrCreatePointsToSet(def)), refKey); - } - } - } - } - - /* - * @see com.ibm.wala.ssa.Instruction.Visitor#visitPut(com.ibm.wala.ssa.PutInstruction) - */ - @Override - public void visitPut(SSAPutInstruction instruction) { - visitPutInternal(instruction.getVal(), instruction.getRef(), instruction.isStatic(), instruction.getDeclaredField()); - } - - public void visitPutInternal(int rval, int ref, boolean isStatic, FieldReference field) { - - if (DEBUG) { - System.err.println("visitPut " + field); - } - - // skip putfields of primitive type - if (field.getFieldType().isPrimitiveType()) { - return; - } - IField f = getClassHierarchy().resolveField(field); - if (f == null) { - if (DEBUG) { - System.err.println("Could not resolve field " + field); - } - Warnings.add(FieldResolutionFailure.create(field)); - return; - } - assert isStatic || !symbolTable.isStringConstant(ref) : "put to string constant shouldn't be allowed?"; - if (isStatic) { - processPutStatic(rval, field, f); - } else { - processPutField(rval, ref, f); - } - } - - private void processPutField(int rval, int ref, IField f) { - assert !f.getFieldTypeReference().isPrimitiveType(); - PointerKey refKey = getPointerKeyForLocal(ref); - PointerKey rvalKey = getPointerKeyForLocal(rval); - // if (!supportFullPointerFlowGraph && - // contentsAreInvariant(rval)) { - if (contentsAreInvariant(symbolTable, du, rval)) { - system.recordImplicitPointsToSet(rvalKey); - InstanceKey[] ik = getInvariantContents(rval); - if (contentsAreInvariant(symbolTable, du, ref)) { - system.recordImplicitPointsToSet(refKey); - InstanceKey[] refk = getInvariantContents(ref); - for (int j = 0; j < refk.length; j++) { - if (!representsNullType(refk[j])) { - system.findOrCreateIndexForInstanceKey(refk[j]); - PointerKey p = getPointerKeyForInstanceField(refk[j], f); - for (int i = 0; i < ik.length; i++) { - system.newConstraint(p, ik[i]); - } - } - } - } else { - for (int i = 0; i < ik.length; i++) { - system.findOrCreateIndexForInstanceKey(ik[i]); - system.newSideEffect(getBuilder().new InstancePutFieldOperator(f, ik[i]), refKey); - } - } - } else { - if (contentsAreInvariant(symbolTable, du, ref)) { - system.recordImplicitPointsToSet(refKey); - InstanceKey[] refk = getInvariantContents(ref); - for (int j = 0; j < refk.length; j++) { - if (!representsNullType(refk[j])) { - system.findOrCreateIndexForInstanceKey(refk[j]); - PointerKey p = getPointerKeyForInstanceField(refk[j], f); - system.newConstraint(p, assignOperator, rvalKey); - } - } - } else { - if (DEBUG) { - System.err.println("adding side effect " + f); - } - system.newSideEffect(getBuilder().new PutFieldOperator(f, system.findOrCreatePointsToSet(rvalKey)), refKey); - } - } - } - - private void processPutStatic(int rval, FieldReference field, IField f) { - PointerKey fKey = getPointerKeyForStaticField(f); - PointerKey rvalKey = getPointerKeyForLocal(rval); - - // if (!supportFullPointerFlowGraph && - // contentsAreInvariant(rval)) { - if (contentsAreInvariant(symbolTable, du, rval)) { - system.recordImplicitPointsToSet(rvalKey); - InstanceKey[] ik = getInvariantContents(rval); - for (int i = 0; i < ik.length; i++) { - system.newConstraint(fKey, ik[i]); - } - } else { - system.newConstraint(fKey, assignOperator, rvalKey); - } - if (DEBUG) { - System.err.println("visitPut class init " + field.getDeclaringClass() + " " + field); - } - // side effect of putstatic: may call class initializer - IClass klass = getClassHierarchy().lookupClass(field.getDeclaringClass()); - if (klass == null) { - Warnings.add(FieldResolutionFailure.create(field)); - } else { - processClassInitializer(klass); - } - } - - /* - * @see com.ibm.wala.ssa.Instruction.Visitor#visitInvoke(com.ibm.wala.ssa.InvokeInstruction) - */ - @Override - public void visitInvoke(SSAInvokeInstruction instruction) { - visitInvokeInternal(instruction, new DefaultInvariantComputer()); - } - - protected void visitInvokeInternal(final SSAAbstractInvokeInstruction instruction, InvariantComputer invs) { - if (DEBUG) { - System.err.println("visitInvoke: " + instruction); - } - - PointerKey uniqueCatch = null; - if (hasUniqueCatchBlock(instruction, ir)) { - uniqueCatch = getBuilder().getUniqueCatchKey(instruction, ir, node); - } - - InstanceKey[][] invariantParameters = invs.computeInvariantParameters(instruction); - if (instruction.getCallSite().isStatic()) { - for (CGNode n : getBuilder().getTargetsForCall(node, instruction, invariantParameters)) { - getBuilder().processResolvedCall(node, instruction, n, invariantParameters, uniqueCatch); - if (DEBUG) { - System.err.println("visitInvoke class init " + n); - } - - // side effect of invoke: may call class initializer - processClassInitializer(n.getMethod().getDeclaringClass()); - } - } else { - // Add a side effect that will fire when we determine a value - // for a dispatch parameter. This side effect will create a new node - // and new constraints based on the new callee context. - IntSet params = getBuilder().getContextSelector().getRelevantParameters(node, instruction.getCallSite()); - if (! params.contains(0)) { - params = IntSetUtil.makeMutableCopy(params); - ((MutableIntSet)params).add(0); - } - final int vns[] = new int[ params.size() ]; - params.foreach(new IntSetAction() { - private int i = 0; - public void act(int x) { - vns[i++] = instruction.getUse(x); - } - }); - - if (contentsAreInvariant(symbolTable, du, vns)) { - for(CGNode n : getBuilder().getTargetsForCall(node, instruction, invariantParameters)) { - getBuilder().processResolvedCall(node, instruction, n, invariantParameters, uniqueCatch); - // side effect of invoke: may call class initializer - processClassInitializer(n.getMethod().getDeclaringClass()); - } - } else { - if (DEBUG) { - System.err.println("Add side effect, dispatch to " + instruction + " for " + params); - } - - final List pks = new ArrayList(params.size()); - params.foreach(new IntSetAction() { - public void act(int x) { - if (!contentsAreInvariant(symbolTable, du, instruction.getUse(x))) { - pks.add(getBuilder().getPointerKeyForLocal(node, instruction.getUse(x))); - } - } - }); - - DispatchOperator dispatchOperator = getBuilder().new DispatchOperator(instruction, node, - invariantParameters, uniqueCatch, params); - system.newSideEffect(dispatchOperator, pks.toArray(new PointerKey[pks.size()])); - } - } - } - - /* - * @see com.ibm.wala.ssa.Instruction.Visitor#visitNew(com.ibm.wala.ssa.NewInstruction) - */ - @Override - public void visitNew(SSANewInstruction instruction) { - InstanceKey iKey = getInstanceKeyForAllocation(instruction.getNewSite()); - - if (iKey == null) { - // something went wrong. I hope someone raised a warning. - return; - } - PointerKey def = getPointerKeyForLocal(instruction.getDef()); - IClass klass = iKey.getConcreteType(); - - if (DEBUG) { - System.err.println("visitNew: " + instruction + " " + iKey + " " + system.findOrCreateIndexForInstanceKey(iKey)); - } - - if (klass == null) { - if (DEBUG) { - System.err.println("Resolution failure: " + instruction); - } - return; - } - - if (!contentsAreInvariant(symbolTable, du, instruction.getDef())) { - system.newConstraint(def, iKey); - } else { - system.findOrCreateIndexForInstanceKey(iKey); - system.recordImplicitPointsToSet(def); - } - - // side effect of new: may call class initializer - if (DEBUG) { - System.err.println("visitNew call clinit: " + klass); - } - processClassInitializer(klass); - - // add instance keys and pointer keys for array contents - int dim = 0; - InstanceKey lastInstance = iKey; - while (klass != null && klass.isArrayClass()) { - klass = ((ArrayClass) klass).getElementClass(); - // klass == null means it's a primitive - if (klass != null && klass.isArrayClass()) { - if (instruction.getNumberOfUses() <= (dim + 1)) { - break; - } - int sv = instruction.getUse(dim + 1); - if (ir.getSymbolTable().isIntegerConstant(sv)) { - Integer c = (Integer) ir.getSymbolTable().getConstantValue(sv); - if (c.intValue() == 0) { - break; - } - } - InstanceKey ik = getInstanceKeyForMultiNewArray(instruction.getNewSite(), dim); - PointerKey pk = getPointerKeyForArrayContents(lastInstance); - if (DEBUG_MULTINEWARRAY) { - System.err.println("multinewarray constraint: "); - System.err.println(" pk: " + pk); - System.err.println(" ik: " + system.findOrCreateIndexForInstanceKey(ik) + " concrete type " + ik.getConcreteType() - + " is " + ik); - System.err.println(" klass:" + klass); - } - system.newConstraint(pk, ik); - lastInstance = ik; - dim++; - } - } - } - - /* - * @see com.ibm.wala.ssa.Instruction.Visitor#visitThrow(com.ibm.wala.ssa.ThrowInstruction) - */ - @Override - public void visitThrow(SSAThrowInstruction instruction) { - // don't do anything: we handle exceptional edges - // in a separate pass - } - - /* - * @see com.ibm.wala.ssa.Instruction.Visitor#visitGetCaughtException(com.ibm.wala.ssa.GetCaughtExceptionInstruction) - */ - @Override - public void visitGetCaughtException(SSAGetCaughtExceptionInstruction instruction) { - List peis = getIncomingPEIs(ir, getBasicBlock()); - PointerKey def = getPointerKeyForLocal(instruction.getDef()); - // SJF: we don't optimize based on dead catch blocks yet ... it's a little - // tricky due interaction with the SINGLE_USE optimization which directly - // shoves exceptional return values from calls into exception vars. - // it may not be worth doing this. - // if (hasNoInterestingUses(instruction.getDef(), du)) { - // solver.recordImplicitPointsToSet(def); - // } else { - Set types = getCaughtExceptionTypes(instruction, ir); - getBuilder().addExceptionDefConstraints(ir, du, node, peis, def, types); - // } - } - - /** - * TODO: What is this doing? Document me! - */ - private int booleanConstantTest(SSAConditionalBranchInstruction c, int v) { - int result = 0; - - // right for OPR_eq - if ((symbolTable.isZeroOrFalse(c.getUse(0)) && c.getUse(1) == v) - || (symbolTable.isZeroOrFalse(c.getUse(1)) && c.getUse(0) == v)) { - result = -1; - } else if ((symbolTable.isOneOrTrue(c.getUse(0)) && c.getUse(1) == v) - || (symbolTable.isOneOrTrue(c.getUse(1)) && c.getUse(0) == v)) { - result = 1; - } - - if (c.getOperator() == ConditionalBranchInstruction.Operator.NE) { - result = -result; - } - - return result; - } - - private int nullConstantTest(SSAConditionalBranchInstruction c, int v) { - if ((symbolTable.isNullConstant(c.getUse(0)) && c.getUse(1) == v) - || (symbolTable.isNullConstant(c.getUse(1)) && c.getUse(0) == v)) { - if (c.getOperator() == ConditionalBranchInstruction.Operator.EQ) { - return 1; - } else { - return -1; - } - } else { - return 0; - } - } - - @Override - public void visitPhi(SSAPhiInstruction instruction) { - if (ir.getMethod() instanceof AbstractRootMethod) { - PointerKey dst = getPointerKeyForLocal(instruction.getDef()); - if (hasNoInterestingUses(instruction.getDef())) { - system.recordImplicitPointsToSet(dst); - } else { - for (int i = 0; i < instruction.getNumberOfUses(); i++) { - PointerKey use = getPointerKeyForLocal(instruction.getUse(i)); - if (contentsAreInvariant(symbolTable, du, instruction.getUse(i))) { - system.recordImplicitPointsToSet(use); - InstanceKey[] ik = getInvariantContents(instruction.getUse(i)); - for (int j = 0; j < ik.length; j++) { - system.newConstraint(dst, ik[j]); - } - } else { - system.newConstraint(dst, assignOperator, use); - } - } - } - } - } - - /* - * @see com.ibm.wala.ssa.SSAInstruction.Visitor#visitPi(com.ibm.wala.ssa.SSAPiInstruction) - */ - @Override - public void visitPi(SSAPiInstruction instruction) { - int dir; - - if (hasNoInterestingUses(instruction.getDef())) { - PointerKey dst = getPointerKeyForLocal(instruction.getDef()); - system.recordImplicitPointsToSet(dst); - } else { - ControlFlowGraph cfg = ir.getControlFlowGraph(); - if (com.ibm.wala.cfg.Util.endsWithConditionalBranch(cfg, getBasicBlock()) && cfg.getSuccNodeCount(getBasicBlock()) == 2) { - SSAConditionalBranchInstruction cond = (SSAConditionalBranchInstruction) com.ibm.wala.cfg.Util.getLastInstruction(cfg, - getBasicBlock()); - SSAInstruction cause = instruction.getCause(); - BasicBlock target = (BasicBlock) cfg.getNode(instruction.getSuccessor()); - - if ((cause instanceof SSAInstanceofInstruction)) { - int direction = booleanConstantTest(cond, cause.getDef()); - if (direction != 0) { - TypeReference type = ((SSAInstanceofInstruction) cause).getCheckedType(); - IClass cls = getClassHierarchy().lookupClass(type); - if (cls == null) { - PointerKey dst = getPointerKeyForLocal(instruction.getDef()); - addPiAssignment(dst, instruction.getVal()); - } else { - PointerKey dst = getFilteredPointerKeyForLocal(instruction.getDef(), new FilteredPointerKey.SingleClassFilter(cls)); - PointerKey src = getPointerKeyForLocal(instruction.getVal()); - if ((target == com.ibm.wala.cfg.Util.getTakenSuccessor(cfg, getBasicBlock()) && direction == 1) - || (target == com.ibm.wala.cfg.Util.getNotTakenSuccessor(cfg, getBasicBlock()) && direction == -1)) { - system.newConstraint(dst, getBuilder().filterOperator, src); - } else { - system.newConstraint(dst, getBuilder().inverseFilterOperator, src); - } - } - } - } else if ((dir = nullConstantTest(cond, instruction.getVal())) != 0) { - if ((target == com.ibm.wala.cfg.Util.getTakenSuccessor(cfg, getBasicBlock()) && dir == -1) - || (target == com.ibm.wala.cfg.Util.getNotTakenSuccessor(cfg, getBasicBlock()) && dir == 1)) { - PointerKey dst = getPointerKeyForLocal(instruction.getDef()); - addPiAssignment(dst, instruction.getVal()); - } - } else { - PointerKey dst = getPointerKeyForLocal(instruction.getDef()); - addPiAssignment(dst, instruction.getVal()); - } - } else { - PointerKey dst = getPointerKeyForLocal(instruction.getDef()); - addPiAssignment(dst, instruction.getVal()); - } - } - } - - /** - * Add a constraint to the system indicating that the contents of local src flows to dst, with no special type filter. - */ - private void addPiAssignment(PointerKey dst, int src) { - PointerKey srcKey = getPointerKeyForLocal(src); - if (contentsAreInvariant(symbolTable, du, src)) { - system.recordImplicitPointsToSet(srcKey); - InstanceKey[] ik = getInvariantContents(src); - for (int j = 0; j < ik.length; j++) { - system.newConstraint(dst, ik[j]); - } - } else { - system.newConstraint(dst, assignOperator, srcKey); - } - - } - - public ISSABasicBlock getBasicBlock() { - return basicBlock; - } - - /** - * The calling loop must call this in each iteration! - */ - public void setBasicBlock(ISSABasicBlock block) { - basicBlock = block; - } - - protected interface InvariantComputer { - - InstanceKey[][] computeInvariantParameters(SSAAbstractInvokeInstruction call); - - } - - public class DefaultInvariantComputer implements InvariantComputer { - /** - * Side effect: records invariant parameters as implicit points-to-sets. - * - * @return if non-null, then result[i] holds the set of instance keys which may be passed as the ith parameter. (which must be - * invariant) - */ - public InstanceKey[][] computeInvariantParameters(SSAAbstractInvokeInstruction call) { - InstanceKey[][] constParams = null; - for (int i = 0; i < call.getNumberOfUses(); i++) { - // not sure how getUse(i) <= 0 .. dead code? - // TODO: investigate - if (call.getUse(i) > 0) { - if (contentsAreInvariant(symbolTable, du, call.getUse(i))) { - system.recordImplicitPointsToSet(getPointerKeyForLocal(call.getUse(i))); - if (constParams == null) { - constParams = new InstanceKey[call.getNumberOfUses()][]; - } - constParams[i] = getInvariantContents(call.getUse(i)); - for (int j = 0; j < constParams[i].length; j++) { - system.findOrCreateIndexForInstanceKey(constParams[i][j]); - } - } - } - } - return constParams; - } - } - - @Override - public void visitLoadMetadata(SSALoadMetadataInstruction instruction) { - PointerKey def = getPointerKeyForLocal(instruction.getDef()); - assert instruction.getType() == TypeReference.JavaLangClass; - InstanceKey iKey = getInstanceKeyForClassObject((TypeReference) instruction.getToken()); - IClass klass = getClassHierarchy().lookupClass((TypeReference) instruction.getToken()); - if (klass != null) { - processClassInitializer(klass); - } - - if (!contentsAreInvariant(symbolTable, du, instruction.getDef())) { - system.newConstraint(def, iKey); - } else { - system.findOrCreateIndexForInstanceKey(iKey); - system.recordImplicitPointsToSet(def); - } - } - - /** - * TODO: lift most of this logic to PropagationCallGraphBuilder - * - * Add a call to the class initializer from the root method. - */ - private void processClassInitializer(IClass klass) { - - assert klass != null; - - if (!getBuilder().getOptions().getHandleStaticInit()) { - return; - } - - if (getBuilder().clinitVisited.contains(klass)) { - return; - } - getBuilder().clinitVisited.add(klass); - - if (klass.getClassInitializer() != null) { - if (DEBUG) { - System.err.println("process class initializer for " + klass); - } - - // add an invocation from the fake root method to the - AbstractRootMethod fakeWorldClinitMethod = (AbstractRootMethod) callGraph.getFakeWorldClinitNode().getMethod(); - MethodReference m = klass.getClassInitializer().getReference(); - CallSiteReference site = CallSiteReference.make(1, m, IInvokeInstruction.Dispatch.STATIC); - IMethod targetMethod = getOptions().getMethodTargetSelector().getCalleeTarget(callGraph.getFakeRootNode(), site, null); - if (targetMethod != null) { - CGNode target = getTargetForCall(callGraph.getFakeRootNode(), site, null, null); - if (target != null && callGraph.getPredNodeCount(target) == 0) { - SSAAbstractInvokeInstruction s = fakeWorldClinitMethod.addInvocation(new int[0], site); - PointerKey uniqueCatch = getBuilder().getPointerKeyForExceptionalReturnValue(callGraph.getFakeRootNode()); - getBuilder().processResolvedCall(callGraph.getFakeWorldClinitNode(), s, target, null, uniqueCatch); - } - } - } - - IClass sc = klass.getSuperclass(); - if (sc != null) { - processClassInitializer(sc); - } - } - } - - /** - * Add constraints for a call site after we have computed a reachable target for the dispatch - * - * Side effect: add edge to the call graph. - * - * @param instruction - * @param constParams if non-null, then constParams[i] holds the set of instance keys that are passed as param i, or null if param - * i is not invariant - * @param uniqueCatchKey if non-null, then this is the unique PointerKey that catches all exceptions from this call site. - */ - @SuppressWarnings("deprecation") - private void processResolvedCall(CGNode caller, SSAAbstractInvokeInstruction instruction, CGNode target, - InstanceKey[][] constParams, PointerKey uniqueCatchKey) { - - if (DEBUG) { - System.err.println("processResolvedCall: " + caller + " ," + instruction + " , " + target); - } - - if (DEBUG) { - System.err.println("addTarget: " + caller + " ," + instruction + " , " + target); - } - caller.addTarget(instruction.getCallSite(), target); - - if (FakeRootMethod.isFakeRootMethod(caller.getMethod().getReference())) { - if (entrypointCallSites.contains(instruction.getCallSite())) { - callGraph.registerEntrypoint(target); - } - } - - if (!haveAlreadyVisited(target)) { - markDiscovered(target); - } - - processCallingConstraints(caller, instruction, target, constParams, uniqueCatchKey); - } - - protected void processCallingConstraints(CGNode caller, SSAAbstractInvokeInstruction instruction, CGNode target, - InstanceKey[][] constParams, PointerKey uniqueCatchKey) { - // TODO: i'd like to enable this optimization, but it's a little tricky - // to recover the implicit points-to sets with recursion. TODO: don't - // be lazy and code the recursive logic to enable this. - // if (hasNoInstructions(target)) { - // // record points-to sets for formals implicitly .. computed on - // // demand. - // // TODO: generalize this by using hasNoInterestingUses on parameters. - // // however .. have to be careful to cache results in that case ... don't - // // want - // // to recompute du each time we process a call to Object. ! - // for (int i = 0; i < instruction.getNumberOfUses(); i++) { - // // we rely on the invariant that the value number for the ith parameter - // // is i+1 - // final int vn = i + 1; - // PointerKey formal = getPointerKeyForLocal(target, vn); - // if (target.getMethod().getParameterType(i).isReferenceType()) { - // system.recordImplicitPointsToSet(formal); - // } - // } - // } else { - // generate contraints from parameter passing - int nUses = instruction.getNumberOfParameters(); - int nExpected = target.getMethod().getNumberOfParameters(); - - /* - * int nExpected = target.getMethod().getReference().getNumberOfParameters(); if (!target.getMethod().isStatic() && - * !target.getMethod().isClinit()) { nExpected++; } - */ - - if (nUses != nExpected) { - // some sort of unverifiable code mismatch. give up. - return; - } - - // we're a little sloppy for now ... we don't filter calls to - // java.lang.Object. - // TODO: we need much more precise filters than cones in order to handle - // the various types of dispatch logic. We need a filter that expresses - // "the set of types s.t. x.foo resolves to y.foo." - for (int i = 0; i < instruction.getNumberOfParameters(); i++) { - if (target.getMethod().getParameterType(i).isReferenceType()) { - PointerKey formal = getTargetPointerKey(target, i); - if (constParams != null && constParams[i] != null) { - InstanceKey[] ik = constParams[i]; - for (int j = 0; j < ik.length; j++) { - system.newConstraint(formal, ik[j]); - } - } else { - if (instruction.getUse(i) < 0) { - Assertions.UNREACHABLE("unexpected " + instruction + " in " + caller); - } - PointerKey actual = getPointerKeyForLocal(caller, instruction.getUse(i)); - if (formal instanceof FilteredPointerKey) { - system.newConstraint(formal, filterOperator, actual); - } else { - system.newConstraint(formal, assignOperator, actual); - } - } - } - } - - // generate contraints from return value. - if (instruction.hasDef() && instruction.getDeclaredResultType().isReferenceType()) { - PointerKey result = getPointerKeyForLocal(caller, instruction.getDef()); - PointerKey ret = getPointerKeyForReturnValue(target); - system.newConstraint(result, assignOperator, ret); - } - // generate constraints from exception return value. - PointerKey e = getPointerKeyForLocal(caller, instruction.getException()); - PointerKey er = getPointerKeyForExceptionalReturnValue(target); - if (SHORT_CIRCUIT_SINGLE_USES && uniqueCatchKey != null) { - // e has exactly one use. so, represent e implicitly - system.newConstraint(uniqueCatchKey, assignOperator, er); - } else { - system.newConstraint(e, assignOperator, er); - } - // } - } - - /** - * An operator to fire when we discover a potential new callee for a virtual or interface call site. - * - * This operator will create a new callee context and constraints if necessary. - */ - final class DispatchOperator extends AbstractOperator implements IPointerOperator { - private final SSAAbstractInvokeInstruction call; - - private final CGNode node; - - private final InstanceKey[][] constParams; - - private final PointerKey uniqueCatch; - - /** - * relevant parameter indices for the registered {@link ContextSelector} - * - * @see ContextSelector#getRelevantParameters(CGNode, CallSiteReference) - */ - private final int[] dispatchIndices; - - /** - * The set of instance keys that have already been processed. - * previousPtrs[i] contains the processed instance keys for parameter - * position dispatchIndices[i] - */ - final private MutableIntSet[] previousPtrs; - - /** - * @param call - * @param node - * @param constParams if non-null, then constParams[i] holds the String constant that is passed as param i, or null if param i - * is not a String constant - */ - DispatchOperator(SSAAbstractInvokeInstruction call, CGNode node, InstanceKey[][] constParams, - PointerKey uniqueCatch, IntSet dispatchIndices) { - this.call = call; - this.node = node; - this.constParams = constParams; - this.uniqueCatch = uniqueCatch; - this.dispatchIndices = IntSetUtil.toArray(dispatchIndices); - // we better always be interested in the receiver - assert this.dispatchIndices[0] == 0; - previousPtrs = new MutableIntSet[dispatchIndices.size()]; - for(int i = 0; i < previousPtrs.length; i++) { - previousPtrs[i] = IntSetUtil.getDefaultIntSetFactory().make(); - } - } - - - - /* - * @see com.ibm.wala.dataflow.fixpoint.UnaryOperator#evaluate(com.ibm.wala.dataflow.fixpoint.IVariable, - * com.ibm.wala.dataflow.fixpoint.IVariable) - */ - @Override - public byte evaluate(PointsToSetVariable lhs, final PointsToSetVariable[] rhs) { - assert dispatchIndices.length >= rhs.length : "bad operator at " + call; - // did evaluating the dispatch operation add a new possible target - // to the call site? - final MutableBoolean addedNewTarget = new MutableBoolean(); - - final MutableIntSet receiverVals; - if (constParams != null && constParams[0] != null) { - receiverVals = IntSetUtil.make(); - for(InstanceKey ik : constParams[0]) { - receiverVals.add(system.getInstanceIndex(ik)); - } - } else { - receiverVals = rhs[0].getValue(); - } - - if (receiverVals == null) { - // this constraint was put on the work list, probably by - // initialization, - // even though the right-hand-side is empty. - // TODO: be more careful about what goes on the worklist to - // avoid this. - if (DEBUG) { - System.err.println("EVAL dispatch with value null"); - } - return NOT_CHANGED; - - } - // we handle the parameter positions one by one, rather than enumerating - // the cartesian product of possibilities. this disallows - // context-sensitivity policies like true CPA, but is necessary for - // performance. - InstanceKey keys[] = new InstanceKey[constParams == null? dispatchIndices[dispatchIndices.length-1]+1: constParams.length]; - // determine whether we're handling a new receiver; used later - // to check for redundancy - boolean newReceiver = !receiverVals.isSubset(previousPtrs[0]); - // keep separate rhsIndex, since it doesn't advance for constant - // parameters - int rhsIndex = (constParams != null && constParams[0] != null)? 0: 1; - // this flag is set to true if we ever call handleAllReceivers() in the - // loop below. we need to catch the case where we have a new receiver, but - // there are no other dispatch indices with new values - boolean propagatedReceivers = false; - // we start at index 1 since we need to handle the receiver specially; see - // below - for (int index = 1; index < dispatchIndices.length; index++) { - try { - MonitorUtil.throwExceptionIfCanceled(monitor); - } catch (CancelException e) { - throw new CancelRuntimeException(e); - } - int paramIndex = dispatchIndices[index]; - assert keys[paramIndex] == null; - final MutableIntSet prevAtIndex = previousPtrs[index]; - if (constParams != null && constParams[paramIndex] != null) { - // we have a constant parameter. only need to propagate again if we've never done it before or if we have a new receiver - if (newReceiver || prevAtIndex.isEmpty()) { - for(int i = 0; i < constParams[paramIndex].length; i++) { - keys[paramIndex] = constParams[paramIndex][i]; - handleAllReceivers(receiverVals,keys, addedNewTarget); - propagatedReceivers = true; - int ii = system.instanceKeys.getMappedIndex(constParams[paramIndex][i]); - prevAtIndex.add(ii); - } - } - } else { // non-constant parameter - PointsToSetVariable v = rhs[rhsIndex]; - if (v.getValue() != null) { - IntIterator ptrs = v.getValue().intIterator(); - while (ptrs.hasNext()) { - int ptr = ptrs.next(); - if (newReceiver || !prevAtIndex.contains(ptr)) { - keys[paramIndex] = system.getInstanceKey(ptr); - handleAllReceivers(receiverVals,keys, addedNewTarget); - propagatedReceivers = true; - prevAtIndex.add(ptr); - } - } - } - rhsIndex++; - } - keys[paramIndex] = null; - } - if (newReceiver) { - if (!propagatedReceivers) { - // we have a new receiver value, and it wasn't propagated at all, - // so propagate it now - handleAllReceivers(receiverVals, keys, addedNewTarget); - } - // update receiver cache - previousPtrs[0].addAll(receiverVals); - } - - byte sideEffectMask = addedNewTarget.b ? (byte) SIDE_EFFECT_MASK : 0; - return (byte) (NOT_CHANGED | sideEffectMask); - } - - private void handleAllReceivers(MutableIntSet receiverVals, InstanceKey[] keys, MutableBoolean sideEffect) { - assert keys[0] == null; - IntIterator receiverIter = receiverVals.intIterator(); - while (receiverIter.hasNext()) { - final int rcvr = receiverIter.next(); - keys[0] = system.getInstanceKey(rcvr); - if (clone2Assign) { - // for efficiency: assume that only call sites that reference - // clone() might dispatch to clone methods - if (call.getCallSite().getDeclaredTarget().getSelector().equals(cloneSelector)) { - IClass recv = (keys[0] != null) ? keys[0].getConcreteType() : null; - IMethod targetMethod = getOptions().getMethodTargetSelector().getCalleeTarget(node, call.getCallSite(), recv); - if (targetMethod != null && targetMethod.getReference().equals(CloneInterpreter.CLONE)) { - // treat this call to clone as an assignment - PointerKey result = getPointerKeyForLocal(node, call.getDef()); - PointerKey receiver = getPointerKeyForLocal(node, call.getReceiver()); - system.newConstraint(result, assignOperator, receiver); - return; - } - } - } - CGNode target = getTargetForCall(node, call.getCallSite(), keys[0].getConcreteType(), keys); - if (target == null) { - // This indicates an error; I sure hope getTargetForCall - // raised a warning about this! - if (DEBUG) { - System.err.println("Warning: null target for call " + call); - } - } else { - IntSet targets = getCallGraph().getPossibleTargetNumbers(node, call.getCallSite()); - // even if we've seen this target before, if we have constant - // parameters, we may need to re-process the call, as the constraints - // for the first time we reached this target may not have been fully - // general. TODO a more refined check? - if (targets != null && targets.contains(target.getGraphNodeId()) && noConstParams()) { - // do nothing; we've previously discovered and handled this - // receiver for this call site. - } else { - // process the newly discovered target for this call - sideEffect.b = true; - processResolvedCall(node, call, target, constParams, uniqueCatch); - if (!haveAlreadyVisited(target)) { - markDiscovered(target); - } - } - } - } - keys[0] = null; - } - - private boolean noConstParams() { - if (constParams != null) { - for (int i = 0; i < constParams.length; i++) { - if (constParams[i] != null) { - for (int j = 0; j < constParams[i].length; i++) { - if (constParams[i][j] != null) { - return false; - } - } - } - } - } - return true; - } - - - - @Override - public String toString() { - return "Dispatch to " + call + " in node " + node; - } - - @Override - public int hashCode() { - return node.hashCode() + 90289 * call.hashCode(); - } - - @Override - public boolean equals(Object o) { - // note that these are not necessarily canonical, since - // with synthetic factories we may regenerate constraints - // many times. TODO: change processing of synthetic factories - // so that we guarantee to insert each dispatch equation - // only once ... if this were true we could optimize this - // with reference equality - - // instanceof is OK because this class is final - if (o instanceof DispatchOperator) { - DispatchOperator other = (DispatchOperator) o; - return node.equals(other.node) && call.equals(other.call) && Arrays.deepEquals(constParams, other.constParams); - } else { - return false; - } - } - - /* - * @see com.ibm.wala.ipa.callgraph.propagation.IPointerOperator#isComplex() - */ - public boolean isComplex() { - return true; - } - } - - protected void iterateCrossProduct(final CGNode caller, final SSAAbstractInvokeInstruction call, IntSet parameters, - final InstanceKey[][] invariants, final VoidFunction f) { - final int params[] = IntSetUtil.toArray(parameters); - final InstanceKey[] keys = new InstanceKey[call.getNumberOfParameters()]; - final CallSiteReference site = call.getCallSite(); - new Object() { - private void rec(final int pi) { - if (pi == params.length) { - f.apply(keys); - } else { - final int p = params[pi]; - int vn = call.getUse(p); - PointerKey var = getPointerKeyForLocal(caller, vn); - InstanceKey[] ik = invariants != null ? invariants[p] : null; - if (ik != null) { - if (ik.length > 0) { - for (int i = 0; i < ik.length; i++) { - system.findOrCreateIndexForInstanceKey(ik[i]); - keys[p] = ik[i]; - rec(pi + 1); - } - } else { - if (!site.isDispatch() || p != 0) { - keys[p] = null; - rec(pi + 1); - } - } - } else { - IntSet s = system.findOrCreatePointsToSet(var).getValue(); - if (s != null && !s.isEmpty()) { - s.foreach(new IntSetAction() { - public void act(int x) { - keys[p] = system.getInstanceKey(x); - rec(pi + 1); - } - }); - } else { - if (!site.isDispatch() || p != 0) { - keys[p] = null; - rec(pi + 1); - } - } - } - } - } - }.rec(0); - } - - protected Set getTargetsForCall(final CGNode caller, final SSAAbstractInvokeInstruction instruction, InstanceKey[][] invs) { - // This method used to take a CallSiteReference as a parameter, rather than - // an SSAAbstractInvokeInstruction. This was bad, since it's - // possible for multiple invoke instructions with different actual - // parameters to be associated with a single CallSiteReference. Changed - // to take the invoke instruction as a parameter instead, since invs is - // associated with the instruction - final CallSiteReference site = instruction.getCallSite(); - IntSet params = contextSelector.getRelevantParameters(caller, site); - if (!site.isStatic() && !params.contains(0)) { - params = IntSetUtil.makeMutableCopy(params); - ((MutableIntSet)params).add(0); - } - final Set targets = HashSetFactory.make(); - VoidFunction f = new VoidFunction() { - public void apply(InstanceKey[] v) { - IClass recv = null; - if (site.isDispatch()) { - recv = v[0].getConcreteType(); - } - CGNode target = getTargetForCall(caller, site, recv, v); - if (target != null) { - targets.add(target); - } - } - }; - iterateCrossProduct(caller, instruction, params, invs, f); - return targets; - } - - public boolean hasNoInterestingUses(CGNode node, int vn, DefUse du) { - - if (du == null) { - throw new IllegalArgumentException("du is null"); - } - if (vn <= 0) { - throw new IllegalArgumentException("v is invalid: " + vn); - } - // todo: enhance this by solving a dead-code elimination - // problem. - InterestingVisitor v = makeInterestingVisitor(node, vn); - for (Iterator it = du.getUses(v.vn); it.hasNext();) { - SSAInstruction s = (SSAInstruction) it.next(); - s.visit(v); - if (v.bingo) { - return false; - } - } - return true; - } - - protected InterestingVisitor makeInterestingVisitor(CGNode node, int vn) { - return new InterestingVisitor(vn); - } - - /** - * sets bingo to true when it visits an interesting instruction - */ - protected static class InterestingVisitor extends SSAInstruction.Visitor { - protected final int vn; - - protected InterestingVisitor(int vn) { - this.vn = vn; - } - - protected boolean bingo = false; - - @Override - public void visitArrayLoad(SSAArrayLoadInstruction instruction) { - if (!instruction.typeIsPrimitive() && instruction.getArrayRef() == vn) { - bingo = true; - } - } - - @Override - public void visitArrayStore(SSAArrayStoreInstruction instruction) { - if (!instruction.typeIsPrimitive() && (instruction.getArrayRef() == vn || instruction.getValue() == vn)) { - bingo = true; - } - } - - @Override - public void visitCheckCast(SSACheckCastInstruction instruction) { - bingo = true; - } - - @Override - public void visitGet(SSAGetInstruction instruction) { - FieldReference field = instruction.getDeclaredField(); - if (!field.getFieldType().isPrimitiveType()) { - bingo = true; - } - } - - @Override - public void visitGetCaughtException(SSAGetCaughtExceptionInstruction instruction) { - bingo = true; - } - - @Override - public void visitInvoke(SSAInvokeInstruction instruction) { - bingo = true; - } - - @Override - public void visitPhi(SSAPhiInstruction instruction) { - bingo = true; - } - - @Override - public void visitPi(SSAPiInstruction instruction) { - bingo = true; - } - - @Override - public void visitPut(SSAPutInstruction instruction) { - FieldReference field = instruction.getDeclaredField(); - if (!field.getFieldType().isPrimitiveType()) { - bingo = true; - } - } - - @Override - public void visitReturn(SSAReturnInstruction instruction) { - bingo = true; - } - - @Override - public void visitThrow(SSAThrowInstruction instruction) { - bingo = true; - } - } - - /** - * TODO: enhance this logic using type inference - * - * @param instruction - * @return true if we need to filter the receiver type to account for virtual dispatch - */ - @SuppressWarnings("unused") - private boolean needsFilterForReceiver(SSAAbstractInvokeInstruction instruction, CGNode target) { - - FilteredPointerKey.TypeFilter f = (FilteredPointerKey.TypeFilter) target.getContext().get(ContextKey.PARAMETERS[0]); - - if (f != null) { - // the context selects a particular concrete type for the receiver. - // we need to filter, unless the declared receiver type implies the - // concrete type (TODO: need to implement this optimization) - return true; - } - - // don't need to filter for invokestatic - if (instruction.getCallSite().isStatic() || instruction.getCallSite().isSpecial()) { - return false; - } - - MethodReference declaredTarget = instruction.getDeclaredTarget(); - IMethod resolvedTarget = getClassHierarchy().resolveMethod(declaredTarget); - if (resolvedTarget == null) { - // there's some problem that will be flagged as a warning - return true; - } - - return true; - } - - private boolean isRootType(IClass klass) { - return klass.getClassHierarchy().isRootClass(klass); - } - - @SuppressWarnings("unused") - private boolean isRootType(FilteredPointerKey.TypeFilter filter) { - if (filter instanceof FilteredPointerKey.SingleClassFilter) { - return isRootType(((FilteredPointerKey.SingleClassFilter) filter).getConcreteType()); - } else { - return false; - } - } - - /** - * TODO: enhance this logic using type inference TODO!!!: enhance filtering to consider concrete types, not just cones. - * precondition: needs Filter - * - * @param target - * @return an IClass which represents - */ - protected PointerKey getTargetPointerKey(CGNode target, int index) { - int vn; - if (target.getIR() != null) { - vn = target.getIR().getSymbolTable().getParameter(index); - } else { - vn = index+1; - } - - FilteredPointerKey.TypeFilter filter = (FilteredPointerKey.TypeFilter) target.getContext().get(ContextKey.PARAMETERS[index]); - if (filter != null && !filter.isRootFilter()) { - return pointerKeyFactory.getFilteredPointerKeyForLocal(target, vn, filter); - - } else if (index == 0 && !target.getMethod().isStatic()) { - // the context does not select a particular concrete type for the - // receiver, so use the type of the method - IClass C = getReceiverClass(target.getMethod()); - if (C.getClassHierarchy().getRootClass().equals(C)) { - return pointerKeyFactory.getPointerKeyForLocal(target, vn); - } else { - return pointerKeyFactory.getFilteredPointerKeyForLocal(target, vn, new FilteredPointerKey.SingleClassFilter(C)); - } - - } else { - return pointerKeyFactory.getPointerKeyForLocal(target, vn); - } - } - - /** - * @param method - * @return the receiver class for this method. - */ - private IClass getReceiverClass(IMethod method) { - TypeReference formalType = method.getParameterType(0); - IClass C = getClassHierarchy().lookupClass(formalType); - if (method.isStatic()) { - Assertions.UNREACHABLE("asked for receiver of static method " + method); - } - if (C == null) { - Assertions.UNREACHABLE("no class found for " + formalType + " recv of " + method); - } - return C; - } - - /** - * A value is "invariant" if we can figure out the instances it can ever point to locally, without resorting to propagation. - * - * @param valueNumber - * @return true iff the contents of the local with this value number can be deduced locally, without propagation - */ - protected boolean contentsAreInvariant(SymbolTable symbolTable, DefUse du, int valueNumber) { - if (isConstantRef(symbolTable, valueNumber)) { - return true; - } else if (SHORT_CIRCUIT_INVARIANT_SETS) { - SSAInstruction def = du.getDef(valueNumber); - if (def instanceof SSANewInstruction) { - return true; - } else { - return false; - } - } else { - return false; - } - } - - protected boolean contentsAreInvariant(SymbolTable symbolTable, DefUse du, int valueNumbers[]) { - for(int i = 0; i < valueNumbers.length; i++) { - if (! contentsAreInvariant(symbolTable, du, valueNumbers[i])) { - return false; - } - } - return true; - } - - /** - * precondition:contentsAreInvariant(valueNumber) - * - * @param valueNumber - * @return the complete set of instances that the local with vn=valueNumber may point to. - */ - protected InstanceKey[] getInvariantContents(SymbolTable symbolTable, DefUse du, CGNode node, int valueNumber, HeapModel hm) { - return getInvariantContents(symbolTable, du, node, valueNumber, hm, false); - } - - protected InstanceKey[] getInvariantContents(SymbolTable symbolTable, DefUse du, CGNode node, int valueNumber, HeapModel hm, - boolean ensureIndexes) { - InstanceKey[] result; - if (isConstantRef(symbolTable, valueNumber)) { - Object x = symbolTable.getConstantValue(valueNumber); - if (x instanceof String) { - // this is always the case in Java. use strong typing in the call to getInstanceKeyForConstant. - String S = (String) x; - TypeReference type = node.getMethod().getDeclaringClass().getClassLoader().getLanguage().getConstantType(S); - if (type == null) { - return new InstanceKey[0]; - } - InstanceKey ik = hm.getInstanceKeyForConstant(type, S); - if (ik != null) { - result = new InstanceKey[] { ik }; - } else { - result = new InstanceKey[0]; - } - } else { - // some non-built in type (e.g. Integer). give up on strong typing. - // language-specific subclasses (e.g. Javascript) should override this method to get strong typing - // with generics if desired. - TypeReference type = node.getMethod().getDeclaringClass().getClassLoader().getLanguage().getConstantType(x); - if (type == null) { - return new InstanceKey[0]; - } - InstanceKey ik = hm.getInstanceKeyForConstant(type, x); - if (ik != null) { - result = new InstanceKey[] { ik }; - } else { - result = new InstanceKey[0]; - } - } - } else { - SSANewInstruction def = (SSANewInstruction) du.getDef(valueNumber); - InstanceKey iKey = hm.getInstanceKeyForAllocation(node, def.getNewSite()); - result = (iKey == null) ? new InstanceKey[0] : new InstanceKey[] { iKey }; - } - - if (ensureIndexes) { - for (int i = 0; i < result.length; i++) { - system.findOrCreateIndexForInstanceKey(result[i]); - } - } - - return result; - } - - protected boolean isConstantRef(SymbolTable symbolTable, int valueNumber) { - if (valueNumber == -1) { - return false; - } - if (symbolTable.isConstant(valueNumber)) { - Object v = symbolTable.getConstantValue(valueNumber); - return (!(v instanceof Number)); - } else { - return false; - } - } - - /** - * @author sfink - * - * A warning for when we fail to resolve the type for a checkcast - */ - private static class CheckcastFailure extends Warning { - - final TypeReference type; - - CheckcastFailure(TypeReference type) { - super(Warning.SEVERE); - this.type = type; - } - - @Override - public String getMsg() { - return getClass().toString() + " : " + type; - } - - public static CheckcastFailure create(TypeReference type) { - return new CheckcastFailure(type); - } - } - - /** - * @author sfink - * - * A warning for when we fail to resolve the type for a field - */ - private static class FieldResolutionFailure extends Warning { - - final FieldReference field; - - FieldResolutionFailure(FieldReference field) { - super(Warning.SEVERE); - this.field = field; - } - - @Override - public String getMsg() { - return getClass().toString() + " : " + field; - } - - public static FieldResolutionFailure create(FieldReference field) { - return new FieldResolutionFailure(field); - } - } - - /* - * @see com.ibm.wala.ipa.callgraph.propagation.HeapModel#iteratePointerKeys() - */ - public Iterator iteratePointerKeys() { - return system.iteratePointerKeys(); - } - - public static Set getCaughtExceptionTypes(SSAGetCaughtExceptionInstruction instruction, IR ir) { - if (ir == null) { - throw new IllegalArgumentException("ir is null"); - } - if (instruction == null) { - throw new IllegalArgumentException("instruction is null"); - } - Iterator exceptionTypes = ((ExceptionHandlerBasicBlock) ir.getControlFlowGraph().getNode( - instruction.getBasicBlockNumber())).getCaughtExceptionTypes(); - HashSet types = HashSetFactory.make(10); - for (; exceptionTypes.hasNext();) { - IClass c = ir.getMethod().getClassHierarchy().lookupClass(exceptionTypes.next()); - if (c != null) { - types.add(c); - } - } - return types; - } - - public InstanceKey getInstanceKeyForPEI(CGNode node, ProgramCounter instr, TypeReference type) { - return getInstanceKeyForPEI(node, instr, type, instanceKeyFactory); - } - - /* - * @see com.ibm.wala.ipa.callgraph.propagation.PropagationCallGraphBuilder#makeSolver() - */ - @Override - protected IPointsToSolver makeSolver() { - return new StandardSolver(system, this); - // return usePreTransitiveSolver ? (IPointsToSolver) new PreTransitiveSolver(system, this) : new StandardSolver(system, this); - // return true ? (IPointsToSolver)new PreTransitiveSolver(system,this) : new - // StandardSolver(system,this); - } -} +/******************************************************************************* + * 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.ipa.callgraph.propagation; + +import java.util.ArrayList; +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.analysis.reflection.CloneInterpreter; +import com.ibm.wala.cfg.ControlFlowGraph; +import com.ibm.wala.cfg.IBasicBlock; +import com.ibm.wala.classLoader.ArrayClass; +import com.ibm.wala.classLoader.CallSiteReference; +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.classLoader.ProgramCounter; +import com.ibm.wala.fixpoint.AbstractOperator; +import com.ibm.wala.ipa.callgraph.AnalysisCache; +import com.ibm.wala.ipa.callgraph.AnalysisOptions; +import com.ibm.wala.ipa.callgraph.CGNode; +import com.ibm.wala.ipa.callgraph.ContextKey; +import com.ibm.wala.ipa.callgraph.ContextSelector; +import com.ibm.wala.ipa.callgraph.impl.AbstractRootMethod; +import com.ibm.wala.ipa.callgraph.impl.ExplicitCallGraph; +import com.ibm.wala.ipa.callgraph.impl.FakeRootMethod; +import com.ibm.wala.ipa.cha.IClassHierarchy; +import com.ibm.wala.shrikeBT.ConditionalBranchInstruction; +import com.ibm.wala.shrikeBT.IInvokeInstruction; +import com.ibm.wala.ssa.DefUse; +import com.ibm.wala.ssa.IR; +import com.ibm.wala.ssa.ISSABasicBlock; +import com.ibm.wala.ssa.SSAAbstractInvokeInstruction; +import com.ibm.wala.ssa.SSAAbstractThrowInstruction; +import com.ibm.wala.ssa.SSAArrayLoadInstruction; +import com.ibm.wala.ssa.SSAArrayStoreInstruction; +import com.ibm.wala.ssa.SSACFG; +import com.ibm.wala.ssa.SSACFG.BasicBlock; +import com.ibm.wala.ssa.SSACFG.ExceptionHandlerBasicBlock; +import com.ibm.wala.ssa.SSACheckCastInstruction; +import com.ibm.wala.ssa.SSAConditionalBranchInstruction; +import com.ibm.wala.ssa.SSAGetCaughtExceptionInstruction; +import com.ibm.wala.ssa.SSAGetInstruction; +import com.ibm.wala.ssa.SSAInstanceofInstruction; +import com.ibm.wala.ssa.SSAInstruction; +import com.ibm.wala.ssa.SSAInvokeInstruction; +import com.ibm.wala.ssa.SSALoadMetadataInstruction; +import com.ibm.wala.ssa.SSANewInstruction; +import com.ibm.wala.ssa.SSAPhiInstruction; +import com.ibm.wala.ssa.SSAPiInstruction; +import com.ibm.wala.ssa.SSAPutInstruction; +import com.ibm.wala.ssa.SSAReturnInstruction; +import com.ibm.wala.ssa.SSAThrowInstruction; +import com.ibm.wala.ssa.SymbolTable; +import com.ibm.wala.types.FieldReference; +import com.ibm.wala.types.MethodReference; +import com.ibm.wala.types.Selector; +import com.ibm.wala.types.TypeReference; +import com.ibm.wala.util.CancelException; +import com.ibm.wala.util.CancelRuntimeException; +import com.ibm.wala.util.MonitorUtil; +import com.ibm.wala.util.MonitorUtil.IProgressMonitor; +import com.ibm.wala.util.collections.HashSetFactory; +import com.ibm.wala.util.debug.Assertions; +import com.ibm.wala.util.functions.VoidFunction; +import com.ibm.wala.util.intset.IntIterator; +import com.ibm.wala.util.intset.IntSet; +import com.ibm.wala.util.intset.IntSetAction; +import com.ibm.wala.util.intset.IntSetUtil; +import com.ibm.wala.util.intset.MutableIntSet; +import com.ibm.wala.util.ref.ReferenceCleanser; +import com.ibm.wala.util.warnings.Warning; +import com.ibm.wala.util.warnings.Warnings; + +/** + * This abstract base class provides the general algorithm for a call graph builder that relies on propagation through an iterative + * dataflow solver, and constraints generated by statements in SSA form. + * + * TODO: This implementation currently keeps all points to sets live ... even those for local variables that do not span + * interprocedural boundaries. This may be too space-inefficient .. we can consider recomputing local sets on demand. + */ +public abstract class SSAPropagationCallGraphBuilder extends PropagationCallGraphBuilder implements HeapModel { + private final static boolean DEBUG = false; + + private final static boolean DEBUG_MULTINEWARRAY = DEBUG | false; + + /** + * Should we periodically clear out soft reference caches in an attempt to help the GC? + */ + public final static boolean PERIODIC_WIPE_SOFT_CACHES = true; + + /** + * Interval which defines the period to clear soft reference caches + */ + public final static int WIPE_SOFT_CACHE_INTERVAL = 2500; + + /** + * Counter for wiping soft caches + */ + private static int wipeCount = 0; + + /** + * use type inference to avoid unnecessary filter constraints? + */ + // private final static boolean OPTIMIZE_WITH_TYPE_INFERENCE = true; + /** + * An optimization: if we can locally determine the final solution for a points-to set, then don't actually create the points-to + * set, but instead short circuit by propagating the final solution to all such uses. + * + * String constants are ALWAYS considered invariant, regardless of the value of this flag. + * + * However, if this flag is set, then the solver is more aggressive identifying invariants. + * + * Doesn't play well with pre-transitive solver; turning off for now. + */ + private final static boolean SHORT_CIRCUIT_INVARIANT_SETS = true; + + /** + * An optimization: if we can locally determine that a particular pointer p has exactly one use, then we don't actually create the + * points-to-set for p, but instead short-circuit by propagating the final solution to the unique use. + * + * Doesn't play well with pre-transitive solver; turning off for now. + */ + protected final static boolean SHORT_CIRCUIT_SINGLE_USES = true; + + /** + * Should we change calls to clone() to assignments? + */ + private final boolean clone2Assign = false; + + /** + * Cache for efficiency + */ + private final static Selector cloneSelector = CloneInterpreter.CLONE.getSelector(); + + /** + * set of class whose clinits have already been processed + */ + private final Set clinitVisited = HashSetFactory.make(); + + private IProgressMonitor monitor; + + protected SSAPropagationCallGraphBuilder(IClassHierarchy cha, AnalysisOptions options, AnalysisCache cache, + PointerKeyFactory pointerKeyFactory) { + super(cha, options, cache, pointerKeyFactory); + // this.usePreTransitiveSolver = options.usePreTransitiveSolver(); + } + + public SSAContextInterpreter getCFAContextInterpreter() { + return (SSAContextInterpreter) getContextInterpreter(); + } + + /** + * @param node + * @param x + * @param type + * @return the instance key that represents the exception of type _type_ thrown by a particular PEI. + * @throws IllegalArgumentException if ikFactory is null + */ + public static InstanceKey getInstanceKeyForPEI(CGNode node, ProgramCounter x, TypeReference type, InstanceKeyFactory ikFactory) { + if (ikFactory == null) { + throw new IllegalArgumentException("ikFactory is null"); + } + return ikFactory.getInstanceKeyForPEI(node, x, type); + } + + /** + * Visit all instructions in a node, and add dataflow constraints induced by each statement in the SSA form. + * @throws CancelException + * + * @see com.ibm.wala.ipa.callgraph.propagation.PropagationCallGraphBuilder#addConstraintsFromNode(com.ibm.wala.ipa.callgraph.CGNode) + */ + @Override + protected boolean addConstraintsFromNode(CGNode node, IProgressMonitor monitor) throws CancelException { + this.monitor = monitor; + if (haveAlreadyVisited(node)) { + return false; + } else { + markAlreadyVisited(node); + } + return unconditionallyAddConstraintsFromNode(node, monitor); + } + + @Override + protected boolean unconditionallyAddConstraintsFromNode(CGNode node, IProgressMonitor monitor) throws CancelException { + this.monitor = monitor; + if (PERIODIC_WIPE_SOFT_CACHES) { + wipeCount++; + if (wipeCount >= WIPE_SOFT_CACHE_INTERVAL) { + wipeCount = 0; + ReferenceCleanser.clearSoftCaches(); + } + } + + if (DEBUG) { + System.err.println("\n\nAdd constraints from node " + node); + } + IR ir = getCFAContextInterpreter().getIR(node); + if (DEBUG) { + if (ir == null) { + System.err.println("\n No statements\n"); + } else { + try { + System.err.println(ir.toString()); + } catch (Error e) { + e.printStackTrace(); + } + } + } + + if (ir == null) { + return false; + } + + addNodeInstructionConstraints(node, monitor); + + DefUse du = getCFAContextInterpreter().getDU(node); + addNodePassthruExceptionConstraints(node, ir, du); + // conservatively assume something changed + return true; + } + + /** + * @return a visitor to examine instructions in the ir + */ + protected ConstraintVisitor makeVisitor(CGNode node) { + return new ConstraintVisitor(this, node); + } + + /** + * Add pointer flow constraints based on instructions in a given node + * @throws CancelException + */ + protected void addNodeInstructionConstraints(CGNode node, IProgressMonitor monitor) throws CancelException { + this.monitor = monitor; + ConstraintVisitor v = makeVisitor(node); + + IR ir = v.ir; + ControlFlowGraph cfg = ir.getControlFlowGraph(); + for (Iterator x = cfg.iterator(); x.hasNext();) { + BasicBlock b = (BasicBlock) x.next(); + addBlockInstructionConstraints(node, cfg, b, v, monitor); + if (wasChanged(node)) { + return; + } + } + } + + /** + * Add constraints for a particular basic block. + * @throws CancelException + */ + protected void addBlockInstructionConstraints(CGNode node, ControlFlowGraph cfg, BasicBlock b, + ConstraintVisitor v, IProgressMonitor monitor) throws CancelException { + this.monitor = monitor; + v.setBasicBlock(b); + + // visit each instruction in the basic block. + for (Iterator it = b.iterator(); it.hasNext();) { + MonitorUtil.throwExceptionIfCanceled(monitor); + SSAInstruction s = it.next(); + if (s != null) { + s.visit(v); + if (wasChanged(node)) { + return; + } + } + } + + addPhiConstraints(node, cfg, b, v); + } + + private void addPhiConstraints(CGNode node, ControlFlowGraph cfg, BasicBlock b, + ConstraintVisitor v) { + // visit each phi instruction in each successor block + for (Iterator sbs = cfg.getSuccNodes(b); sbs.hasNext();) { + BasicBlock sb = (BasicBlock) sbs.next(); + if (!sb.hasPhi()) { + continue; + } + int n = 0; + for (Iterator back = cfg.getPredNodes(sb); back.hasNext(); n++) { + if (back.next() == b) { + break; + } + } + assert n < cfg.getPredNodeCount(sb); + for (Iterator phis = sb.iteratePhis(); phis.hasNext();) { + SSAPhiInstruction phi = (SSAPhiInstruction) phis.next(); + if (phi == null) { + continue; + } + PointerKey def = getPointerKeyForLocal(node, phi.getDef()); + if (hasNoInterestingUses(node, phi.getDef(), v.du)) { + system.recordImplicitPointsToSet(def); + } else { + // the following test restricts the constraints to reachable + // paths, according to verification constraints + if (phi.getUse(n) > 0) { + PointerKey use = getPointerKeyForLocal(node, phi.getUse(n)); + if (contentsAreInvariant(v.symbolTable, v.du, phi.getUse(n))) { + system.recordImplicitPointsToSet(use); + InstanceKey[] ik = getInvariantContents(v.symbolTable, v.du, node, phi.getUse(n), this); + for (int i = 0; i < ik.length; i++) { + system.newConstraint(def, ik[i]); + } + } else { + system.newConstraint(def, assignOperator, use); + } + } + } + } + } + } + + /** + * Add constraints to represent the flow of exceptions to the exceptional return value for this node + * + * @param node + * @param ir + */ + protected void addNodePassthruExceptionConstraints(CGNode node, IR ir, DefUse du) { + // add constraints relating to thrown exceptions that reach the exit block. + List peis = getIncomingPEIs(ir, ir.getExitBlock()); + PointerKey exception = getPointerKeyForExceptionalReturnValue(node); + + TypeReference throwableType = node.getMethod().getDeclaringClass().getClassLoader().getLanguage().getThrowableType(); + IClass c = node.getClassHierarchy().lookupClass(throwableType); + addExceptionDefConstraints(ir, du, node, peis, exception, Collections.singleton(c)); + } + + /** + * Generate constraints which assign exception values into an exception pointer + * + * @param node governing node + * @param peis list of PEI instructions + * @param exceptionVar PointerKey representing a pointer to an exception value + * @param catchClasses the types "caught" by the exceptionVar + */ + private void addExceptionDefConstraints(IR ir, DefUse du, CGNode node, List peis, PointerKey exceptionVar, + Set catchClasses) { + if (DEBUG) { + System.err.println("Add exception def constraints for node " + node); + } + for (Iterator it = peis.iterator(); it.hasNext();) { + ProgramCounter peiLoc = it.next(); + if (DEBUG) { + System.err.println("peiLoc: " + peiLoc); + } + SSAInstruction pei = ir.getPEI(peiLoc); + + if (DEBUG) { + System.err.println("Add exceptions from pei " + pei); + } + + if (pei instanceof SSAAbstractInvokeInstruction) { + SSAAbstractInvokeInstruction s = (SSAAbstractInvokeInstruction) pei; + PointerKey e = getPointerKeyForLocal(node, s.getException()); + + if (!SHORT_CIRCUIT_SINGLE_USES || !hasUniqueCatchBlock(s, ir)) { + addAssignmentsForCatchPointerKey(exceptionVar, catchClasses, e); + }// else { + // System.err.println("SKIPPING ASSIGNMENTS TO " + exceptionVar + " FROM " + + // e); + // } + } else if (pei instanceof SSAAbstractThrowInstruction) { + SSAAbstractThrowInstruction s = (SSAAbstractThrowInstruction) pei; + PointerKey e = getPointerKeyForLocal(node, s.getException()); + + if (contentsAreInvariant(ir.getSymbolTable(), du, s.getException())) { + InstanceKey[] ik = getInvariantContents(ir.getSymbolTable(), du, node, s.getException(), this); + for (int i = 0; i < ik.length; i++) { + system.findOrCreateIndexForInstanceKey(ik[i]); + assignInstanceToCatch(exceptionVar, catchClasses, ik[i]); + } + } else { + addAssignmentsForCatchPointerKey(exceptionVar, catchClasses, e); + } + } + + // Account for those exceptions for which we do not actually have a + // points-to set for + // the pei, but just instance keys + Collection types = pei.getExceptionTypes(); + if (types != null) { + for (Iterator it2 = types.iterator(); it2.hasNext();) { + TypeReference type = it2.next(); + if (type != null) { + InstanceKey ik = getInstanceKeyForPEI(node, peiLoc, type, instanceKeyFactory); + if (ik == null) { + continue; + } + assert ik instanceof ConcreteTypeKey : "uh oh: need to implement getCaughtException constraints for instance " + ik; + ConcreteTypeKey ck = (ConcreteTypeKey) ik; + IClass klass = ck.getType(); + if (PropagationCallGraphBuilder.catches(catchClasses, klass, cha)) { + system.newConstraint(exceptionVar, getInstanceKeyForPEI(node, peiLoc, type, instanceKeyFactory)); + } + } + } + } + } + } + + /** + * @return true iff there's a unique catch block which catches all exceptions thrown by a certain call site. + */ + protected static boolean hasUniqueCatchBlock(SSAAbstractInvokeInstruction call, IR ir) { + ISSABasicBlock[] bb = ir.getBasicBlocksForCall(call.getCallSite()); + if (bb.length == 1) { + Iterator it = ir.getControlFlowGraph().getExceptionalSuccessors(bb[0]).iterator(); + // check that there's exactly one element in the iterator + if (it.hasNext()) { + it.next(); + return (!it.hasNext()); + } + } + return false; + } + + /** + * precondition: hasUniqueCatchBlock(call,node,cg) + * + * @return the unique pointer key which catches the exceptions thrown by a call + * @throws IllegalArgumentException if ir == null + * @throws IllegalArgumentException if call == null + */ + public PointerKey getUniqueCatchKey(SSAAbstractInvokeInstruction call, IR ir, CGNode node) throws IllegalArgumentException, + IllegalArgumentException { + if (call == null) { + throw new IllegalArgumentException("call == null"); + } + if (ir == null) { + throw new IllegalArgumentException("ir == null"); + } + ISSABasicBlock[] bb = ir.getBasicBlocksForCall(call.getCallSite()); + assert bb.length == 1; + SSACFG.BasicBlock cb = (BasicBlock) ir.getControlFlowGraph().getExceptionalSuccessors(bb[0]).iterator().next(); + if (cb.isExitBlock()) { + return getPointerKeyForExceptionalReturnValue(node); + } else { + SSACFG.ExceptionHandlerBasicBlock ehbb = (ExceptionHandlerBasicBlock) cb; + SSAGetCaughtExceptionInstruction ci = ehbb.getCatchInstruction(); + return getPointerKeyForLocal(node, ci.getDef()); + } + } + + /** + * @return a List of Instructions that may transfer control to bb via an exceptional edge + * @throws IllegalArgumentException if ir is null + */ + public static List getIncomingPEIs(IR ir, ISSABasicBlock bb) { + if (ir == null) { + throw new IllegalArgumentException("ir is null"); + } + if (DEBUG) { + System.err.println("getIncomingPEIs " + bb); + } + ControlFlowGraph g = ir.getControlFlowGraph(); + List result = new ArrayList(g.getPredNodeCount(bb)); + for (Iterator it = g.getPredNodes(bb); it.hasNext();) { + BasicBlock pred = (BasicBlock) it.next(); + if (DEBUG) { + System.err.println("pred: " + pred); + } + if (pred.isEntryBlock()) + continue; + int index = pred.getLastInstructionIndex(); + SSAInstruction pei = ir.getInstructions()[index]; + // Note: pei might be null if pred is unreachable. + // TODO: consider pruning CFG for unreachable blocks. + if (pei != null && pei.isPEI()) { + if (DEBUG) { + System.err.println("PEI: " + pei + " index " + index + " PC " + g.getProgramCounter(index)); + } + result.add(new ProgramCounter(g.getProgramCounter(index))); + } + } + return result; + } + + /** + * A visitor that generates constraints based on statements in SSA form. + */ + protected static class ConstraintVisitor extends SSAInstruction.Visitor { + + /** + * The governing call graph builder. This field is used instead of an inner class in order to allow more flexible reuse of this + * visitor in subclasses + */ + protected final SSAPropagationCallGraphBuilder builder; + + /** + * The node whose statements we are currently traversing + */ + protected final CGNode node; + + /** + * The governing call graph. + */ + private final ExplicitCallGraph callGraph; + + /** + * The governing IR + */ + protected final IR ir; + + /** + * The governing propagation system, into which constraints are added + */ + protected final PropagationSystem system; + + /** + * The basic block currently being processed + */ + protected ISSABasicBlock basicBlock; + + /** + * Governing symbol table + */ + protected final SymbolTable symbolTable; + + /** + * Def-use information + */ + protected final DefUse du; + + public ConstraintVisitor(SSAPropagationCallGraphBuilder builder, CGNode node) { + this.builder = builder; + this.node = node; + + this.callGraph = builder.getCallGraph(); + + this.system = builder.getPropagationSystem(); + + this.ir = builder.getCFAContextInterpreter().getIR(node); + this.symbolTable = this.ir.getSymbolTable(); + + this.du = builder.getCFAContextInterpreter().getDU(node); + + assert symbolTable != null; + } + + protected SSAPropagationCallGraphBuilder getBuilder() { + return builder; + } + + protected AnalysisOptions getOptions() { + return builder.options; + } + + protected AnalysisCache getAnalysisCache() { + return builder.getAnalysisCache(); + } + + public PointerKey getPointerKeyForLocal(int valueNumber) { + return getBuilder().getPointerKeyForLocal(node, valueNumber); + } + + public FilteredPointerKey getFilteredPointerKeyForLocal(int valueNumber, FilteredPointerKey.TypeFilter filter) { + return getBuilder().getFilteredPointerKeyForLocal(node, valueNumber, filter); + } + + public PointerKey getPointerKeyForReturnValue() { + return getBuilder().getPointerKeyForReturnValue(node); + } + + public PointerKey getPointerKeyForExceptionalReturnValue() { + return getBuilder().getPointerKeyForExceptionalReturnValue(node); + } + + public PointerKey getPointerKeyForStaticField(IField f) { + return getBuilder().getPointerKeyForStaticField(f); + } + + public PointerKey getPointerKeyForInstanceField(InstanceKey I, IField f) { + return getBuilder().getPointerKeyForInstanceField(I, f); + } + + public PointerKey getPointerKeyForArrayContents(InstanceKey I) { + return getBuilder().getPointerKeyForArrayContents(I); + } + + public InstanceKey getInstanceKeyForAllocation(NewSiteReference allocation) { + return getBuilder().getInstanceKeyForAllocation(node, allocation); + } + + public InstanceKey getInstanceKeyForMultiNewArray(NewSiteReference allocation, int dim) { + return getBuilder().getInstanceKeyForMultiNewArray(node, allocation, dim); + } + + public InstanceKey getInstanceKeyForConstant(T S) { + TypeReference type = node.getMethod().getDeclaringClass().getClassLoader().getLanguage().getConstantType(S); + return getBuilder().getInstanceKeyForConstant(type, S); + } + + public InstanceKey getInstanceKeyForPEI(ProgramCounter instr, TypeReference type) { + return getBuilder().getInstanceKeyForPEI(node, instr, type); + } + + public InstanceKey getInstanceKeyForClassObject(TypeReference type) { + return getBuilder().getInstanceKeyForClassObject(type); + } + + public CGNode getTargetForCall(CGNode caller, CallSiteReference site, IClass recv, InstanceKey iKey[]) { + return getBuilder().getTargetForCall(caller, site, recv, iKey); + } + + protected boolean contentsAreInvariant(SymbolTable symbolTable, DefUse du, int valueNumber) { + return getBuilder().contentsAreInvariant(symbolTable, du, valueNumber); + } + + protected boolean contentsAreInvariant(SymbolTable symbolTable, DefUse du, int valueNumber[]) { + return getBuilder().contentsAreInvariant(symbolTable, du, valueNumber); + } + + protected InstanceKey[] getInvariantContents(int valueNumber) { + return getInvariantContents(ir.getSymbolTable(), du, node, valueNumber); + } + + protected InstanceKey[] getInvariantContents(SymbolTable symbolTable, DefUse du, CGNode node, int valueNumber) { + return getBuilder().getInvariantContents(symbolTable, du, node, valueNumber, getBuilder()); + } + + protected IClassHierarchy getClassHierarchy() { + return getBuilder().getClassHierarchy(); + } + + protected boolean hasNoInterestingUses(int vn) { + return getBuilder().hasNoInterestingUses(node, vn, du); + } + + protected boolean isRootType(IClass klass) { + return getBuilder().isRootType(klass); + } + + /* + * @see com.ibm.wala.ssa.SSAInstruction.Visitor#visitArrayLoad(com.ibm.wala.ssa.SSAArrayLoadInstruction) + */ + @Override + public void visitArrayLoad(SSAArrayLoadInstruction instruction) { + // skip arrays of primitive type + if (instruction.typeIsPrimitive()) { + return; + } + doVisitArrayLoad(instruction.getDef(), instruction.getArrayRef()); + } + + protected void doVisitArrayLoad(int def, int arrayRef) { + PointerKey result = getPointerKeyForLocal(def); + PointerKey arrayRefPtrKey = getPointerKeyForLocal(arrayRef); + if (hasNoInterestingUses(def)) { + system.recordImplicitPointsToSet(result); + } else { + if (contentsAreInvariant(symbolTable, du, arrayRef)) { + system.recordImplicitPointsToSet(arrayRefPtrKey); + InstanceKey[] ik = getInvariantContents(arrayRef); + for (int i = 0; i < ik.length; i++) { + if (!representsNullType(ik[i])) { + system.findOrCreateIndexForInstanceKey(ik[i]); + PointerKey p = getPointerKeyForArrayContents(ik[i]); + if (p == null) { + } else { + system.newConstraint(result, assignOperator, p); + } + } + } + } else { + assert !system.isUnified(result); + assert !system.isUnified(arrayRefPtrKey); + system.newSideEffect(getBuilder().new ArrayLoadOperator(system.findOrCreatePointsToSet(result)), arrayRefPtrKey); + } + } + } + + /* + * @see com.ibm.wala.ssa.SSAInstruction.Visitor#visitArrayStore(com.ibm.wala.ssa.SSAArrayStoreInstruction) + */ + public void doVisitArrayStore(int arrayRef, int value) { + // (requires the creation of assign constraints as + // the set points-to(a[]) grows.) + PointerKey valuePtrKey = getPointerKeyForLocal(value); + PointerKey arrayRefPtrKey = getPointerKeyForLocal(arrayRef); + // if (!supportFullPointerFlowGraph && + // contentsAreInvariant(instruction.getArrayRef())) { + if (contentsAreInvariant(symbolTable, du, arrayRef)) { + system.recordImplicitPointsToSet(arrayRefPtrKey); + InstanceKey[] ik = getInvariantContents(arrayRef); + + for (int i = 0; i < ik.length; i++) { + if (!representsNullType(ik[i]) && !(ik[i] instanceof ZeroLengthArrayInNode)) { + system.findOrCreateIndexForInstanceKey(ik[i]); + PointerKey p = getPointerKeyForArrayContents(ik[i]); + IClass contents = ((ArrayClass) ik[i].getConcreteType()).getElementClass(); + if (p == null) { + } else { + if (contentsAreInvariant(symbolTable, du, value)) { + system.recordImplicitPointsToSet(valuePtrKey); + InstanceKey[] vk = getInvariantContents(value); + for (int j = 0; j < vk.length; j++) { + system.findOrCreateIndexForInstanceKey(vk[j]); + if (vk[j].getConcreteType() != null) { + if (getClassHierarchy().isAssignableFrom(contents, vk[j].getConcreteType())) { + system.newConstraint(p, vk[j]); + } + } + } + } else { + if (isRootType(contents)) { + system.newConstraint(p, assignOperator, valuePtrKey); + } else { + system.newConstraint(p, getBuilder().filterOperator, valuePtrKey); + } + } + } + } + } + } else { + if (contentsAreInvariant(symbolTable, du, value)) { + system.recordImplicitPointsToSet(valuePtrKey); + InstanceKey[] ik = getInvariantContents(value); + for (int i = 0; i < ik.length; i++) { + system.findOrCreateIndexForInstanceKey(ik[i]); + assert !system.isUnified(arrayRefPtrKey); + system.newSideEffect(getBuilder().new InstanceArrayStoreOperator(ik[i]), arrayRefPtrKey); + } + } else { + system.newSideEffect(getBuilder().new ArrayStoreOperator(system.findOrCreatePointsToSet(valuePtrKey)), arrayRefPtrKey); + } + } + } + + @Override + public void visitArrayStore(SSAArrayStoreInstruction instruction) { + // skip arrays of primitive type + if (instruction.typeIsPrimitive()) { + return; + } + doVisitArrayStore(instruction.getArrayRef(), instruction.getValue()); + } + + /* + * @see com.ibm.wala.ssa.SSAInstruction.Visitor#visitCheckCast(com.ibm.wala.ssa.SSACheckCastInstruction) + */ + @Override + public void visitCheckCast(SSACheckCastInstruction instruction) { + + boolean isRoot = false; + Set types = HashSetFactory.make(); + + for(TypeReference t : instruction.getDeclaredResultTypes()) { + IClass cls = getClassHierarchy().lookupClass(t); + if (cls == null) { + Warnings.add(CheckcastFailure.create(t)); + return; + } else { + if (isRootType(cls)) { + isRoot = true; + } + types.add(cls); + } + } + + PointerKey result = getFilteredPointerKeyForLocal(instruction.getResult(), new FilteredPointerKey.MultipleClassesFilter(types.toArray(new IClass[ types.size() ]))); + PointerKey value = getPointerKeyForLocal(instruction.getVal()); + + if (hasNoInterestingUses(instruction.getDef())) { + system.recordImplicitPointsToSet(result); + } else { + if (contentsAreInvariant(symbolTable, du, instruction.getVal())) { + system.recordImplicitPointsToSet(value); + InstanceKey[] ik = getInvariantContents(instruction.getVal()); + for(TypeReference t : instruction.getDeclaredResultTypes()) { + IClass cls = getClassHierarchy().lookupClass(t); + + if (cls.isInterface()) { + for (int i = 0; i < ik.length; i++) { + system.findOrCreateIndexForInstanceKey(ik[i]); + if (getClassHierarchy().implementsInterface(ik[i].getConcreteType(), cls)) { + system.newConstraint(result, ik[i]); + } + } + } else { + for (int i = 0; i < ik.length; i++) { + system.findOrCreateIndexForInstanceKey(ik[i]); + if (getClassHierarchy().isSubclassOf(ik[i].getConcreteType(), cls)) { + system.newConstraint(result, ik[i]); + } + } + } + } + } else { + if (isRoot) { + system.newConstraint(result, assignOperator, value); + } else { + system.newConstraint(result, getBuilder().filterOperator, value); + } + } + } + } + + /* + * @see com.ibm.wala.ssa.SSAInstruction.Visitor#visitReturn(com.ibm.wala.ssa.SSAReturnInstruction) + */ + @Override + public void visitReturn(SSAReturnInstruction instruction) { + + // skip returns of primitive type + if (instruction.returnsPrimitiveType() || instruction.returnsVoid()) { + return; + } + if (DEBUG) { + System.err.println("visitReturn: " + instruction); + } + + PointerKey returnValue = getPointerKeyForReturnValue(); + PointerKey result = getPointerKeyForLocal(instruction.getResult()); + if (contentsAreInvariant(symbolTable, du, instruction.getResult())) { + system.recordImplicitPointsToSet(result); + InstanceKey[] ik = getInvariantContents(instruction.getResult()); + for (int i = 0; i < ik.length; i++) { + if (DEBUG) { + System.err.println("invariant contents: " + returnValue + " " + ik[i]); + } + system.newConstraint(returnValue, ik[i]); + } + } else { + system.newConstraint(returnValue, assignOperator, result); + } + } + + /* + * @see com.ibm.wala.ssa.SSAInstruction.Visitor#visitGet(com.ibm.wala.ssa.SSAGetInstruction) + */ + @Override + public void visitGet(SSAGetInstruction instruction) { + visitGetInternal(instruction.getDef(), instruction.getRef(), instruction.isStatic(), instruction.getDeclaredField()); + } + + protected void visitGetInternal(int lval, int ref, boolean isStatic, FieldReference field) { + if (DEBUG) { + System.err.println("visitGet " + field); + } + + // skip getfields of primitive type (optimisation) + if (field.getFieldType().isPrimitiveType()) { + return; + } + PointerKey def = getPointerKeyForLocal(lval); + assert def != null; + + IField f = getClassHierarchy().resolveField(field); + if (f == null && callGraph.getFakeRootNode().getMethod().getDeclaringClass().getReference().equals(field.getDeclaringClass())) { + f = callGraph.getFakeRootNode().getMethod().getDeclaringClass().getField(field.getName()); + } + + if (f == null) { + return; + } + + if (hasNoInterestingUses(lval)) { + system.recordImplicitPointsToSet(def); + } else { + if (isStatic) { + PointerKey fKey = getPointerKeyForStaticField(f); + system.newConstraint(def, assignOperator, fKey); + IClass klass = getClassHierarchy().lookupClass(field.getDeclaringClass()); + if (klass == null) { + } else { + // side effect of getstatic: may call class initializer + if (DEBUG) { + System.err.println("getstatic call class init " + klass); + } + processClassInitializer(klass); + } + } else { + PointerKey refKey = getPointerKeyForLocal(ref); + // if (!supportFullPointerFlowGraph && + // contentsAreInvariant(ref)) { + if (contentsAreInvariant(symbolTable, du, ref)) { + system.recordImplicitPointsToSet(refKey); + InstanceKey[] ik = getInvariantContents(ref); + for (int i = 0; i < ik.length; i++) { + if (!representsNullType(ik[i])) { + system.findOrCreateIndexForInstanceKey(ik[i]); + PointerKey p = getPointerKeyForInstanceField(ik[i], f); + system.newConstraint(def, assignOperator, p); + } + } + } else { + system.newSideEffect(getBuilder().new GetFieldOperator(f, system.findOrCreatePointsToSet(def)), refKey); + } + } + } + } + + /* + * @see com.ibm.wala.ssa.Instruction.Visitor#visitPut(com.ibm.wala.ssa.PutInstruction) + */ + @Override + public void visitPut(SSAPutInstruction instruction) { + visitPutInternal(instruction.getVal(), instruction.getRef(), instruction.isStatic(), instruction.getDeclaredField()); + } + + public void visitPutInternal(int rval, int ref, boolean isStatic, FieldReference field) { + + if (DEBUG) { + System.err.println("visitPut " + field); + } + + // skip putfields of primitive type + if (field.getFieldType().isPrimitiveType()) { + return; + } + IField f = getClassHierarchy().resolveField(field); + if (f == null) { + if (DEBUG) { + System.err.println("Could not resolve field " + field); + } + Warnings.add(FieldResolutionFailure.create(field)); + return; + } + assert isStatic || !symbolTable.isStringConstant(ref) : "put to string constant shouldn't be allowed?"; + if (isStatic) { + processPutStatic(rval, field, f); + } else { + processPutField(rval, ref, f); + } + } + + private void processPutField(int rval, int ref, IField f) { + assert !f.getFieldTypeReference().isPrimitiveType(); + PointerKey refKey = getPointerKeyForLocal(ref); + PointerKey rvalKey = getPointerKeyForLocal(rval); + // if (!supportFullPointerFlowGraph && + // contentsAreInvariant(rval)) { + if (contentsAreInvariant(symbolTable, du, rval)) { + system.recordImplicitPointsToSet(rvalKey); + InstanceKey[] ik = getInvariantContents(rval); + if (contentsAreInvariant(symbolTable, du, ref)) { + system.recordImplicitPointsToSet(refKey); + InstanceKey[] refk = getInvariantContents(ref); + for (int j = 0; j < refk.length; j++) { + if (!representsNullType(refk[j])) { + system.findOrCreateIndexForInstanceKey(refk[j]); + PointerKey p = getPointerKeyForInstanceField(refk[j], f); + for (int i = 0; i < ik.length; i++) { + system.newConstraint(p, ik[i]); + } + } + } + } else { + for (int i = 0; i < ik.length; i++) { + system.findOrCreateIndexForInstanceKey(ik[i]); + system.newSideEffect(getBuilder().new InstancePutFieldOperator(f, ik[i]), refKey); + } + } + } else { + if (contentsAreInvariant(symbolTable, du, ref)) { + system.recordImplicitPointsToSet(refKey); + InstanceKey[] refk = getInvariantContents(ref); + for (int j = 0; j < refk.length; j++) { + if (!representsNullType(refk[j])) { + system.findOrCreateIndexForInstanceKey(refk[j]); + PointerKey p = getPointerKeyForInstanceField(refk[j], f); + system.newConstraint(p, assignOperator, rvalKey); + } + } + } else { + if (DEBUG) { + System.err.println("adding side effect " + f); + } + system.newSideEffect(getBuilder().new PutFieldOperator(f, system.findOrCreatePointsToSet(rvalKey)), refKey); + } + } + } + + private void processPutStatic(int rval, FieldReference field, IField f) { + PointerKey fKey = getPointerKeyForStaticField(f); + PointerKey rvalKey = getPointerKeyForLocal(rval); + + // if (!supportFullPointerFlowGraph && + // contentsAreInvariant(rval)) { + if (contentsAreInvariant(symbolTable, du, rval)) { + system.recordImplicitPointsToSet(rvalKey); + InstanceKey[] ik = getInvariantContents(rval); + for (int i = 0; i < ik.length; i++) { + system.newConstraint(fKey, ik[i]); + } + } else { + system.newConstraint(fKey, assignOperator, rvalKey); + } + if (DEBUG) { + System.err.println("visitPut class init " + field.getDeclaringClass() + " " + field); + } + // side effect of putstatic: may call class initializer + IClass klass = getClassHierarchy().lookupClass(field.getDeclaringClass()); + if (klass == null) { + Warnings.add(FieldResolutionFailure.create(field)); + } else { + processClassInitializer(klass); + } + } + + /* + * @see com.ibm.wala.ssa.Instruction.Visitor#visitInvoke(com.ibm.wala.ssa.InvokeInstruction) + */ + @Override + public void visitInvoke(SSAInvokeInstruction instruction) { + visitInvokeInternal(instruction, new DefaultInvariantComputer()); + } + + protected void visitInvokeInternal(final SSAAbstractInvokeInstruction instruction, InvariantComputer invs) { + if (DEBUG) { + System.err.println("visitInvoke: " + instruction); + } + + PointerKey uniqueCatch = null; + if (hasUniqueCatchBlock(instruction, ir)) { + uniqueCatch = getBuilder().getUniqueCatchKey(instruction, ir, node); + } + + InstanceKey[][] invariantParameters = invs.computeInvariantParameters(instruction); + if (instruction.getCallSite().isStatic()) { + for (CGNode n : getBuilder().getTargetsForCall(node, instruction, invariantParameters)) { + getBuilder().processResolvedCall(node, instruction, n, invariantParameters, uniqueCatch); + if (DEBUG) { + System.err.println("visitInvoke class init " + n); + } + + // side effect of invoke: may call class initializer + processClassInitializer(n.getMethod().getDeclaringClass()); + } + } else { + // Add a side effect that will fire when we determine a value + // for a dispatch parameter. This side effect will create a new node + // and new constraints based on the new callee context. + IntSet params = getBuilder().getContextSelector().getRelevantParameters(node, instruction.getCallSite()); + if (! params.contains(0)) { + params = IntSetUtil.makeMutableCopy(params); + ((MutableIntSet)params).add(0); + } + final int vns[] = new int[ params.size() ]; + params.foreach(new IntSetAction() { + private int i = 0; + public void act(int x) { + vns[i++] = instruction.getUse(x); + } + }); + + if (contentsAreInvariant(symbolTable, du, vns)) { + for(CGNode n : getBuilder().getTargetsForCall(node, instruction, invariantParameters)) { + getBuilder().processResolvedCall(node, instruction, n, invariantParameters, uniqueCatch); + // side effect of invoke: may call class initializer + processClassInitializer(n.getMethod().getDeclaringClass()); + } + } else { + if (DEBUG) { + System.err.println("Add side effect, dispatch to " + instruction + " for " + params); + } + + final List pks = new ArrayList(params.size()); + params.foreach(new IntSetAction() { + public void act(int x) { + if (!contentsAreInvariant(symbolTable, du, instruction.getUse(x))) { + pks.add(getBuilder().getPointerKeyForLocal(node, instruction.getUse(x))); + } + } + }); + + DispatchOperator dispatchOperator = getBuilder().new DispatchOperator(instruction, node, + invariantParameters, uniqueCatch, params); + system.newSideEffect(dispatchOperator, pks.toArray(new PointerKey[pks.size()])); + } + } + } + + /* + * @see com.ibm.wala.ssa.Instruction.Visitor#visitNew(com.ibm.wala.ssa.NewInstruction) + */ + @Override + public void visitNew(SSANewInstruction instruction) { + InstanceKey iKey = getInstanceKeyForAllocation(instruction.getNewSite()); + + if (iKey == null) { + // something went wrong. I hope someone raised a warning. + return; + } + PointerKey def = getPointerKeyForLocal(instruction.getDef()); + IClass klass = iKey.getConcreteType(); + + if (DEBUG) { + System.err.println("visitNew: " + instruction + " " + iKey + " " + system.findOrCreateIndexForInstanceKey(iKey)); + } + + if (klass == null) { + if (DEBUG) { + System.err.println("Resolution failure: " + instruction); + } + return; + } + + if (!contentsAreInvariant(symbolTable, du, instruction.getDef())) { + system.newConstraint(def, iKey); + } else { + system.findOrCreateIndexForInstanceKey(iKey); + system.recordImplicitPointsToSet(def); + } + + // side effect of new: may call class initializer + if (DEBUG) { + System.err.println("visitNew call clinit: " + klass); + } + processClassInitializer(klass); + + // add instance keys and pointer keys for array contents + int dim = 0; + InstanceKey lastInstance = iKey; + while (klass != null && klass.isArrayClass()) { + klass = ((ArrayClass) klass).getElementClass(); + // klass == null means it's a primitive + if (klass != null && klass.isArrayClass()) { + if (instruction.getNumberOfUses() <= (dim + 1)) { + break; + } + int sv = instruction.getUse(dim + 1); + if (ir.getSymbolTable().isIntegerConstant(sv)) { + Integer c = (Integer) ir.getSymbolTable().getConstantValue(sv); + if (c.intValue() == 0) { + break; + } + } + InstanceKey ik = getInstanceKeyForMultiNewArray(instruction.getNewSite(), dim); + PointerKey pk = getPointerKeyForArrayContents(lastInstance); + if (DEBUG_MULTINEWARRAY) { + System.err.println("multinewarray constraint: "); + System.err.println(" pk: " + pk); + System.err.println(" ik: " + system.findOrCreateIndexForInstanceKey(ik) + " concrete type " + ik.getConcreteType() + + " is " + ik); + System.err.println(" klass:" + klass); + } + system.newConstraint(pk, ik); + lastInstance = ik; + dim++; + } + } + } + + /* + * @see com.ibm.wala.ssa.Instruction.Visitor#visitThrow(com.ibm.wala.ssa.ThrowInstruction) + */ + @Override + public void visitThrow(SSAThrowInstruction instruction) { + // don't do anything: we handle exceptional edges + // in a separate pass + } + + /* + * @see com.ibm.wala.ssa.Instruction.Visitor#visitGetCaughtException(com.ibm.wala.ssa.GetCaughtExceptionInstruction) + */ + @Override + public void visitGetCaughtException(SSAGetCaughtExceptionInstruction instruction) { + List peis = getIncomingPEIs(ir, getBasicBlock()); + PointerKey def = getPointerKeyForLocal(instruction.getDef()); + // SJF: we don't optimize based on dead catch blocks yet ... it's a little + // tricky due interaction with the SINGLE_USE optimization which directly + // shoves exceptional return values from calls into exception vars. + // it may not be worth doing this. + // if (hasNoInterestingUses(instruction.getDef(), du)) { + // solver.recordImplicitPointsToSet(def); + // } else { + Set types = getCaughtExceptionTypes(instruction, ir); + getBuilder().addExceptionDefConstraints(ir, du, node, peis, def, types); + // } + } + + /** + * TODO: What is this doing? Document me! + */ + private int booleanConstantTest(SSAConditionalBranchInstruction c, int v) { + int result = 0; + + // right for OPR_eq + if ((symbolTable.isZeroOrFalse(c.getUse(0)) && c.getUse(1) == v) + || (symbolTable.isZeroOrFalse(c.getUse(1)) && c.getUse(0) == v)) { + result = -1; + } else if ((symbolTable.isOneOrTrue(c.getUse(0)) && c.getUse(1) == v) + || (symbolTable.isOneOrTrue(c.getUse(1)) && c.getUse(0) == v)) { + result = 1; + } + + if (c.getOperator() == ConditionalBranchInstruction.Operator.NE) { + result = -result; + } + + return result; + } + + private int nullConstantTest(SSAConditionalBranchInstruction c, int v) { + if ((symbolTable.isNullConstant(c.getUse(0)) && c.getUse(1) == v) + || (symbolTable.isNullConstant(c.getUse(1)) && c.getUse(0) == v)) { + if (c.getOperator() == ConditionalBranchInstruction.Operator.EQ) { + return 1; + } else { + return -1; + } + } else { + return 0; + } + } + + @Override + public void visitPhi(SSAPhiInstruction instruction) { + if (ir.getMethod() instanceof AbstractRootMethod) { + PointerKey dst = getPointerKeyForLocal(instruction.getDef()); + if (hasNoInterestingUses(instruction.getDef())) { + system.recordImplicitPointsToSet(dst); + } else { + for (int i = 0; i < instruction.getNumberOfUses(); i++) { + PointerKey use = getPointerKeyForLocal(instruction.getUse(i)); + if (contentsAreInvariant(symbolTable, du, instruction.getUse(i))) { + system.recordImplicitPointsToSet(use); + InstanceKey[] ik = getInvariantContents(instruction.getUse(i)); + for (int j = 0; j < ik.length; j++) { + system.newConstraint(dst, ik[j]); + } + } else { + system.newConstraint(dst, assignOperator, use); + } + } + } + } + } + + /* + * @see com.ibm.wala.ssa.SSAInstruction.Visitor#visitPi(com.ibm.wala.ssa.SSAPiInstruction) + */ + @Override + public void visitPi(SSAPiInstruction instruction) { + int dir; + + if (hasNoInterestingUses(instruction.getDef())) { + PointerKey dst = getPointerKeyForLocal(instruction.getDef()); + system.recordImplicitPointsToSet(dst); + } else { + ControlFlowGraph cfg = ir.getControlFlowGraph(); + if (com.ibm.wala.cfg.Util.endsWithConditionalBranch(cfg, getBasicBlock()) && cfg.getSuccNodeCount(getBasicBlock()) == 2) { + SSAConditionalBranchInstruction cond = (SSAConditionalBranchInstruction) com.ibm.wala.cfg.Util.getLastInstruction(cfg, + getBasicBlock()); + SSAInstruction cause = instruction.getCause(); + BasicBlock target = (BasicBlock) cfg.getNode(instruction.getSuccessor()); + + if ((cause instanceof SSAInstanceofInstruction)) { + int direction = booleanConstantTest(cond, cause.getDef()); + if (direction != 0) { + TypeReference type = ((SSAInstanceofInstruction) cause).getCheckedType(); + IClass cls = getClassHierarchy().lookupClass(type); + if (cls == null) { + PointerKey dst = getPointerKeyForLocal(instruction.getDef()); + addPiAssignment(dst, instruction.getVal()); + } else { + PointerKey dst = getFilteredPointerKeyForLocal(instruction.getDef(), new FilteredPointerKey.SingleClassFilter(cls)); + PointerKey src = getPointerKeyForLocal(instruction.getVal()); + if ((target == com.ibm.wala.cfg.Util.getTakenSuccessor(cfg, getBasicBlock()) && direction == 1) + || (target == com.ibm.wala.cfg.Util.getNotTakenSuccessor(cfg, getBasicBlock()) && direction == -1)) { + system.newConstraint(dst, getBuilder().filterOperator, src); + } else { + system.newConstraint(dst, getBuilder().inverseFilterOperator, src); + } + } + } + } else if ((dir = nullConstantTest(cond, instruction.getVal())) != 0) { + if ((target == com.ibm.wala.cfg.Util.getTakenSuccessor(cfg, getBasicBlock()) && dir == -1) + || (target == com.ibm.wala.cfg.Util.getNotTakenSuccessor(cfg, getBasicBlock()) && dir == 1)) { + PointerKey dst = getPointerKeyForLocal(instruction.getDef()); + addPiAssignment(dst, instruction.getVal()); + } + } else { + PointerKey dst = getPointerKeyForLocal(instruction.getDef()); + addPiAssignment(dst, instruction.getVal()); + } + } else { + PointerKey dst = getPointerKeyForLocal(instruction.getDef()); + addPiAssignment(dst, instruction.getVal()); + } + } + } + + /** + * Add a constraint to the system indicating that the contents of local src flows to dst, with no special type filter. + */ + private void addPiAssignment(PointerKey dst, int src) { + PointerKey srcKey = getPointerKeyForLocal(src); + if (contentsAreInvariant(symbolTable, du, src)) { + system.recordImplicitPointsToSet(srcKey); + InstanceKey[] ik = getInvariantContents(src); + for (int j = 0; j < ik.length; j++) { + system.newConstraint(dst, ik[j]); + } + } else { + system.newConstraint(dst, assignOperator, srcKey); + } + + } + + public ISSABasicBlock getBasicBlock() { + return basicBlock; + } + + /** + * The calling loop must call this in each iteration! + */ + public void setBasicBlock(ISSABasicBlock block) { + basicBlock = block; + } + + protected interface InvariantComputer { + + InstanceKey[][] computeInvariantParameters(SSAAbstractInvokeInstruction call); + + } + + public class DefaultInvariantComputer implements InvariantComputer { + /** + * Side effect: records invariant parameters as implicit points-to-sets. + * + * @return if non-null, then result[i] holds the set of instance keys which may be passed as the ith parameter. (which must be + * invariant) + */ + public InstanceKey[][] computeInvariantParameters(SSAAbstractInvokeInstruction call) { + InstanceKey[][] constParams = null; + for (int i = 0; i < call.getNumberOfUses(); i++) { + // not sure how getUse(i) <= 0 .. dead code? + // TODO: investigate + if (call.getUse(i) > 0) { + if (contentsAreInvariant(symbolTable, du, call.getUse(i))) { + system.recordImplicitPointsToSet(getPointerKeyForLocal(call.getUse(i))); + if (constParams == null) { + constParams = new InstanceKey[call.getNumberOfUses()][]; + } + constParams[i] = getInvariantContents(call.getUse(i)); + for (int j = 0; j < constParams[i].length; j++) { + system.findOrCreateIndexForInstanceKey(constParams[i][j]); + } + } + } + } + return constParams; + } + } + + @Override + public void visitLoadMetadata(SSALoadMetadataInstruction instruction) { + PointerKey def = getPointerKeyForLocal(instruction.getDef()); + assert instruction.getType() == TypeReference.JavaLangClass; + InstanceKey iKey = getInstanceKeyForClassObject((TypeReference) instruction.getToken()); + IClass klass = getClassHierarchy().lookupClass((TypeReference) instruction.getToken()); + if (klass != null) { + processClassInitializer(klass); + } + + if (!contentsAreInvariant(symbolTable, du, instruction.getDef())) { + system.newConstraint(def, iKey); + } else { + system.findOrCreateIndexForInstanceKey(iKey); + system.recordImplicitPointsToSet(def); + } + } + + /** + * TODO: lift most of this logic to PropagationCallGraphBuilder + * + * Add a call to the class initializer from the root method. + */ + private void processClassInitializer(IClass klass) { + + assert klass != null; + + if (!getBuilder().getOptions().getHandleStaticInit()) { + return; + } + + if (getBuilder().clinitVisited.contains(klass)) { + return; + } + getBuilder().clinitVisited.add(klass); + + if (klass.getClassInitializer() != null) { + if (DEBUG) { + System.err.println("process class initializer for " + klass); + } + + // add an invocation from the fake root method to the + AbstractRootMethod fakeWorldClinitMethod = (AbstractRootMethod) callGraph.getFakeWorldClinitNode().getMethod(); + MethodReference m = klass.getClassInitializer().getReference(); + CallSiteReference site = CallSiteReference.make(1, m, IInvokeInstruction.Dispatch.STATIC); + IMethod targetMethod = getOptions().getMethodTargetSelector().getCalleeTarget(callGraph.getFakeRootNode(), site, null); + if (targetMethod != null) { + CGNode target = getTargetForCall(callGraph.getFakeRootNode(), site, null, null); + if (target != null && callGraph.getPredNodeCount(target) == 0) { + SSAAbstractInvokeInstruction s = fakeWorldClinitMethod.addInvocation(new int[0], site); + PointerKey uniqueCatch = getBuilder().getPointerKeyForExceptionalReturnValue(callGraph.getFakeRootNode()); + getBuilder().processResolvedCall(callGraph.getFakeWorldClinitNode(), s, target, null, uniqueCatch); + } + } + } + + IClass sc = klass.getSuperclass(); + if (sc != null) { + processClassInitializer(sc); + } + } + } + + /** + * Add constraints for a call site after we have computed a reachable target for the dispatch + * + * Side effect: add edge to the call graph. + * + * @param instruction + * @param constParams if non-null, then constParams[i] holds the set of instance keys that are passed as param i, or null if param + * i is not invariant + * @param uniqueCatchKey if non-null, then this is the unique PointerKey that catches all exceptions from this call site. + */ + @SuppressWarnings("deprecation") + private void processResolvedCall(CGNode caller, SSAAbstractInvokeInstruction instruction, CGNode target, + InstanceKey[][] constParams, PointerKey uniqueCatchKey) { + + if (DEBUG) { + System.err.println("processResolvedCall: " + caller + " ," + instruction + " , " + target); + } + + if (DEBUG) { + System.err.println("addTarget: " + caller + " ," + instruction + " , " + target); + } + caller.addTarget(instruction.getCallSite(), target); + + if (FakeRootMethod.isFakeRootMethod(caller.getMethod().getReference())) { + if (entrypointCallSites.contains(instruction.getCallSite())) { + callGraph.registerEntrypoint(target); + } + } + + if (!haveAlreadyVisited(target)) { + markDiscovered(target); + } + + processCallingConstraints(caller, instruction, target, constParams, uniqueCatchKey); + } + + protected void processCallingConstraints(CGNode caller, SSAAbstractInvokeInstruction instruction, CGNode target, + InstanceKey[][] constParams, PointerKey uniqueCatchKey) { + // TODO: i'd like to enable this optimization, but it's a little tricky + // to recover the implicit points-to sets with recursion. TODO: don't + // be lazy and code the recursive logic to enable this. + // if (hasNoInstructions(target)) { + // // record points-to sets for formals implicitly .. computed on + // // demand. + // // TODO: generalize this by using hasNoInterestingUses on parameters. + // // however .. have to be careful to cache results in that case ... don't + // // want + // // to recompute du each time we process a call to Object. ! + // for (int i = 0; i < instruction.getNumberOfUses(); i++) { + // // we rely on the invariant that the value number for the ith parameter + // // is i+1 + // final int vn = i + 1; + // PointerKey formal = getPointerKeyForLocal(target, vn); + // if (target.getMethod().getParameterType(i).isReferenceType()) { + // system.recordImplicitPointsToSet(formal); + // } + // } + // } else { + // generate contraints from parameter passing + int nUses = instruction.getNumberOfParameters(); + int nExpected = target.getMethod().getNumberOfParameters(); + + /* + * int nExpected = target.getMethod().getReference().getNumberOfParameters(); if (!target.getMethod().isStatic() && + * !target.getMethod().isClinit()) { nExpected++; } + */ + + if (nUses != nExpected) { + // some sort of unverifiable code mismatch. give up. + return; + } + + // we're a little sloppy for now ... we don't filter calls to + // java.lang.Object. + // TODO: we need much more precise filters than cones in order to handle + // the various types of dispatch logic. We need a filter that expresses + // "the set of types s.t. x.foo resolves to y.foo." + for (int i = 0; i < instruction.getNumberOfParameters(); i++) { + if (target.getMethod().getParameterType(i).isReferenceType()) { + PointerKey formal = getTargetPointerKey(target, i); + if (constParams != null && constParams[i] != null) { + InstanceKey[] ik = constParams[i]; + for (int j = 0; j < ik.length; j++) { + system.newConstraint(formal, ik[j]); + } + } else { + if (instruction.getUse(i) < 0) { + Assertions.UNREACHABLE("unexpected " + instruction + " in " + caller); + } + PointerKey actual = getPointerKeyForLocal(caller, instruction.getUse(i)); + if (formal instanceof FilteredPointerKey) { + system.newConstraint(formal, filterOperator, actual); + } else { + system.newConstraint(formal, assignOperator, actual); + } + } + } + } + + // generate contraints from return value. + if (instruction.hasDef() && instruction.getDeclaredResultType().isReferenceType()) { + PointerKey result = getPointerKeyForLocal(caller, instruction.getDef()); + PointerKey ret = getPointerKeyForReturnValue(target); + system.newConstraint(result, assignOperator, ret); + } + // generate constraints from exception return value. + PointerKey e = getPointerKeyForLocal(caller, instruction.getException()); + PointerKey er = getPointerKeyForExceptionalReturnValue(target); + if (SHORT_CIRCUIT_SINGLE_USES && uniqueCatchKey != null) { + // e has exactly one use. so, represent e implicitly + system.newConstraint(uniqueCatchKey, assignOperator, er); + } else { + system.newConstraint(e, assignOperator, er); + } + // } + } + + /** + * An operator to fire when we discover a potential new callee for a virtual or interface call site. + * + * This operator will create a new callee context and constraints if necessary. + */ + final class DispatchOperator extends AbstractOperator implements IPointerOperator { + private final SSAAbstractInvokeInstruction call; + + private final CGNode node; + + private final InstanceKey[][] constParams; + + private final PointerKey uniqueCatch; + + /** + * relevant parameter indices for the registered {@link ContextSelector} + * + * @see ContextSelector#getRelevantParameters(CGNode, CallSiteReference) + */ + private final int[] dispatchIndices; + + /** + * The set of instance keys that have already been processed. + * previousPtrs[i] contains the processed instance keys for parameter + * position dispatchIndices[i] + */ + final private MutableIntSet[] previousPtrs; + + /** + * @param call + * @param node + * @param constParams if non-null, then constParams[i] holds the String constant that is passed as param i, or null if param i + * is not a String constant + */ + DispatchOperator(SSAAbstractInvokeInstruction call, CGNode node, InstanceKey[][] constParams, + PointerKey uniqueCatch, IntSet dispatchIndices) { + this.call = call; + this.node = node; + this.constParams = constParams; + this.uniqueCatch = uniqueCatch; + this.dispatchIndices = IntSetUtil.toArray(dispatchIndices); + // we better always be interested in the receiver + assert this.dispatchIndices[0] == 0; + previousPtrs = new MutableIntSet[dispatchIndices.size()]; + for(int i = 0; i < previousPtrs.length; i++) { + previousPtrs[i] = IntSetUtil.getDefaultIntSetFactory().make(); + } + } + + + + /* + * @see com.ibm.wala.dataflow.fixpoint.UnaryOperator#evaluate(com.ibm.wala.dataflow.fixpoint.IVariable, + * com.ibm.wala.dataflow.fixpoint.IVariable) + */ + @Override + public byte evaluate(PointsToSetVariable lhs, final PointsToSetVariable[] rhs) { + assert dispatchIndices.length >= rhs.length : "bad operator at " + call; + // did evaluating the dispatch operation add a new possible target + // to the call site? + final MutableBoolean addedNewTarget = new MutableBoolean(); + + final MutableIntSet receiverVals; + if (constParams != null && constParams[0] != null) { + receiverVals = IntSetUtil.make(); + for(InstanceKey ik : constParams[0]) { + receiverVals.add(system.getInstanceIndex(ik)); + } + } else { + receiverVals = rhs[0].getValue(); + } + + if (receiverVals == null) { + // this constraint was put on the work list, probably by + // initialization, + // even though the right-hand-side is empty. + // TODO: be more careful about what goes on the worklist to + // avoid this. + if (DEBUG) { + System.err.println("EVAL dispatch with value null"); + } + return NOT_CHANGED; + + } + // we handle the parameter positions one by one, rather than enumerating + // the cartesian product of possibilities. this disallows + // context-sensitivity policies like true CPA, but is necessary for + // performance. + InstanceKey keys[] = new InstanceKey[constParams == null? dispatchIndices[dispatchIndices.length-1]+1: constParams.length]; + // determine whether we're handling a new receiver; used later + // to check for redundancy + boolean newReceiver = !receiverVals.isSubset(previousPtrs[0]); + // keep separate rhsIndex, since it doesn't advance for constant + // parameters + int rhsIndex = (constParams != null && constParams[0] != null)? 0: 1; + // this flag is set to true if we ever call handleAllReceivers() in the + // loop below. we need to catch the case where we have a new receiver, but + // there are no other dispatch indices with new values + boolean propagatedReceivers = false; + // we start at index 1 since we need to handle the receiver specially; see + // below + for (int index = 1; index < dispatchIndices.length; index++) { + try { + MonitorUtil.throwExceptionIfCanceled(monitor); + } catch (CancelException e) { + throw new CancelRuntimeException(e); + } + int paramIndex = dispatchIndices[index]; + assert keys[paramIndex] == null; + final MutableIntSet prevAtIndex = previousPtrs[index]; + if (constParams != null && constParams[paramIndex] != null) { + // we have a constant parameter. only need to propagate again if we've never done it before or if we have a new receiver + if (newReceiver || prevAtIndex.isEmpty()) { + for(int i = 0; i < constParams[paramIndex].length; i++) { + keys[paramIndex] = constParams[paramIndex][i]; + handleAllReceivers(receiverVals,keys, addedNewTarget); + propagatedReceivers = true; + int ii = system.instanceKeys.getMappedIndex(constParams[paramIndex][i]); + prevAtIndex.add(ii); + } + } + } else { // non-constant parameter + PointsToSetVariable v = rhs[rhsIndex]; + if (v.getValue() != null) { + IntIterator ptrs = v.getValue().intIterator(); + while (ptrs.hasNext()) { + int ptr = ptrs.next(); + if (newReceiver || !prevAtIndex.contains(ptr)) { + keys[paramIndex] = system.getInstanceKey(ptr); + handleAllReceivers(receiverVals,keys, addedNewTarget); + propagatedReceivers = true; + prevAtIndex.add(ptr); + } + } + } + rhsIndex++; + } + keys[paramIndex] = null; + } + if (newReceiver) { + if (!propagatedReceivers) { + // we have a new receiver value, and it wasn't propagated at all, + // so propagate it now + handleAllReceivers(receiverVals, keys, addedNewTarget); + } + // update receiver cache + previousPtrs[0].addAll(receiverVals); + } + + byte sideEffectMask = addedNewTarget.b ? (byte) SIDE_EFFECT_MASK : 0; + return (byte) (NOT_CHANGED | sideEffectMask); + } + + private void handleAllReceivers(MutableIntSet receiverVals, InstanceKey[] keys, MutableBoolean sideEffect) { + assert keys[0] == null; + IntIterator receiverIter = receiverVals.intIterator(); + while (receiverIter.hasNext()) { + final int rcvr = receiverIter.next(); + keys[0] = system.getInstanceKey(rcvr); + if (clone2Assign) { + // for efficiency: assume that only call sites that reference + // clone() might dispatch to clone methods + if (call.getCallSite().getDeclaredTarget().getSelector().equals(cloneSelector)) { + IClass recv = (keys[0] != null) ? keys[0].getConcreteType() : null; + IMethod targetMethod = getOptions().getMethodTargetSelector().getCalleeTarget(node, call.getCallSite(), recv); + if (targetMethod != null && targetMethod.getReference().equals(CloneInterpreter.CLONE)) { + // treat this call to clone as an assignment + PointerKey result = getPointerKeyForLocal(node, call.getDef()); + PointerKey receiver = getPointerKeyForLocal(node, call.getReceiver()); + system.newConstraint(result, assignOperator, receiver); + return; + } + } + } + CGNode target = getTargetForCall(node, call.getCallSite(), keys[0].getConcreteType(), keys); + if (target == null) { + // This indicates an error; I sure hope getTargetForCall + // raised a warning about this! + if (DEBUG) { + System.err.println("Warning: null target for call " + call); + } + } else { + IntSet targets = getCallGraph().getPossibleTargetNumbers(node, call.getCallSite()); + // even if we've seen this target before, if we have constant + // parameters, we may need to re-process the call, as the constraints + // for the first time we reached this target may not have been fully + // general. TODO a more refined check? + if (targets != null && targets.contains(target.getGraphNodeId()) && noConstParams()) { + // do nothing; we've previously discovered and handled this + // receiver for this call site. + } else { + // process the newly discovered target for this call + sideEffect.b = true; + processResolvedCall(node, call, target, constParams, uniqueCatch); + if (!haveAlreadyVisited(target)) { + markDiscovered(target); + } + } + } + } + keys[0] = null; + } + + private boolean noConstParams() { + if (constParams != null) { + for (int i = 0; i < constParams.length; i++) { + if (constParams[i] != null) { + for (int j = 0; j < constParams[i].length; i++) { + if (constParams[i][j] != null) { + return false; + } + } + } + } + } + return true; + } + + + + @Override + public String toString() { + return "Dispatch to " + call + " in node " + node; + } + + @Override + public int hashCode() { + return node.hashCode() + 90289 * call.hashCode(); + } + + @Override + public boolean equals(Object o) { + // note that these are not necessarily canonical, since + // with synthetic factories we may regenerate constraints + // many times. TODO: change processing of synthetic factories + // so that we guarantee to insert each dispatch equation + // only once ... if this were true we could optimize this + // with reference equality + + // instanceof is OK because this class is final + if (o instanceof DispatchOperator) { + DispatchOperator other = (DispatchOperator) o; + return node.equals(other.node) && call.equals(other.call) && Arrays.deepEquals(constParams, other.constParams); + } else { + return false; + } + } + + /* + * @see com.ibm.wala.ipa.callgraph.propagation.IPointerOperator#isComplex() + */ + public boolean isComplex() { + return true; + } + } + + protected void iterateCrossProduct(final CGNode caller, final SSAAbstractInvokeInstruction call, IntSet parameters, + final InstanceKey[][] invariants, final VoidFunction f) { + final int params[] = IntSetUtil.toArray(parameters); + final InstanceKey[] keys = new InstanceKey[call.getNumberOfParameters()]; + final CallSiteReference site = call.getCallSite(); + new Object() { + private void rec(final int pi) { + if (pi == params.length) { + f.apply(keys); + } else { + final int p = params[pi]; + int vn = call.getUse(p); + PointerKey var = getPointerKeyForLocal(caller, vn); + InstanceKey[] ik = invariants != null ? invariants[p] : null; + if (ik != null) { + if (ik.length > 0) { + for (int i = 0; i < ik.length; i++) { + system.findOrCreateIndexForInstanceKey(ik[i]); + keys[p] = ik[i]; + rec(pi + 1); + } + } else { + if (!site.isDispatch() || p != 0) { + keys[p] = null; + rec(pi + 1); + } + } + } else { + IntSet s = system.findOrCreatePointsToSet(var).getValue(); + if (s != null && !s.isEmpty()) { + s.foreach(new IntSetAction() { + public void act(int x) { + keys[p] = system.getInstanceKey(x); + rec(pi + 1); + } + }); + } else { + if (!site.isDispatch() || p != 0) { + keys[p] = null; + rec(pi + 1); + } + } + } + } + } + }.rec(0); + } + + protected Set getTargetsForCall(final CGNode caller, final SSAAbstractInvokeInstruction instruction, InstanceKey[][] invs) { + // This method used to take a CallSiteReference as a parameter, rather than + // an SSAAbstractInvokeInstruction. This was bad, since it's + // possible for multiple invoke instructions with different actual + // parameters to be associated with a single CallSiteReference. Changed + // to take the invoke instruction as a parameter instead, since invs is + // associated with the instruction + final CallSiteReference site = instruction.getCallSite(); + IntSet params = contextSelector.getRelevantParameters(caller, site); + if (!site.isStatic() && !params.contains(0)) { + params = IntSetUtil.makeMutableCopy(params); + ((MutableIntSet)params).add(0); + } + final Set targets = HashSetFactory.make(); + VoidFunction f = new VoidFunction() { + public void apply(InstanceKey[] v) { + IClass recv = null; + if (site.isDispatch()) { + recv = v[0].getConcreteType(); + } + CGNode target = getTargetForCall(caller, site, recv, v); + if (target != null) { + targets.add(target); + } + } + }; + iterateCrossProduct(caller, instruction, params, invs, f); + return targets; + } + + public boolean hasNoInterestingUses(CGNode node, int vn, DefUse du) { + + if (du == null) { + throw new IllegalArgumentException("du is null"); + } + if (vn <= 0) { + throw new IllegalArgumentException("v is invalid: " + vn); + } + // todo: enhance this by solving a dead-code elimination + // problem. + InterestingVisitor v = makeInterestingVisitor(node, vn); + for (Iterator it = du.getUses(v.vn); it.hasNext();) { + SSAInstruction s = (SSAInstruction) it.next(); + s.visit(v); + if (v.bingo) { + return false; + } + } + return true; + } + + protected InterestingVisitor makeInterestingVisitor(CGNode node, int vn) { + return new InterestingVisitor(vn); + } + + /** + * sets bingo to true when it visits an interesting instruction + */ + protected static class InterestingVisitor extends SSAInstruction.Visitor { + protected final int vn; + + protected InterestingVisitor(int vn) { + this.vn = vn; + } + + protected boolean bingo = false; + + @Override + public void visitArrayLoad(SSAArrayLoadInstruction instruction) { + if (!instruction.typeIsPrimitive() && instruction.getArrayRef() == vn) { + bingo = true; + } + } + + @Override + public void visitArrayStore(SSAArrayStoreInstruction instruction) { + if (!instruction.typeIsPrimitive() && (instruction.getArrayRef() == vn || instruction.getValue() == vn)) { + bingo = true; + } + } + + @Override + public void visitCheckCast(SSACheckCastInstruction instruction) { + bingo = true; + } + + @Override + public void visitGet(SSAGetInstruction instruction) { + FieldReference field = instruction.getDeclaredField(); + if (!field.getFieldType().isPrimitiveType()) { + bingo = true; + } + } + + @Override + public void visitGetCaughtException(SSAGetCaughtExceptionInstruction instruction) { + bingo = true; + } + + @Override + public void visitInvoke(SSAInvokeInstruction instruction) { + bingo = true; + } + + @Override + public void visitPhi(SSAPhiInstruction instruction) { + bingo = true; + } + + @Override + public void visitPi(SSAPiInstruction instruction) { + bingo = true; + } + + @Override + public void visitPut(SSAPutInstruction instruction) { + FieldReference field = instruction.getDeclaredField(); + if (!field.getFieldType().isPrimitiveType()) { + bingo = true; + } + } + + @Override + public void visitReturn(SSAReturnInstruction instruction) { + bingo = true; + } + + @Override + public void visitThrow(SSAThrowInstruction instruction) { + bingo = true; + } + } + + /** + * TODO: enhance this logic using type inference + * + * @param instruction + * @return true if we need to filter the receiver type to account for virtual dispatch + */ + @SuppressWarnings("unused") + private boolean needsFilterForReceiver(SSAAbstractInvokeInstruction instruction, CGNode target) { + + FilteredPointerKey.TypeFilter f = (FilteredPointerKey.TypeFilter) target.getContext().get(ContextKey.PARAMETERS[0]); + + if (f != null) { + // the context selects a particular concrete type for the receiver. + // we need to filter, unless the declared receiver type implies the + // concrete type (TODO: need to implement this optimization) + return true; + } + + // don't need to filter for invokestatic + if (instruction.getCallSite().isStatic() || instruction.getCallSite().isSpecial()) { + return false; + } + + MethodReference declaredTarget = instruction.getDeclaredTarget(); + IMethod resolvedTarget = getClassHierarchy().resolveMethod(declaredTarget); + if (resolvedTarget == null) { + // there's some problem that will be flagged as a warning + return true; + } + + return true; + } + + private boolean isRootType(IClass klass) { + return klass.getClassHierarchy().isRootClass(klass); + } + + @SuppressWarnings("unused") + private boolean isRootType(FilteredPointerKey.TypeFilter filter) { + if (filter instanceof FilteredPointerKey.SingleClassFilter) { + return isRootType(((FilteredPointerKey.SingleClassFilter) filter).getConcreteType()); + } else { + return false; + } + } + + /** + * TODO: enhance this logic using type inference TODO!!!: enhance filtering to consider concrete types, not just cones. + * precondition: needs Filter + * + * @param target + * @return an IClass which represents + */ + protected PointerKey getTargetPointerKey(CGNode target, int index) { + int vn; + if (target.getIR() != null) { + vn = target.getIR().getSymbolTable().getParameter(index); + } else { + vn = index+1; + } + + FilteredPointerKey.TypeFilter filter = (FilteredPointerKey.TypeFilter) target.getContext().get(ContextKey.PARAMETERS[index]); + if (filter != null && !filter.isRootFilter()) { + return pointerKeyFactory.getFilteredPointerKeyForLocal(target, vn, filter); + + } else if (index == 0 && !target.getMethod().isStatic()) { + // the context does not select a particular concrete type for the + // receiver, so use the type of the method + IClass C = getReceiverClass(target.getMethod()); + if (C.getClassHierarchy().getRootClass().equals(C)) { + return pointerKeyFactory.getPointerKeyForLocal(target, vn); + } else { + return pointerKeyFactory.getFilteredPointerKeyForLocal(target, vn, new FilteredPointerKey.SingleClassFilter(C)); + } + + } else { + return pointerKeyFactory.getPointerKeyForLocal(target, vn); + } + } + + /** + * @param method + * @return the receiver class for this method. + */ + private IClass getReceiverClass(IMethod method) { + TypeReference formalType = method.getParameterType(0); + IClass C = getClassHierarchy().lookupClass(formalType); + if (method.isStatic()) { + Assertions.UNREACHABLE("asked for receiver of static method " + method); + } + if (C == null) { + Assertions.UNREACHABLE("no class found for " + formalType + " recv of " + method); + } + return C; + } + + /** + * A value is "invariant" if we can figure out the instances it can ever point to locally, without resorting to propagation. + * + * @param valueNumber + * @return true iff the contents of the local with this value number can be deduced locally, without propagation + */ + protected boolean contentsAreInvariant(SymbolTable symbolTable, DefUse du, int valueNumber) { + if (isConstantRef(symbolTable, valueNumber)) { + return true; + } else if (SHORT_CIRCUIT_INVARIANT_SETS) { + SSAInstruction def = du.getDef(valueNumber); + if (def instanceof SSANewInstruction) { + return true; + } else { + return false; + } + } else { + return false; + } + } + + protected boolean contentsAreInvariant(SymbolTable symbolTable, DefUse du, int valueNumbers[]) { + for(int i = 0; i < valueNumbers.length; i++) { + if (! contentsAreInvariant(symbolTable, du, valueNumbers[i])) { + return false; + } + } + return true; + } + + /** + * precondition:contentsAreInvariant(valueNumber) + * + * @param valueNumber + * @return the complete set of instances that the local with vn=valueNumber may point to. + */ + protected InstanceKey[] getInvariantContents(SymbolTable symbolTable, DefUse du, CGNode node, int valueNumber, HeapModel hm) { + return getInvariantContents(symbolTable, du, node, valueNumber, hm, false); + } + + protected InstanceKey[] getInvariantContents(SymbolTable symbolTable, DefUse du, CGNode node, int valueNumber, HeapModel hm, + boolean ensureIndexes) { + InstanceKey[] result; + if (isConstantRef(symbolTable, valueNumber)) { + Object x = symbolTable.getConstantValue(valueNumber); + if (x instanceof String) { + // this is always the case in Java. use strong typing in the call to getInstanceKeyForConstant. + String S = (String) x; + TypeReference type = node.getMethod().getDeclaringClass().getClassLoader().getLanguage().getConstantType(S); + if (type == null) { + return new InstanceKey[0]; + } + InstanceKey ik = hm.getInstanceKeyForConstant(type, S); + if (ik != null) { + result = new InstanceKey[] { ik }; + } else { + result = new InstanceKey[0]; + } + } else { + // some non-built in type (e.g. Integer). give up on strong typing. + // language-specific subclasses (e.g. Javascript) should override this method to get strong typing + // with generics if desired. + TypeReference type = node.getMethod().getDeclaringClass().getClassLoader().getLanguage().getConstantType(x); + if (type == null) { + return new InstanceKey[0]; + } + InstanceKey ik = hm.getInstanceKeyForConstant(type, x); + if (ik != null) { + result = new InstanceKey[] { ik }; + } else { + result = new InstanceKey[0]; + } + } + } else { + SSANewInstruction def = (SSANewInstruction) du.getDef(valueNumber); + InstanceKey iKey = hm.getInstanceKeyForAllocation(node, def.getNewSite()); + result = (iKey == null) ? new InstanceKey[0] : new InstanceKey[] { iKey }; + } + + if (ensureIndexes) { + for (int i = 0; i < result.length; i++) { + system.findOrCreateIndexForInstanceKey(result[i]); + } + } + + return result; + } + + protected boolean isConstantRef(SymbolTable symbolTable, int valueNumber) { + if (valueNumber == -1) { + return false; + } + if (symbolTable.isConstant(valueNumber)) { + Object v = symbolTable.getConstantValue(valueNumber); + return (!(v instanceof Number)); + } else { + return false; + } + } + + /** + * @author sfink + * + * A warning for when we fail to resolve the type for a checkcast + */ + private static class CheckcastFailure extends Warning { + + final TypeReference type; + + CheckcastFailure(TypeReference type) { + super(Warning.SEVERE); + this.type = type; + } + + @Override + public String getMsg() { + return getClass().toString() + " : " + type; + } + + public static CheckcastFailure create(TypeReference type) { + return new CheckcastFailure(type); + } + } + + /** + * @author sfink + * + * A warning for when we fail to resolve the type for a field + */ + private static class FieldResolutionFailure extends Warning { + + final FieldReference field; + + FieldResolutionFailure(FieldReference field) { + super(Warning.SEVERE); + this.field = field; + } + + @Override + public String getMsg() { + return getClass().toString() + " : " + field; + } + + public static FieldResolutionFailure create(FieldReference field) { + return new FieldResolutionFailure(field); + } + } + + /* + * @see com.ibm.wala.ipa.callgraph.propagation.HeapModel#iteratePointerKeys() + */ + public Iterator iteratePointerKeys() { + return system.iteratePointerKeys(); + } + + public static Set getCaughtExceptionTypes(SSAGetCaughtExceptionInstruction instruction, IR ir) { + if (ir == null) { + throw new IllegalArgumentException("ir is null"); + } + if (instruction == null) { + throw new IllegalArgumentException("instruction is null"); + } + Iterator exceptionTypes = ((ExceptionHandlerBasicBlock) ir.getControlFlowGraph().getNode( + instruction.getBasicBlockNumber())).getCaughtExceptionTypes(); + HashSet types = HashSetFactory.make(10); + for (; exceptionTypes.hasNext();) { + IClass c = ir.getMethod().getClassHierarchy().lookupClass(exceptionTypes.next()); + if (c != null) { + types.add(c); + } + } + return types; + } + + public InstanceKey getInstanceKeyForPEI(CGNode node, ProgramCounter instr, TypeReference type) { + return getInstanceKeyForPEI(node, instr, type, instanceKeyFactory); + } + + /* + * @see com.ibm.wala.ipa.callgraph.propagation.PropagationCallGraphBuilder#makeSolver() + */ + @Override + protected IPointsToSolver makeSolver() { + return new StandardSolver(system, this); + // return usePreTransitiveSolver ? (IPointsToSolver) new PreTransitiveSolver(system, this) : new StandardSolver(system, this); + // return true ? (IPointsToSolver)new PreTransitiveSolver(system,this) : new + // StandardSolver(system,this); + } +} diff --git a/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/SmushedAllocationSiteInNode.java b/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/SmushedAllocationSiteInNode.java index 96ebd80b7..1627d95a4 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/SmushedAllocationSiteInNode.java +++ b/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/SmushedAllocationSiteInNode.java @@ -1,47 +1,47 @@ -/******************************************************************************* - * 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.ipa.callgraph.propagation; - -import com.ibm.wala.classLoader.IClass; -import com.ibm.wala.ipa.callgraph.CGNode; - -/** - * An {@link InstanceKey} which represents the set of all allocation sites - * of a given type in a {@link CGNode}. - * An instance key which represents a unique set for ALL allocation sites of a - * given type in a CGNode - */ -public class SmushedAllocationSiteInNode extends AbstractTypeInNode { - public SmushedAllocationSiteInNode(CGNode node, IClass type) { - super(node, type); - } - - @Override - public boolean equals(Object obj) { - // instanceof is OK because this class is final - if (obj instanceof SmushedAllocationSiteInNode) { - SmushedAllocationSiteInNode other = (SmushedAllocationSiteInNode) obj; - return getNode().equals(other.getNode()) && getConcreteType().equals(other.getConcreteType()); - } else { - return false; - } - } - - @Override - public int hashCode() { - return getNode().hashCode() * 8293 + getConcreteType().hashCode(); - } - - @Override - public String toString() { - return "SMUSHED " + getNode() + " : " + getConcreteType(); - } -} +/******************************************************************************* + * 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.ipa.callgraph.propagation; + +import com.ibm.wala.classLoader.IClass; +import com.ibm.wala.ipa.callgraph.CGNode; + +/** + * An {@link InstanceKey} which represents the set of all allocation sites + * of a given type in a {@link CGNode}. + * An instance key which represents a unique set for ALL allocation sites of a + * given type in a CGNode + */ +public class SmushedAllocationSiteInNode extends AbstractTypeInNode { + public SmushedAllocationSiteInNode(CGNode node, IClass type) { + super(node, type); + } + + @Override + public boolean equals(Object obj) { + // instanceof is OK because this class is final + if (obj instanceof SmushedAllocationSiteInNode) { + SmushedAllocationSiteInNode other = (SmushedAllocationSiteInNode) obj; + return getNode().equals(other.getNode()) && getConcreteType().equals(other.getConcreteType()); + } else { + return false; + } + } + + @Override + public int hashCode() { + return getNode().hashCode() * 8293 + getConcreteType().hashCode(); + } + + @Override + public String toString() { + return "SMUSHED " + getNode() + " : " + getConcreteType(); + } +} diff --git a/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/SmushedAllocationSiteInstanceKeys.java b/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/SmushedAllocationSiteInstanceKeys.java index 6c1231efa..ad9bc9751 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/SmushedAllocationSiteInstanceKeys.java +++ b/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/SmushedAllocationSiteInstanceKeys.java @@ -1,96 +1,96 @@ -/******************************************************************************* - * 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.ipa.callgraph.propagation; - -import com.ibm.wala.classLoader.ArrayClass; -import com.ibm.wala.classLoader.IClass; -import com.ibm.wala.classLoader.IMethod; -import com.ibm.wala.classLoader.NewSiteReference; -import com.ibm.wala.classLoader.ProgramCounter; -import com.ibm.wala.ipa.callgraph.AnalysisOptions; -import com.ibm.wala.ipa.callgraph.CGNode; -import com.ibm.wala.ipa.callgraph.propagation.cfa.ContainerContextSelector; -import com.ibm.wala.ipa.cha.IClassHierarchy; -import com.ibm.wala.types.TypeReference; - -/** - * This class provides instance keys where for a given type T in a CGNode N, there is one "abstract allocation site" instance for - * all T allocations in node N. - */ -public class SmushedAllocationSiteInstanceKeys implements InstanceKeyFactory { - - /** - * Governing call graph construction options - */ - private final AnalysisOptions options; - - /** - * Governing class hierarchy - */ - private final IClassHierarchy cha; - - private final ClassBasedInstanceKeys classBased; - - /** - * @param options Governing call graph construction options - */ - public SmushedAllocationSiteInstanceKeys(AnalysisOptions options, IClassHierarchy cha) { - this.options = options; - this.cha = cha; - this.classBased = new ClassBasedInstanceKeys(options, cha); - } - - public InstanceKey getInstanceKeyForAllocation(CGNode node, NewSiteReference allocation) { - IClass type = options.getClassTargetSelector().getAllocatedTarget(node, allocation); - if (type == null) { - return null; - } - - // disallow recursion in contexts. - if (node.getContext() instanceof ReceiverInstanceContext) { - IMethod m = node.getMethod(); - CGNode n = ContainerContextSelector.findNodeRecursiveMatchingContext(m, node.getContext()); - if (n != null) { - return new SmushedAllocationSiteInNode(n, type); - } - } - - InstanceKey key = new SmushedAllocationSiteInNode(node, type); - - return key; - } - - public InstanceKey getInstanceKeyForMultiNewArray(CGNode node, NewSiteReference allocation, int dim) { - ArrayClass type = (ArrayClass) options.getClassTargetSelector().getAllocatedTarget(node, allocation); - if (type == null) { - return null; - } - InstanceKey key = new MultiNewArrayInNode(node, allocation, type, dim); - - return key; - } - - public InstanceKey getInstanceKeyForConstant(TypeReference type, T S) { - if (options.getUseConstantSpecificKeys()) - return new ConstantKey(S, cha.lookupClass(type)); - else - return new ConcreteTypeKey(cha.lookupClass(type)); - } - - public InstanceKey getInstanceKeyForPEI(CGNode node, ProgramCounter pei, TypeReference type) { - return classBased.getInstanceKeyForPEI(node, pei, type); - } - - public InstanceKey getInstanceKeyForClassObject(TypeReference type) { - return classBased.getInstanceKeyForClassObject(type); - } - -} +/******************************************************************************* + * 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.ipa.callgraph.propagation; + +import com.ibm.wala.classLoader.ArrayClass; +import com.ibm.wala.classLoader.IClass; +import com.ibm.wala.classLoader.IMethod; +import com.ibm.wala.classLoader.NewSiteReference; +import com.ibm.wala.classLoader.ProgramCounter; +import com.ibm.wala.ipa.callgraph.AnalysisOptions; +import com.ibm.wala.ipa.callgraph.CGNode; +import com.ibm.wala.ipa.callgraph.propagation.cfa.ContainerContextSelector; +import com.ibm.wala.ipa.cha.IClassHierarchy; +import com.ibm.wala.types.TypeReference; + +/** + * This class provides instance keys where for a given type T in a CGNode N, there is one "abstract allocation site" instance for + * all T allocations in node N. + */ +public class SmushedAllocationSiteInstanceKeys implements InstanceKeyFactory { + + /** + * Governing call graph construction options + */ + private final AnalysisOptions options; + + /** + * Governing class hierarchy + */ + private final IClassHierarchy cha; + + private final ClassBasedInstanceKeys classBased; + + /** + * @param options Governing call graph construction options + */ + public SmushedAllocationSiteInstanceKeys(AnalysisOptions options, IClassHierarchy cha) { + this.options = options; + this.cha = cha; + this.classBased = new ClassBasedInstanceKeys(options, cha); + } + + public InstanceKey getInstanceKeyForAllocation(CGNode node, NewSiteReference allocation) { + IClass type = options.getClassTargetSelector().getAllocatedTarget(node, allocation); + if (type == null) { + return null; + } + + // disallow recursion in contexts. + if (node.getContext() instanceof ReceiverInstanceContext) { + IMethod m = node.getMethod(); + CGNode n = ContainerContextSelector.findNodeRecursiveMatchingContext(m, node.getContext()); + if (n != null) { + return new SmushedAllocationSiteInNode(n, type); + } + } + + InstanceKey key = new SmushedAllocationSiteInNode(node, type); + + return key; + } + + public InstanceKey getInstanceKeyForMultiNewArray(CGNode node, NewSiteReference allocation, int dim) { + ArrayClass type = (ArrayClass) options.getClassTargetSelector().getAllocatedTarget(node, allocation); + if (type == null) { + return null; + } + InstanceKey key = new MultiNewArrayInNode(node, allocation, type, dim); + + return key; + } + + public InstanceKey getInstanceKeyForConstant(TypeReference type, T S) { + if (options.getUseConstantSpecificKeys()) + return new ConstantKey(S, cha.lookupClass(type)); + else + return new ConcreteTypeKey(cha.lookupClass(type)); + } + + public InstanceKey getInstanceKeyForPEI(CGNode node, ProgramCounter pei, TypeReference type) { + return classBased.getInstanceKeyForPEI(node, pei, type); + } + + public InstanceKey getInstanceKeyForClassObject(TypeReference type) { + return classBased.getInstanceKeyForClassObject(type); + } + +} diff --git a/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/StandardSolver.java b/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/StandardSolver.java index d59107f99..bef1a27f1 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/StandardSolver.java +++ b/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/StandardSolver.java @@ -1,79 +1,79 @@ -/******************************************************************************* - * 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.ipa.callgraph.propagation; - - -import com.ibm.wala.util.CancelException; -import com.ibm.wala.util.MonitorUtil.IProgressMonitor; - -/** - * standard fixed-point iterative solver for pointer analysis - */ -public class StandardSolver extends AbstractPointsToSolver { - - private static final boolean DEBUG_PHASES = DEBUG || false; - - public StandardSolver(PropagationSystem system, PropagationCallGraphBuilder builder) { - super(system, builder); - } - - /* - * @see com.ibm.wala.ipa.callgraph.propagation.IPointsToSolver#solve() - */ - @Override - public void solve(IProgressMonitor monitor) throws IllegalArgumentException, CancelException { - int i = 0; - do { - i++; - - if (DEBUG_PHASES) { - System.err.println("Iteration " + i); - } - getSystem().solve(monitor); - if (DEBUG_PHASES) { - System.err.println("Solved " + i); - } - - if (getBuilder().getOptions().getMaxNumberOfNodes() > -1) { - if (getBuilder().getCallGraph().getNumberOfNodes() >= getBuilder().getOptions().getMaxNumberOfNodes()) { - if (DEBUG) { - System.err.println("Bail out from call graph limit" + i); - } - throw CancelException.make("reached call graph size limit"); - } - } - - // Add constraints until there are no new discovered nodes - if (DEBUG_PHASES) { - System.err.println("adding constraints"); - } - getBuilder().addConstraintsFromNewNodes(monitor); - - // getBuilder().callGraph.summarizeByPackage(); - - if (DEBUG_PHASES) { - System.err.println("handling reflection"); - } - if (i <= getBuilder().getOptions().getReflectionOptions().getNumFlowToCastIterations()) { - getReflectionHandler().updateForReflection(monitor); - } - // Handling reflection may have discovered new nodes! - if (DEBUG_PHASES) { - System.err.println("adding constraints again"); - } - getBuilder().addConstraintsFromNewNodes(monitor); - // Note that we may have added stuff to the - // worklist; so, - } while (!getSystem().emptyWorkList()); - - } - -} +/******************************************************************************* + * 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.ipa.callgraph.propagation; + + +import com.ibm.wala.util.CancelException; +import com.ibm.wala.util.MonitorUtil.IProgressMonitor; + +/** + * standard fixed-point iterative solver for pointer analysis + */ +public class StandardSolver extends AbstractPointsToSolver { + + private static final boolean DEBUG_PHASES = DEBUG || false; + + public StandardSolver(PropagationSystem system, PropagationCallGraphBuilder builder) { + super(system, builder); + } + + /* + * @see com.ibm.wala.ipa.callgraph.propagation.IPointsToSolver#solve() + */ + @Override + public void solve(IProgressMonitor monitor) throws IllegalArgumentException, CancelException { + int i = 0; + do { + i++; + + if (DEBUG_PHASES) { + System.err.println("Iteration " + i); + } + getSystem().solve(monitor); + if (DEBUG_PHASES) { + System.err.println("Solved " + i); + } + + if (getBuilder().getOptions().getMaxNumberOfNodes() > -1) { + if (getBuilder().getCallGraph().getNumberOfNodes() >= getBuilder().getOptions().getMaxNumberOfNodes()) { + if (DEBUG) { + System.err.println("Bail out from call graph limit" + i); + } + throw CancelException.make("reached call graph size limit"); + } + } + + // Add constraints until there are no new discovered nodes + if (DEBUG_PHASES) { + System.err.println("adding constraints"); + } + getBuilder().addConstraintsFromNewNodes(monitor); + + // getBuilder().callGraph.summarizeByPackage(); + + if (DEBUG_PHASES) { + System.err.println("handling reflection"); + } + if (i <= getBuilder().getOptions().getReflectionOptions().getNumFlowToCastIterations()) { + getReflectionHandler().updateForReflection(monitor); + } + // Handling reflection may have discovered new nodes! + if (DEBUG_PHASES) { + System.err.println("adding constraints again"); + } + getBuilder().addConstraintsFromNewNodes(monitor); + // Note that we may have added stuff to the + // worklist; so, + } while (!getSystem().emptyWorkList()); + + } + +} diff --git a/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/StaticFieldKey.java b/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/StaticFieldKey.java index dad6d7451..73751c2dd 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/StaticFieldKey.java +++ b/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/StaticFieldKey.java @@ -1,49 +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.ipa.callgraph.propagation; - -import com.ibm.wala.classLoader.IField; - -/** - * An pointer key which represents a unique set for each static field - */ -public final class StaticFieldKey extends AbstractPointerKey { - private final IField field; - - public StaticFieldKey(IField field) { - if (field == null) { - throw new IllegalArgumentException("null field"); - } - this.field = field; - } - - @Override - public boolean equals(Object obj) { - // instanceof is OK because this class is final - if (obj instanceof StaticFieldKey) { - StaticFieldKey other = (StaticFieldKey) obj; - return field.equals(other.field); - } else { - return false; - } - } - @Override - public int hashCode() { - return 1889 * field.hashCode(); - } - @Override - public String toString() { - return "[" + field + "]"; - } - public IField getField() { - return field; - } -} +/******************************************************************************* + * 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.ipa.callgraph.propagation; + +import com.ibm.wala.classLoader.IField; + +/** + * An pointer key which represents a unique set for each static field + */ +public final class StaticFieldKey extends AbstractPointerKey { + private final IField field; + + public StaticFieldKey(IField field) { + if (field == null) { + throw new IllegalArgumentException("null field"); + } + this.field = field; + } + + @Override + public boolean equals(Object obj) { + // instanceof is OK because this class is final + if (obj instanceof StaticFieldKey) { + StaticFieldKey other = (StaticFieldKey) obj; + return field.equals(other.field); + } else { + return false; + } + } + @Override + public int hashCode() { + return 1889 * field.hashCode(); + } + @Override + public String toString() { + return "[" + field + "]"; + } + public IField getField() { + return field; + } +} diff --git a/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/StringConstantCharArray.java b/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/StringConstantCharArray.java index 34463a0b6..700da32de 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/StringConstantCharArray.java +++ b/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/StringConstantCharArray.java @@ -1,68 +1,68 @@ -/******************************************************************************* - * Copyright (c) 2007 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.ipa.callgraph.propagation; - -import com.ibm.wala.classLoader.IClass; -import com.ibm.wala.types.TypeReference; - -/** - * An {@link InstanceKey} which represents the constant char[] contents - * of a string constant object. - */ -public class StringConstantCharArray implements InstanceKey { - - private final ConstantKey constant; - - private StringConstantCharArray(ConstantKey constant) { - this.constant = constant; - } - - public static StringConstantCharArray make(ConstantKey constant) { - if (constant == null) { - throw new IllegalArgumentException("null constant"); - } - return new StringConstantCharArray(constant); - } - - @Override - public int hashCode() { - final int prime = 31; - int result = 1; - result = prime * result + ((constant == null) ? 0 : constant.hashCode()); - return result; - } - - @Override - public boolean equals(Object obj) { - if (this == obj) - return true; - if (obj == null) - return false; - if (getClass() != obj.getClass()) - return false; - final StringConstantCharArray other = (StringConstantCharArray) obj; - if (constant == null) { - if (other.constant != null) - return false; - } else if (!constant.equals(other.constant)) - return false; - return true; - } - - public IClass getConcreteType() { - return constant.getConcreteType().getClassHierarchy().lookupClass(TypeReference.CharArray); - } - - @Override - public String toString() { - return "StringConstantCharArray:" + constant; - } -} +/******************************************************************************* + * Copyright (c) 2007 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.ipa.callgraph.propagation; + +import com.ibm.wala.classLoader.IClass; +import com.ibm.wala.types.TypeReference; + +/** + * An {@link InstanceKey} which represents the constant char[] contents + * of a string constant object. + */ +public class StringConstantCharArray implements InstanceKey { + + private final ConstantKey constant; + + private StringConstantCharArray(ConstantKey constant) { + this.constant = constant; + } + + public static StringConstantCharArray make(ConstantKey constant) { + if (constant == null) { + throw new IllegalArgumentException("null constant"); + } + return new StringConstantCharArray(constant); + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((constant == null) ? 0 : constant.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + final StringConstantCharArray other = (StringConstantCharArray) obj; + if (constant == null) { + if (other.constant != null) + return false; + } else if (!constant.equals(other.constant)) + return false; + return true; + } + + public IClass getConcreteType() { + return constant.getConcreteType().getClassHierarchy().lookupClass(TypeReference.CharArray); + } + + @Override + public String toString() { + return "StringConstantCharArray:" + constant; + } +} diff --git a/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/TargetMethodContextSelector.java b/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/TargetMethodContextSelector.java index 78bf13f7d..2a0e7c472 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/TargetMethodContextSelector.java +++ b/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/TargetMethodContextSelector.java @@ -1,84 +1,84 @@ -/******************************************************************************* - * Copyright (c) 2002 - 2006 IBM Corporation. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * IBM Corporation - initial API and implementation - *******************************************************************************/ -package com.ibm.wala.ipa.callgraph.propagation; - -import com.ibm.wala.classLoader.CallSiteReference; -import com.ibm.wala.classLoader.IMethod; -import com.ibm.wala.ipa.callgraph.CGNode; -import com.ibm.wala.ipa.callgraph.Context; -import com.ibm.wala.ipa.callgraph.ContextItem; -import com.ibm.wala.ipa.callgraph.ContextKey; -import com.ibm.wala.ipa.callgraph.ContextSelector; -import com.ibm.wala.ipa.cha.IClassHierarchy; -import com.ibm.wala.types.Selector; -import com.ibm.wala.util.intset.IntSet; -import com.ibm.wala.util.intset.IntSetUtil; - -/** - * This context selector selects a context based on whether the receiver type - * dispatches to a given method. - */ -public class TargetMethodContextSelector implements ContextSelector { - - private final Selector selector; - - public TargetMethodContextSelector(Selector selector, IClassHierarchy cha) { - this.selector = selector; - } - - public Context getCalleeTarget(CGNode caller, CallSiteReference site, IMethod callee, InstanceKey[] R) { - if (R == null || R[0] == null) { - throw new IllegalArgumentException("R is null"); - } - - final IMethod M = R[0].getConcreteType().getMethod(selector); - - class MethodDispatchContext implements Context { - - private IMethod getTargetMethod() { - return M; - } - - public ContextItem get(ContextKey name) { - if (name.equals(ContextKey.PARAMETERS[0])) { - return new FilteredPointerKey.TargetMethodFilter(M); - } else { - return null; - } - } - - @Override - public String toString() { - return "DispatchContext: " + M; - } - - @Override - public int hashCode() { - return M.hashCode(); - } - - @Override - public boolean equals(Object o) { - return (o instanceof MethodDispatchContext) && ((MethodDispatchContext) o).getTargetMethod().equals(M); - } - } - ; - - return new MethodDispatchContext(); - } - - private static final IntSet thisParameter = IntSetUtil.make(new int[]{0}); - - public IntSet getRelevantParameters(CGNode caller, CallSiteReference site) { - return thisParameter; - } - -} +/******************************************************************************* + * 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.ipa.callgraph.propagation; + +import com.ibm.wala.classLoader.CallSiteReference; +import com.ibm.wala.classLoader.IMethod; +import com.ibm.wala.ipa.callgraph.CGNode; +import com.ibm.wala.ipa.callgraph.Context; +import com.ibm.wala.ipa.callgraph.ContextItem; +import com.ibm.wala.ipa.callgraph.ContextKey; +import com.ibm.wala.ipa.callgraph.ContextSelector; +import com.ibm.wala.ipa.cha.IClassHierarchy; +import com.ibm.wala.types.Selector; +import com.ibm.wala.util.intset.IntSet; +import com.ibm.wala.util.intset.IntSetUtil; + +/** + * This context selector selects a context based on whether the receiver type + * dispatches to a given method. + */ +public class TargetMethodContextSelector implements ContextSelector { + + private final Selector selector; + + public TargetMethodContextSelector(Selector selector, IClassHierarchy cha) { + this.selector = selector; + } + + public Context getCalleeTarget(CGNode caller, CallSiteReference site, IMethod callee, InstanceKey[] R) { + if (R == null || R[0] == null) { + throw new IllegalArgumentException("R is null"); + } + + final IMethod M = R[0].getConcreteType().getMethod(selector); + + class MethodDispatchContext implements Context { + + private IMethod getTargetMethod() { + return M; + } + + public ContextItem get(ContextKey name) { + if (name.equals(ContextKey.PARAMETERS[0])) { + return new FilteredPointerKey.TargetMethodFilter(M); + } else { + return null; + } + } + + @Override + public String toString() { + return "DispatchContext: " + M; + } + + @Override + public int hashCode() { + return M.hashCode(); + } + + @Override + public boolean equals(Object o) { + return (o instanceof MethodDispatchContext) && ((MethodDispatchContext) o).getTargetMethod().equals(M); + } + } + ; + + return new MethodDispatchContext(); + } + + private static final IntSet thisParameter = IntSetUtil.make(new int[]{0}); + + public IntSet getRelevantParameters(CGNode caller, CallSiteReference site) { + return thisParameter; + } + +} diff --git a/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/UnarySideEffect.java b/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/UnarySideEffect.java index 1e9834014..6200da567 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/UnarySideEffect.java +++ b/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/UnarySideEffect.java @@ -1,73 +1,73 @@ -/******************************************************************************* - * Copyright (c) 2002 - 2006 IBM Corporation. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * IBM Corporation - initial API and implementation - *******************************************************************************/ -package com.ibm.wala.ipa.callgraph.propagation; - -import com.ibm.wala.fixpoint.UnaryOperator; - -/** - * A SideEffect is a constraint which carries a points-to-set which is def'fed or used in created constraints. - * - * The side effect doesn't actually def or use the fixedSet itself ... rather, the side effect creates new constraints that - * def or use the fixed set. - * - * A "load" operator generates defs of the fixed set. A "store" operator generates uses of the fixed set. - */ -public abstract class UnarySideEffect extends UnaryOperator { - private PointsToSetVariable fixedSet; - - public UnarySideEffect(PointsToSetVariable fixedSet) { - this.fixedSet = fixedSet; - } - - @Override - public final byte evaluate(PointsToSetVariable lhs, PointsToSetVariable rhs) { - return evaluate(rhs); - } - - public abstract byte evaluate(PointsToSetVariable rhs); - - /** - * @return Returns the fixed points-to-set associated with this side effect. - */ - PointsToSetVariable getFixedSet() { - return fixedSet; - } - - @Override - public boolean equals(Object o) { - if (o == null) { - return false; - } - if (getClass().equals(o.getClass())) { - UnarySideEffect other = (UnarySideEffect) o; - return fixedSet.equals(other.fixedSet); - } else { - return false; - } - } - - @Override - public int hashCode() { - return 8059 * fixedSet.hashCode(); - } - - /** - * A "load" operator generates defs of the fixed set. A "store" operator generates uses of the fixed set. - */ - abstract protected boolean isLoadOperator(); - - /** - * Update the fixed points-to-set associated with this side effect. - */ - public void replaceFixedSet(PointsToSetVariable p) { - fixedSet = p; - } -} +/******************************************************************************* + * 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.ipa.callgraph.propagation; + +import com.ibm.wala.fixpoint.UnaryOperator; + +/** + * A SideEffect is a constraint which carries a points-to-set which is def'fed or used in created constraints. + * + * The side effect doesn't actually def or use the fixedSet itself ... rather, the side effect creates new constraints that + * def or use the fixed set. + * + * A "load" operator generates defs of the fixed set. A "store" operator generates uses of the fixed set. + */ +public abstract class UnarySideEffect extends UnaryOperator { + private PointsToSetVariable fixedSet; + + public UnarySideEffect(PointsToSetVariable fixedSet) { + this.fixedSet = fixedSet; + } + + @Override + public final byte evaluate(PointsToSetVariable lhs, PointsToSetVariable rhs) { + return evaluate(rhs); + } + + public abstract byte evaluate(PointsToSetVariable rhs); + + /** + * @return Returns the fixed points-to-set associated with this side effect. + */ + PointsToSetVariable getFixedSet() { + return fixedSet; + } + + @Override + public boolean equals(Object o) { + if (o == null) { + return false; + } + if (getClass().equals(o.getClass())) { + UnarySideEffect other = (UnarySideEffect) o; + return fixedSet.equals(other.fixedSet); + } else { + return false; + } + } + + @Override + public int hashCode() { + return 8059 * fixedSet.hashCode(); + } + + /** + * A "load" operator generates defs of the fixed set. A "store" operator generates uses of the fixed set. + */ + abstract protected boolean isLoadOperator(); + + /** + * Update the fixed points-to-set associated with this side effect. + */ + public void replaceFixedSet(PointsToSetVariable p) { + fixedSet = p; + } +} diff --git a/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/cfa/CallString.java b/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/cfa/CallString.java index 0b107f35d..5bf80e195 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/cfa/CallString.java +++ b/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/cfa/CallString.java @@ -1,87 +1,87 @@ -/******************************************************************************* - * Copyright (c) 2007 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.ipa.callgraph.propagation.cfa; - -import com.ibm.wala.classLoader.CallSiteReference; -import com.ibm.wala.classLoader.IMethod; -import com.ibm.wala.ipa.callgraph.ContextItem; - -public class CallString implements ContextItem { - private final CallSiteReference sites[]; - - private final IMethod methods[]; - - public CallString(CallSiteReference site, IMethod method) { - if (site == null) { - throw new IllegalArgumentException("null site"); - } - this.sites = new CallSiteReference[] { site }; - this.methods = new IMethod[] { method }; - } - - CallString(CallSiteReference site, IMethod method, int length, CallString base) { - int sitesLength = Math.min(length, base.sites.length + 1); - int methodsLength = Math.min(length, base.methods.length + 1); - sites = new CallSiteReference[sitesLength]; - sites[0] = site; - System.arraycopy(base.sites, 0, sites, 1, Math.min(length - 1, base.sites.length)); - methods = new IMethod[methodsLength]; - methods[0] = method; - System.arraycopy(base.methods, 0, methods, 1, Math.min(length - 1, base.methods.length)); - } - - @Override - public String toString() { - StringBuffer str = new StringBuffer("["); - for (int i = 0; i < sites.length; i++) { - str.append(" ").append(methods[i].getSignature()).append("@").append(sites[i].getProgramCounter()); - } - str.append(" ]"); - return str.toString(); - } - - @Override - public int hashCode() { - int code = 1; - for (int i = 0; i < sites.length; i++) { - code *= sites[i].hashCode() * methods[i].hashCode(); - } - - return code; - } - - @Override - public boolean equals(Object o) { - if (o instanceof CallString) { - CallString oc = (CallString) o; - if (oc.sites.length == sites.length) { - for (int i = 0; i < sites.length; i++) { - if (!(sites[i].equals(oc.sites[i]) && methods[i].equals(oc.methods[i]))) { - return false; - } - } - - return true; - } - } - - return false; - } - - public CallSiteReference[] getCallSiteRefs() { - return this.sites; - } - - public IMethod[] getMethods() { - return this.methods; - } - +/******************************************************************************* + * Copyright (c) 2007 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.ipa.callgraph.propagation.cfa; + +import com.ibm.wala.classLoader.CallSiteReference; +import com.ibm.wala.classLoader.IMethod; +import com.ibm.wala.ipa.callgraph.ContextItem; + +public class CallString implements ContextItem { + private final CallSiteReference sites[]; + + private final IMethod methods[]; + + public CallString(CallSiteReference site, IMethod method) { + if (site == null) { + throw new IllegalArgumentException("null site"); + } + this.sites = new CallSiteReference[] { site }; + this.methods = new IMethod[] { method }; + } + + CallString(CallSiteReference site, IMethod method, int length, CallString base) { + int sitesLength = Math.min(length, base.sites.length + 1); + int methodsLength = Math.min(length, base.methods.length + 1); + sites = new CallSiteReference[sitesLength]; + sites[0] = site; + System.arraycopy(base.sites, 0, sites, 1, Math.min(length - 1, base.sites.length)); + methods = new IMethod[methodsLength]; + methods[0] = method; + System.arraycopy(base.methods, 0, methods, 1, Math.min(length - 1, base.methods.length)); + } + + @Override + public String toString() { + StringBuffer str = new StringBuffer("["); + for (int i = 0; i < sites.length; i++) { + str.append(" ").append(methods[i].getSignature()).append("@").append(sites[i].getProgramCounter()); + } + str.append(" ]"); + return str.toString(); + } + + @Override + public int hashCode() { + int code = 1; + for (int i = 0; i < sites.length; i++) { + code *= sites[i].hashCode() * methods[i].hashCode(); + } + + return code; + } + + @Override + public boolean equals(Object o) { + if (o instanceof CallString) { + CallString oc = (CallString) o; + if (oc.sites.length == sites.length) { + for (int i = 0; i < sites.length; i++) { + if (!(sites[i].equals(oc.sites[i]) && methods[i].equals(oc.methods[i]))) { + return false; + } + } + + return true; + } + } + + return false; + } + + public CallSiteReference[] getCallSiteRefs() { + return this.sites; + } + + public IMethod[] getMethods() { + return this.methods; + } + } \ No newline at end of file diff --git a/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/cfa/CallStringContext.java b/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/cfa/CallStringContext.java index 4c8c0685a..1e41e38f8 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/cfa/CallStringContext.java +++ b/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/cfa/CallStringContext.java @@ -1,49 +1,49 @@ -/******************************************************************************* - * Copyright (c) 2007 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.ipa.callgraph.propagation.cfa; - -import com.ibm.wala.ipa.callgraph.Context; -import com.ibm.wala.ipa.callgraph.ContextItem; -import com.ibm.wala.ipa.callgraph.ContextKey; - -public class CallStringContext implements Context { - private final CallString cs; - - public CallStringContext(CallString cs) { - if (cs == null) { - throw new IllegalArgumentException("null cs"); - } - this.cs = cs; - } - - @Override - public boolean equals(Object o) { - return (o instanceof CallStringContext) && ((CallStringContext) o).cs.equals(cs); - } - - @Override - public int hashCode() { - return cs.hashCode(); - } - - @Override - public String toString() { - return "CallStringContext: " + cs.toString(); - } - - public ContextItem get(ContextKey name) { - if (CallStringContextSelector.CALL_STRING.equals(name)) { - return cs; - } else { - return null; - } - } +/******************************************************************************* + * Copyright (c) 2007 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.ipa.callgraph.propagation.cfa; + +import com.ibm.wala.ipa.callgraph.Context; +import com.ibm.wala.ipa.callgraph.ContextItem; +import com.ibm.wala.ipa.callgraph.ContextKey; + +public class CallStringContext implements Context { + private final CallString cs; + + public CallStringContext(CallString cs) { + if (cs == null) { + throw new IllegalArgumentException("null cs"); + } + this.cs = cs; + } + + @Override + public boolean equals(Object o) { + return (o instanceof CallStringContext) && ((CallStringContext) o).cs.equals(cs); + } + + @Override + public int hashCode() { + return cs.hashCode(); + } + + @Override + public String toString() { + return "CallStringContext: " + cs.toString(); + } + + public ContextItem get(ContextKey name) { + if (CallStringContextSelector.CALL_STRING.equals(name)) { + return cs; + } else { + return null; + } + } } \ No newline at end of file diff --git a/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/cfa/CallStringContextSelector.java b/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/cfa/CallStringContextSelector.java index 7cf05dfb8..7829a0ce0 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/cfa/CallStringContextSelector.java +++ b/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/cfa/CallStringContextSelector.java @@ -1,118 +1,118 @@ -/******************************************************************************* - * 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.ipa.callgraph.propagation.cfa; - -import com.ibm.wala.classLoader.CallSiteReference; -import com.ibm.wala.classLoader.IMethod; -import com.ibm.wala.ipa.callgraph.CGNode; -import com.ibm.wala.ipa.callgraph.Context; -import com.ibm.wala.ipa.callgraph.ContextItem; -import com.ibm.wala.ipa.callgraph.ContextKey; -import com.ibm.wala.ipa.callgraph.ContextSelector; -import com.ibm.wala.ipa.callgraph.impl.Everywhere; -import com.ibm.wala.ipa.callgraph.propagation.InstanceKey; -import com.ibm.wala.ipa.callgraph.propagation.ReceiverInstanceContext; -import com.ibm.wala.util.intset.EmptyIntSet; -import com.ibm.wala.util.intset.IntSet; - -public abstract class CallStringContextSelector implements ContextSelector { - - public static final ContextKey CALL_STRING = new ContextKey() { - @Override - public String toString() { - return "CALL_STRING_KEY"; - } - }; - - public static class CallStringContextPair implements Context { - private final CallString cs; - - private final Context base; - - private CallStringContextPair(CallString cs, Context base) { - this.cs = cs; - this.base = base; - } - - @Override - public boolean equals(Object o) { - return (o instanceof CallStringContextPair) && ((CallStringContextPair) o).cs.equals(cs) - && ((CallStringContextPair) o).base.equals(base); - } - - @Override - public String toString() { - return "CallStringContextPair: " + cs.toString() + ":" + base.toString(); - } - - @Override - public int hashCode() { - return cs.hashCode() * base.hashCode(); - } - - public ContextItem get(ContextKey name) { - if (CALL_STRING.equals(name)) { - return cs; - } else { - return base.get(name); - } - } - - public Context getBaseContext() { - return base; - } - - public CallString getCallString() { - return cs; - } - }; - - private final ContextSelector base; - - public CallStringContextSelector(ContextSelector base) { - this.base = base; - } - - protected abstract int getLength(CGNode caller, CallSiteReference site, IMethod target); - - private CallString getCallString(CGNode caller, CallSiteReference site, IMethod target) { - int length = getLength(caller, site, target); - if (length > 0) { - if (caller.getContext().get(CALL_STRING) != null) { - return new CallString(site, caller.getMethod(), length, (CallString) caller.getContext().get(CALL_STRING)); - } else { - return new CallString(site, caller.getMethod()); - } - } else { - return null; - } - } - - /* - * @see com.ibm.wala.ipa.callgraph.ContextSelector#getCalleeTarget(com.ibm.wala.ipa.callgraph.CGNode, com.ibm.wala.classLoader.CallSiteReference, com.ibm.wala.classLoader.IMethod, com.ibm.wala.ipa.callgraph.propagation.InstanceKey) - */ - public Context getCalleeTarget(CGNode caller, CallSiteReference site, IMethod callee, InstanceKey[] receiver) { - Context baseContext = base.getCalleeTarget(caller, site, callee, receiver); - CallString cs = getCallString(caller, site, callee); - if (cs == null) { - return baseContext; - } else if (baseContext == Everywhere.EVERYWHERE) { - return new CallStringContext(cs); - } else { - return new CallStringContextPair(cs, baseContext); - } - } - - public IntSet getRelevantParameters(CGNode caller, CallSiteReference site) { - return base.getRelevantParameters(caller, site); - } - -} +/******************************************************************************* + * 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.ipa.callgraph.propagation.cfa; + +import com.ibm.wala.classLoader.CallSiteReference; +import com.ibm.wala.classLoader.IMethod; +import com.ibm.wala.ipa.callgraph.CGNode; +import com.ibm.wala.ipa.callgraph.Context; +import com.ibm.wala.ipa.callgraph.ContextItem; +import com.ibm.wala.ipa.callgraph.ContextKey; +import com.ibm.wala.ipa.callgraph.ContextSelector; +import com.ibm.wala.ipa.callgraph.impl.Everywhere; +import com.ibm.wala.ipa.callgraph.propagation.InstanceKey; +import com.ibm.wala.ipa.callgraph.propagation.ReceiverInstanceContext; +import com.ibm.wala.util.intset.EmptyIntSet; +import com.ibm.wala.util.intset.IntSet; + +public abstract class CallStringContextSelector implements ContextSelector { + + public static final ContextKey CALL_STRING = new ContextKey() { + @Override + public String toString() { + return "CALL_STRING_KEY"; + } + }; + + public static class CallStringContextPair implements Context { + private final CallString cs; + + private final Context base; + + private CallStringContextPair(CallString cs, Context base) { + this.cs = cs; + this.base = base; + } + + @Override + public boolean equals(Object o) { + return (o instanceof CallStringContextPair) && ((CallStringContextPair) o).cs.equals(cs) + && ((CallStringContextPair) o).base.equals(base); + } + + @Override + public String toString() { + return "CallStringContextPair: " + cs.toString() + ":" + base.toString(); + } + + @Override + public int hashCode() { + return cs.hashCode() * base.hashCode(); + } + + public ContextItem get(ContextKey name) { + if (CALL_STRING.equals(name)) { + return cs; + } else { + return base.get(name); + } + } + + public Context getBaseContext() { + return base; + } + + public CallString getCallString() { + return cs; + } + }; + + private final ContextSelector base; + + public CallStringContextSelector(ContextSelector base) { + this.base = base; + } + + protected abstract int getLength(CGNode caller, CallSiteReference site, IMethod target); + + private CallString getCallString(CGNode caller, CallSiteReference site, IMethod target) { + int length = getLength(caller, site, target); + if (length > 0) { + if (caller.getContext().get(CALL_STRING) != null) { + return new CallString(site, caller.getMethod(), length, (CallString) caller.getContext().get(CALL_STRING)); + } else { + return new CallString(site, caller.getMethod()); + } + } else { + return null; + } + } + + /* + * @see com.ibm.wala.ipa.callgraph.ContextSelector#getCalleeTarget(com.ibm.wala.ipa.callgraph.CGNode, com.ibm.wala.classLoader.CallSiteReference, com.ibm.wala.classLoader.IMethod, com.ibm.wala.ipa.callgraph.propagation.InstanceKey) + */ + public Context getCalleeTarget(CGNode caller, CallSiteReference site, IMethod callee, InstanceKey[] receiver) { + Context baseContext = base.getCalleeTarget(caller, site, callee, receiver); + CallString cs = getCallString(caller, site, callee); + if (cs == null) { + return baseContext; + } else if (baseContext == Everywhere.EVERYWHERE) { + return new CallStringContext(cs); + } else { + return new CallStringContextPair(cs, baseContext); + } + } + + public IntSet getRelevantParameters(CGNode caller, CallSiteReference site) { + return base.getRelevantParameters(caller, site); + } + +} diff --git a/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/cfa/CallerContext.java b/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/cfa/CallerContext.java index b54053b35..c6e928d5b 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/cfa/CallerContext.java +++ b/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/cfa/CallerContext.java @@ -1,73 +1,73 @@ -/******************************************************************************* - * Copyright (c) 2002 - 2006 IBM Corporation. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * IBM Corporation - initial API and implementation - *******************************************************************************/ -package com.ibm.wala.ipa.callgraph.propagation.cfa; - -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; - -/** - * This is a context which is defined by the caller node. - */ -public class CallerContext implements Context { - - private final CGNode caller; - - /** - * @param caller the node which defines this context. - */ - public CallerContext(CGNode caller) { - if (caller == null) { - throw new IllegalArgumentException("null caller"); - } - this.caller = caller; - } - - public ContextItem get(ContextKey name) { - if (name == null) { - throw new IllegalArgumentException("name is null"); - } - if (name.equals(ContextKey.CALLER)) { - return caller; - } else { - return null; - } - } - - @Override - public boolean equals(Object obj) { - if (obj == null) { - return false; - } - if (getClass().equals(obj.getClass())) { - CallerContext other = (CallerContext)obj; - return caller.equals(other.caller); - } else { - return false; - } - } - - @Override - public int hashCode() { - return 7841 * caller.hashCode(); - } - - @Override - public String toString() { - return "Caller: " + caller; - } - - public CGNode getCaller() { - return caller; - } - -} +/******************************************************************************* + * 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.ipa.callgraph.propagation.cfa; + +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; + +/** + * This is a context which is defined by the caller node. + */ +public class CallerContext implements Context { + + private final CGNode caller; + + /** + * @param caller the node which defines this context. + */ + public CallerContext(CGNode caller) { + if (caller == null) { + throw new IllegalArgumentException("null caller"); + } + this.caller = caller; + } + + public ContextItem get(ContextKey name) { + if (name == null) { + throw new IllegalArgumentException("name is null"); + } + if (name.equals(ContextKey.CALLER)) { + return caller; + } else { + return null; + } + } + + @Override + public boolean equals(Object obj) { + if (obj == null) { + return false; + } + if (getClass().equals(obj.getClass())) { + CallerContext other = (CallerContext)obj; + return caller.equals(other.caller); + } else { + return false; + } + } + + @Override + public int hashCode() { + return 7841 * caller.hashCode(); + } + + @Override + public String toString() { + return "Caller: " + caller; + } + + public CGNode getCaller() { + return caller; + } + +} diff --git a/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/cfa/CallerContextPair.java b/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/cfa/CallerContextPair.java index 76400eeb2..cf55d55fe 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/cfa/CallerContextPair.java +++ b/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/cfa/CallerContextPair.java @@ -1,73 +1,73 @@ -/******************************************************************************* - * Copyright (c) 2002 - 2006 IBM Corporation. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * IBM Corporation - initial API and implementation - *******************************************************************************/ - -package com.ibm.wala.ipa.callgraph.propagation.cfa; - -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; - -/** - * This is a {@link Context} which is defined by a pair consisting of . - * - * The base context is typically some special case; e.g., a JavaTypeContext used for reflection. - */ -public class CallerContextPair extends CallerContext { - - private final Context baseContext; - - /** - * @param caller the node which defines this context. - */ - public CallerContextPair(CGNode caller, Context baseContext) { - super(caller); - this.baseContext = baseContext; - // avoid recursive contexts for now. - assert !(baseContext instanceof CallerContextPair); - } - - @Override - public ContextItem get(ContextKey name) { - if (name == null) { - throw new IllegalArgumentException("name is null"); - } - if (name.equals(ContextKey.CALLER)) { - return super.get(name); - } else { - return baseContext.get(name); - } - } - - @Override - public boolean equals(Object obj) { - if (obj == null) { - return false; - } - if (getClass().equals(obj.getClass())) { - CallerContextPair other = (CallerContextPair) obj; - return getCaller().equals(other.getCaller()) && baseContext.equals(other.baseContext); - } else { - return false; - } - } - - @Override - public int hashCode() { - return 8377 * getCaller().hashCode() + baseContext.hashCode(); - } - - @Override - public String toString() { - return "Caller: " + getCaller() + ",Base:" + baseContext; - } - -} +/******************************************************************************* + * 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.ipa.callgraph.propagation.cfa; + +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; + +/** + * This is a {@link Context} which is defined by a pair consisting of . + * + * The base context is typically some special case; e.g., a JavaTypeContext used for reflection. + */ +public class CallerContextPair extends CallerContext { + + private final Context baseContext; + + /** + * @param caller the node which defines this context. + */ + public CallerContextPair(CGNode caller, Context baseContext) { + super(caller); + this.baseContext = baseContext; + // avoid recursive contexts for now. + assert !(baseContext instanceof CallerContextPair); + } + + @Override + public ContextItem get(ContextKey name) { + if (name == null) { + throw new IllegalArgumentException("name is null"); + } + if (name.equals(ContextKey.CALLER)) { + return super.get(name); + } else { + return baseContext.get(name); + } + } + + @Override + public boolean equals(Object obj) { + if (obj == null) { + return false; + } + if (getClass().equals(obj.getClass())) { + CallerContextPair other = (CallerContextPair) obj; + return getCaller().equals(other.getCaller()) && baseContext.equals(other.baseContext); + } else { + return false; + } + } + + @Override + public int hashCode() { + return 8377 * getCaller().hashCode() + baseContext.hashCode(); + } + + @Override + public String toString() { + return "Caller: " + getCaller() + ",Base:" + baseContext; + } + +} diff --git a/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/cfa/CallerSiteContext.java b/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/cfa/CallerSiteContext.java index 2983a663d..bfd11694c 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/cfa/CallerSiteContext.java +++ b/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/cfa/CallerSiteContext.java @@ -1,62 +1,62 @@ -/******************************************************************************* - * 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.ipa.callgraph.propagation.cfa; - -import com.ibm.wala.classLoader.CallSiteReference; -import com.ibm.wala.ipa.callgraph.CGNode; -import com.ibm.wala.ipa.callgraph.ContextItem; -import com.ibm.wala.ipa.callgraph.ContextKey; - -/** - * A context which is a pair - */ -public class CallerSiteContext extends CallerContext { - - private final CallSiteReference callSite; - - public CallerSiteContext(CGNode caller, CallSiteReference callSite) { - super(caller); - this.callSite = callSite; - } - - @Override - public ContextItem get(ContextKey name) { - if (name.equals(ContextKey.CALLSITE)) { - return callSite; - } else { - return super.get(name); - } - } - - @Override - public boolean equals(Object obj) { - if (obj != null && getClass().equals(obj.getClass())) { - CallerSiteContext other = (CallerSiteContext) obj; - return getCaller().equals(other.getCaller()) && callSite.equals(other.callSite); - } else { - return false; - } - } - - @Override - public int hashCode() { - return callSite.hashCode() * 19 + super.hashCode(); - } - - @Override - public String toString() { - return super.toString() + "@" + callSite.getProgramCounter(); - } - - public CallSiteReference getCallSite() { - return callSite; - } -} +/******************************************************************************* + * 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.ipa.callgraph.propagation.cfa; + +import com.ibm.wala.classLoader.CallSiteReference; +import com.ibm.wala.ipa.callgraph.CGNode; +import com.ibm.wala.ipa.callgraph.ContextItem; +import com.ibm.wala.ipa.callgraph.ContextKey; + +/** + * A context which is a pair + */ +public class CallerSiteContext extends CallerContext { + + private final CallSiteReference callSite; + + public CallerSiteContext(CGNode caller, CallSiteReference callSite) { + super(caller); + this.callSite = callSite; + } + + @Override + public ContextItem get(ContextKey name) { + if (name.equals(ContextKey.CALLSITE)) { + return callSite; + } else { + return super.get(name); + } + } + + @Override + public boolean equals(Object obj) { + if (obj != null && getClass().equals(obj.getClass())) { + CallerSiteContext other = (CallerSiteContext) obj; + return getCaller().equals(other.getCaller()) && callSite.equals(other.callSite); + } else { + return false; + } + } + + @Override + public int hashCode() { + return callSite.hashCode() * 19 + super.hashCode(); + } + + @Override + public String toString() { + return super.toString() + "@" + callSite.getProgramCounter(); + } + + public CallSiteReference getCallSite() { + return callSite; + } +} diff --git a/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/cfa/CallerSiteContextPair.java b/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/cfa/CallerSiteContextPair.java index cc20cb273..3db0f3075 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/cfa/CallerSiteContextPair.java +++ b/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/cfa/CallerSiteContextPair.java @@ -1,77 +1,77 @@ -/******************************************************************************* - * Copyright (c) 2002 - 2006 IBM Corporation. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * IBM Corporation - initial API and implementation - *******************************************************************************/ -package com.ibm.wala.ipa.callgraph.propagation.cfa; - -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; - -/** - * This is a context which is defined by a pair consisting of . - * - * The base context is typically some special case; e.g., a JavaTypeContext used for reflection. - */ -public class CallerSiteContextPair extends CallerSiteContext { - - private final Context baseContext; - - /** - * @param caller the node which defines this context. - */ - public CallerSiteContextPair(CGNode caller, CallSiteReference callSite, Context baseContext) { - super(caller, callSite); - if (caller == null) { - throw new IllegalArgumentException("null caller"); - } - this.baseContext = baseContext; - // avoid recursive contexts for now. - assert !(baseContext instanceof CallerContextPair); - } - - @Override - public ContextItem get(ContextKey name) { - if (name == null) { - throw new IllegalArgumentException("name is null"); - } - if (name.equals(ContextKey.CALLER) || name.equals(ContextKey.CALLSITE)) { - return super.get(name); - } else { - return baseContext.get(name); - } - } - - @Override - public boolean equals(Object obj) { - if (obj == null) { - return false; - } - if (getClass().equals(obj.getClass())) { - CallerSiteContextPair other = (CallerSiteContextPair) obj; - return getCaller().equals(other.getCaller()) && getCallSite().equals(other.getCallSite()) - && baseContext.equals(other.baseContext); - } else { - return false; - } - } - - @Override - public int hashCode() { - return super.hashCode() + baseContext.hashCode(); - } - - @Override - public String toString() { - return super.toString() + ",Base:" + baseContext; - } - -} +/******************************************************************************* + * 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.ipa.callgraph.propagation.cfa; + +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; + +/** + * This is a context which is defined by a pair consisting of . + * + * The base context is typically some special case; e.g., a JavaTypeContext used for reflection. + */ +public class CallerSiteContextPair extends CallerSiteContext { + + private final Context baseContext; + + /** + * @param caller the node which defines this context. + */ + public CallerSiteContextPair(CGNode caller, CallSiteReference callSite, Context baseContext) { + super(caller, callSite); + if (caller == null) { + throw new IllegalArgumentException("null caller"); + } + this.baseContext = baseContext; + // avoid recursive contexts for now. + assert !(baseContext instanceof CallerContextPair); + } + + @Override + public ContextItem get(ContextKey name) { + if (name == null) { + throw new IllegalArgumentException("name is null"); + } + if (name.equals(ContextKey.CALLER) || name.equals(ContextKey.CALLSITE)) { + return super.get(name); + } else { + return baseContext.get(name); + } + } + + @Override + public boolean equals(Object obj) { + if (obj == null) { + return false; + } + if (getClass().equals(obj.getClass())) { + CallerSiteContextPair other = (CallerSiteContextPair) obj; + return getCaller().equals(other.getCaller()) && getCallSite().equals(other.getCallSite()) + && baseContext.equals(other.baseContext); + } else { + return false; + } + } + + @Override + public int hashCode() { + return super.hashCode() + baseContext.hashCode(); + } + + @Override + public String toString() { + return super.toString() + ",Base:" + baseContext; + } + +} diff --git a/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/cfa/ContainerContextSelector.java b/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/cfa/ContainerContextSelector.java index bda938a09..f84afe2c5 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/cfa/ContainerContextSelector.java +++ b/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/cfa/ContainerContextSelector.java @@ -1,344 +1,344 @@ -/******************************************************************************* - * 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.ipa.callgraph.propagation.cfa; - -import com.ibm.wala.classLoader.CallSiteReference; -import com.ibm.wala.classLoader.IClass; -import com.ibm.wala.classLoader.IMethod; -import com.ibm.wala.ipa.callgraph.CGNode; -import com.ibm.wala.ipa.callgraph.Context; -import com.ibm.wala.ipa.callgraph.ContextSelector; -import com.ibm.wala.ipa.callgraph.propagation.AllocationSiteInNode; -import com.ibm.wala.ipa.callgraph.propagation.ContainerUtil; -import com.ibm.wala.ipa.callgraph.propagation.InstanceKey; -import com.ibm.wala.ipa.callgraph.propagation.ReceiverInstanceContext; -import com.ibm.wala.ipa.cha.IClassHierarchy; -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.debug.Assertions; -import com.ibm.wala.util.intset.EmptyIntSet; -import com.ibm.wala.util.intset.IntSet; -import com.ibm.wala.util.intset.IntSetUtil; -import com.ibm.wala.util.strings.Atom; - -/** - * This context selector returns a context customized for the {@link InstanceKey} of the receiver if - *
          - *
        • receiver is a container, or
        • - * was allocated in a node whose context was a {@link ReceiverInstanceContext}, and the type is interesting according to a delegate - * {@link ZeroXInstanceKeys} - *
        - * - * Additionally, we add one level of call string context to a few well-known static factory methods from the standard libraries. - */ -public class ContainerContextSelector implements ContextSelector { - - private final static boolean DEBUG = false; - - private final static TypeName SyntheticSystemName = TypeName.string2TypeName("Lcom/ibm/wala/model/java/lang/System"); - - public final static TypeReference SyntheticSystem = TypeReference.findOrCreate(ClassLoaderReference.Primordial, - SyntheticSystemName); - - public final static TypeReference JavaUtilHashtable = TypeReference.findOrCreate(ClassLoaderReference.Primordial, - "Ljava/util/Hashtable"); - - public final static Atom arraycopyAtom = Atom.findOrCreateUnicodeAtom("arraycopy"); - - private final static Descriptor arraycopyDesc = Descriptor.findOrCreateUTF8("(Ljava/lang/Object;Ljava/lang/Object;)V"); - - public final static MethodReference synthArraycopy = MethodReference.findOrCreate(SyntheticSystem, arraycopyAtom, arraycopyDesc); - - private final static TypeReference Arrays = TypeReference.findOrCreate(ClassLoaderReference.Primordial, "Ljava/util/Arrays"); - - private final static Atom asList = Atom.findOrCreateUnicodeAtom("asList"); - - private final static Atom copyOf = Atom.findOrCreateUnicodeAtom("copyOf"); - - private final static Atom copyOfRange = Atom.findOrCreateUnicodeAtom("copyOfRange"); - - private final static Atom toString = Atom.findOrCreateUnicodeAtom("toString"); - - private final static MethodReference StringValueOf = MethodReference.findOrCreate(TypeReference.JavaLangString, "valueOf", - "(Ljava/lang/Object;)Ljava/lang/String;"); - - private final static MethodReference HashtableNewEntry = MethodReference.findOrCreate(JavaUtilHashtable, "newEntry", - "(Ljava/lang/Object;Ljava/lang/Object;I)Ljava/util/Hashtable$Entry;"); - - /** - * The governing class hierarchy. - */ - private final IClassHierarchy cha; - - /** - * An object that determines object naming policy - */ - private final ZeroXInstanceKeys delegate; - - /** - * @param cha governing class hierarchy - * @param delegate object which determines which classes are "interesting" - */ - public ContainerContextSelector(IClassHierarchy cha, ZeroXInstanceKeys delegate) { - this.cha = cha; - this.delegate = delegate; - if (delegate == null) { - throw new IllegalArgumentException("null delegate"); - } - } - - /* - * @see com.ibm.wala.ipa.callgraph.ContextSelector#getCalleeTarget(com.ibm.wala.ipa.callgraph.CGNode, - * com.ibm.wala.classLoader.CallSiteReference, com.ibm.wala.classLoader.IMethod, - * com.ibm.wala.ipa.callgraph.propagation.InstanceKey) - */ - public Context getCalleeTarget(CGNode caller, CallSiteReference site, IMethod callee, InstanceKey[] keys) { - if (DEBUG) { - System.err.println("ContainerContextSelector: getCalleeTarget " + callee); - } - InstanceKey receiver = null; - if (keys != null && keys.length > 0 && keys[0] != null) { - receiver = keys[0]; - } - if (receiver != null && mayUnderstand(caller, site, callee, receiver)) { - if (DEBUG) { - System.err.println("May Understand: " + callee + " recv " + receiver); - } - if (isWellKnownStaticFactory(callee.getReference())) { - return new CallerSiteContext(caller, site); - } else { - if (receiver == null) { - Assertions.UNREACHABLE("null receiver for " + site); - } - return new ReceiverInstanceContext(receiver); - } - } else { - return null; - } - } - - /** - * Does m represent a static factory method we know about from the standard libraries, that we usually wish to model with one - * level of call-string context? - */ - public static boolean isWellKnownStaticFactory(MethodReference m) { - if (isArrayCopyingMethod(m)) { - return true; - } - if (isArrayToStringMethod(m)) { - return true; - } - if (m.equals(StringValueOf)) { - return true; - } - if (m.equals(HashtableNewEntry)) { - return true; - } - return false; - } - - /** - * Does m represent a library method that copies arrays? - */ - public static boolean isArrayCopyingMethod(MethodReference m) { - if (m == null) { - throw new IllegalArgumentException("null m"); - } - if (m.getDeclaringClass().equals(TypeReference.JavaLangSystem)) { - if (m.getName().toString().equals("arraycopy")) { - return true; - } - } - if (m.equals(synthArraycopy)) { - return true; - } - if (isArrayCopyMethod(m)) { - return true; - } - return false; - } - - /** - * return true iff m represents one of the well-known methods in java.lang.reflect.Arrays that do some sort of arraycopy - */ - private static boolean isArrayCopyMethod(MethodReference m) { - if (m.getDeclaringClass().equals(Arrays)) { - if (m.getName().equals(asList) || m.getName().equals(copyOf) || m.getName().equals(copyOfRange)) { - return true; - } - } - return false; - } - - /** - * return true iff m represents one of the well-known methods in java.lang.reflect.Arrays that do toString() on an array - */ - private static boolean isArrayToStringMethod(MethodReference m) { - if (m.getDeclaringClass().equals(Arrays)) { - if (m.getName().equals(toString)) { - return true; - } - } - return false; - } - - /** - * This method walks recursively up the definition of a context C, to see if the chain of contexts that give rise to C a) includes - * the method M. or b) includes the method in which the receiver was allocated - * - * @return the matching context if found, null otherwise - */ - public static Context findRecursiveMatchingContext(IMethod M, Context C, InstanceKey receiver) { - if (DEBUG) { - System.err.println("findRecursiveMatchingContext for " + M + " in context " + C + " receiver " + receiver); - } - Context result = findRecursiveMatchingContext(M, C); - if (result != null) { - return result; - } else { - if (receiver instanceof AllocationSiteInNode) { - AllocationSiteInNode a = (AllocationSiteInNode) receiver; - IMethod m = a.getNode().getMethod(); - return findRecursiveMatchingContext(m, C); - } else { - return null; - } - } - } - - /** - * This method walks recursively up the definition of a context C, to see if the chain of contexts that give rise to C includes - * the method M. - * - * If C is a ReceiverInstanceContext, Let N be the node that allocated C.instance. If N.method == M, return N. Else return - * findRecursiveMatchingContext(M, N.context) Else return null - */ - public static CGNode findNodeRecursiveMatchingContext(IMethod m, Context c) { - if (DEBUG) { - System.err.println("findNodeRecursiveMatchingContext " + m + " in context " + c); - } - if (c instanceof ReceiverInstanceContext) { - ReceiverInstanceContext ric = (ReceiverInstanceContext) c; - if (!(ric.getReceiver() instanceof AllocationSiteInNode)) { - return null; - } - AllocationSiteInNode i = (AllocationSiteInNode) ric.getReceiver(); - CGNode n = i.getNode(); - if (n.getMethod().equals(m)) { - return n; - } else { - return findNodeRecursiveMatchingContext(m, n.getContext()); - } - } else if (c instanceof CallerContext) { - CallerContext cc = (CallerContext) c; - CGNode n = cc.getCaller(); - if (n.getMethod().equals(m)) { - return n; - } else { - return findNodeRecursiveMatchingContext(m, n.getContext()); - } - } else { - return null; - } - } - - /** - * This method walks recursively up the definition of a context C, to see if the chain of contexts that give rise to C includes - * the method M. - * - * If C is a ReceiverInstanceContext, Let N be the node that allocated C.instance. If N.method == M, return N.context. Else return - * findRecursiveMatchingContext(M, N.context) Else return null - */ - public static Context findRecursiveMatchingContext(IMethod M, Context C) { - CGNode n = findNodeRecursiveMatchingContext(M, C); - return (n == null) ? null : n.getContext(); - } - - public boolean mayUnderstand(CGNode caller, CallSiteReference site, IMethod targetMethod, InstanceKey receiver) { - if (targetMethod == null) { - throw new IllegalArgumentException("targetMethod is null"); - } - if (isWellKnownStaticFactory(targetMethod.getReference())) { - return true; - } else { - if (site.isStatic()) { - return false; - } - if (targetMethod.getDeclaringClass().getReference().equals(TypeReference.JavaLangObject)) { - // ramp down context: assuming methods on java.lang.Object don't cause pollution - // important for containers that invoke reflection - return false; - } - if (isContainer(targetMethod.getDeclaringClass())) { - return true; - } - - if (receiver == null) { - // any possible receiver. However, we will only handle this call - // if the concrete receiver type is interesting. - IClass klass = targetMethod.getDeclaringClass(); - int n = cha.getNumberOfImmediateSubclasses(klass); - if (n > 0) { - // the receiver is not "effectively final". - // give up and assume we might see an interesting subclass. - return true; - } - // only one possible receiver class - if (delegate.isInteresting(klass)) { - // we may create a receiver instance context for this call - return true; - } else { - // we will never create a receiver instance context for this call - return false; - } - } - if (!delegate.isInteresting(receiver.getConcreteType())) { - return false; - } - if (receiver instanceof AllocationSiteInNode) { - AllocationSiteInNode I = (AllocationSiteInNode) receiver; - CGNode N = I.getNode(); - if (N.getContext() instanceof ReceiverInstanceContext) { - return true; - } - } - return false; - } - } - - /** - * @return true iff C is a container class - */ - protected boolean isContainer(IClass C) { - if (DEBUG) { - System.err.println("isContainer? " + C + " " + ContainerUtil.isContainer(C)); - } - return ContainerUtil.isContainer(C); - } - - protected IClassHierarchy getClassHierarchy() { - return cha; - } - - private static final IntSet thisParameter = IntSetUtil.make(new int[]{0}); - - public IntSet getRelevantParameters(CGNode caller, CallSiteReference site) { - if (site.isDispatch() || site.getDeclaredTarget().getNumberOfParameters() > 0) { - return thisParameter; - } else { - return EmptyIntSet.instance; - } - } - -} +/******************************************************************************* + * 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.ipa.callgraph.propagation.cfa; + +import com.ibm.wala.classLoader.CallSiteReference; +import com.ibm.wala.classLoader.IClass; +import com.ibm.wala.classLoader.IMethod; +import com.ibm.wala.ipa.callgraph.CGNode; +import com.ibm.wala.ipa.callgraph.Context; +import com.ibm.wala.ipa.callgraph.ContextSelector; +import com.ibm.wala.ipa.callgraph.propagation.AllocationSiteInNode; +import com.ibm.wala.ipa.callgraph.propagation.ContainerUtil; +import com.ibm.wala.ipa.callgraph.propagation.InstanceKey; +import com.ibm.wala.ipa.callgraph.propagation.ReceiverInstanceContext; +import com.ibm.wala.ipa.cha.IClassHierarchy; +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.debug.Assertions; +import com.ibm.wala.util.intset.EmptyIntSet; +import com.ibm.wala.util.intset.IntSet; +import com.ibm.wala.util.intset.IntSetUtil; +import com.ibm.wala.util.strings.Atom; + +/** + * This context selector returns a context customized for the {@link InstanceKey} of the receiver if + *
          + *
        • receiver is a container, or
        • + * was allocated in a node whose context was a {@link ReceiverInstanceContext}, and the type is interesting according to a delegate + * {@link ZeroXInstanceKeys} + *
        + * + * Additionally, we add one level of call string context to a few well-known static factory methods from the standard libraries. + */ +public class ContainerContextSelector implements ContextSelector { + + private final static boolean DEBUG = false; + + private final static TypeName SyntheticSystemName = TypeName.string2TypeName("Lcom/ibm/wala/model/java/lang/System"); + + public final static TypeReference SyntheticSystem = TypeReference.findOrCreate(ClassLoaderReference.Primordial, + SyntheticSystemName); + + public final static TypeReference JavaUtilHashtable = TypeReference.findOrCreate(ClassLoaderReference.Primordial, + "Ljava/util/Hashtable"); + + public final static Atom arraycopyAtom = Atom.findOrCreateUnicodeAtom("arraycopy"); + + private final static Descriptor arraycopyDesc = Descriptor.findOrCreateUTF8("(Ljava/lang/Object;Ljava/lang/Object;)V"); + + public final static MethodReference synthArraycopy = MethodReference.findOrCreate(SyntheticSystem, arraycopyAtom, arraycopyDesc); + + private final static TypeReference Arrays = TypeReference.findOrCreate(ClassLoaderReference.Primordial, "Ljava/util/Arrays"); + + private final static Atom asList = Atom.findOrCreateUnicodeAtom("asList"); + + private final static Atom copyOf = Atom.findOrCreateUnicodeAtom("copyOf"); + + private final static Atom copyOfRange = Atom.findOrCreateUnicodeAtom("copyOfRange"); + + private final static Atom toString = Atom.findOrCreateUnicodeAtom("toString"); + + private final static MethodReference StringValueOf = MethodReference.findOrCreate(TypeReference.JavaLangString, "valueOf", + "(Ljava/lang/Object;)Ljava/lang/String;"); + + private final static MethodReference HashtableNewEntry = MethodReference.findOrCreate(JavaUtilHashtable, "newEntry", + "(Ljava/lang/Object;Ljava/lang/Object;I)Ljava/util/Hashtable$Entry;"); + + /** + * The governing class hierarchy. + */ + private final IClassHierarchy cha; + + /** + * An object that determines object naming policy + */ + private final ZeroXInstanceKeys delegate; + + /** + * @param cha governing class hierarchy + * @param delegate object which determines which classes are "interesting" + */ + public ContainerContextSelector(IClassHierarchy cha, ZeroXInstanceKeys delegate) { + this.cha = cha; + this.delegate = delegate; + if (delegate == null) { + throw new IllegalArgumentException("null delegate"); + } + } + + /* + * @see com.ibm.wala.ipa.callgraph.ContextSelector#getCalleeTarget(com.ibm.wala.ipa.callgraph.CGNode, + * com.ibm.wala.classLoader.CallSiteReference, com.ibm.wala.classLoader.IMethod, + * com.ibm.wala.ipa.callgraph.propagation.InstanceKey) + */ + public Context getCalleeTarget(CGNode caller, CallSiteReference site, IMethod callee, InstanceKey[] keys) { + if (DEBUG) { + System.err.println("ContainerContextSelector: getCalleeTarget " + callee); + } + InstanceKey receiver = null; + if (keys != null && keys.length > 0 && keys[0] != null) { + receiver = keys[0]; + } + if (receiver != null && mayUnderstand(caller, site, callee, receiver)) { + if (DEBUG) { + System.err.println("May Understand: " + callee + " recv " + receiver); + } + if (isWellKnownStaticFactory(callee.getReference())) { + return new CallerSiteContext(caller, site); + } else { + if (receiver == null) { + Assertions.UNREACHABLE("null receiver for " + site); + } + return new ReceiverInstanceContext(receiver); + } + } else { + return null; + } + } + + /** + * Does m represent a static factory method we know about from the standard libraries, that we usually wish to model with one + * level of call-string context? + */ + public static boolean isWellKnownStaticFactory(MethodReference m) { + if (isArrayCopyingMethod(m)) { + return true; + } + if (isArrayToStringMethod(m)) { + return true; + } + if (m.equals(StringValueOf)) { + return true; + } + if (m.equals(HashtableNewEntry)) { + return true; + } + return false; + } + + /** + * Does m represent a library method that copies arrays? + */ + public static boolean isArrayCopyingMethod(MethodReference m) { + if (m == null) { + throw new IllegalArgumentException("null m"); + } + if (m.getDeclaringClass().equals(TypeReference.JavaLangSystem)) { + if (m.getName().toString().equals("arraycopy")) { + return true; + } + } + if (m.equals(synthArraycopy)) { + return true; + } + if (isArrayCopyMethod(m)) { + return true; + } + return false; + } + + /** + * return true iff m represents one of the well-known methods in java.lang.reflect.Arrays that do some sort of arraycopy + */ + private static boolean isArrayCopyMethod(MethodReference m) { + if (m.getDeclaringClass().equals(Arrays)) { + if (m.getName().equals(asList) || m.getName().equals(copyOf) || m.getName().equals(copyOfRange)) { + return true; + } + } + return false; + } + + /** + * return true iff m represents one of the well-known methods in java.lang.reflect.Arrays that do toString() on an array + */ + private static boolean isArrayToStringMethod(MethodReference m) { + if (m.getDeclaringClass().equals(Arrays)) { + if (m.getName().equals(toString)) { + return true; + } + } + return false; + } + + /** + * This method walks recursively up the definition of a context C, to see if the chain of contexts that give rise to C a) includes + * the method M. or b) includes the method in which the receiver was allocated + * + * @return the matching context if found, null otherwise + */ + public static Context findRecursiveMatchingContext(IMethod M, Context C, InstanceKey receiver) { + if (DEBUG) { + System.err.println("findRecursiveMatchingContext for " + M + " in context " + C + " receiver " + receiver); + } + Context result = findRecursiveMatchingContext(M, C); + if (result != null) { + return result; + } else { + if (receiver instanceof AllocationSiteInNode) { + AllocationSiteInNode a = (AllocationSiteInNode) receiver; + IMethod m = a.getNode().getMethod(); + return findRecursiveMatchingContext(m, C); + } else { + return null; + } + } + } + + /** + * This method walks recursively up the definition of a context C, to see if the chain of contexts that give rise to C includes + * the method M. + * + * If C is a ReceiverInstanceContext, Let N be the node that allocated C.instance. If N.method == M, return N. Else return + * findRecursiveMatchingContext(M, N.context) Else return null + */ + public static CGNode findNodeRecursiveMatchingContext(IMethod m, Context c) { + if (DEBUG) { + System.err.println("findNodeRecursiveMatchingContext " + m + " in context " + c); + } + if (c instanceof ReceiverInstanceContext) { + ReceiverInstanceContext ric = (ReceiverInstanceContext) c; + if (!(ric.getReceiver() instanceof AllocationSiteInNode)) { + return null; + } + AllocationSiteInNode i = (AllocationSiteInNode) ric.getReceiver(); + CGNode n = i.getNode(); + if (n.getMethod().equals(m)) { + return n; + } else { + return findNodeRecursiveMatchingContext(m, n.getContext()); + } + } else if (c instanceof CallerContext) { + CallerContext cc = (CallerContext) c; + CGNode n = cc.getCaller(); + if (n.getMethod().equals(m)) { + return n; + } else { + return findNodeRecursiveMatchingContext(m, n.getContext()); + } + } else { + return null; + } + } + + /** + * This method walks recursively up the definition of a context C, to see if the chain of contexts that give rise to C includes + * the method M. + * + * If C is a ReceiverInstanceContext, Let N be the node that allocated C.instance. If N.method == M, return N.context. Else return + * findRecursiveMatchingContext(M, N.context) Else return null + */ + public static Context findRecursiveMatchingContext(IMethod M, Context C) { + CGNode n = findNodeRecursiveMatchingContext(M, C); + return (n == null) ? null : n.getContext(); + } + + public boolean mayUnderstand(CGNode caller, CallSiteReference site, IMethod targetMethod, InstanceKey receiver) { + if (targetMethod == null) { + throw new IllegalArgumentException("targetMethod is null"); + } + if (isWellKnownStaticFactory(targetMethod.getReference())) { + return true; + } else { + if (site.isStatic()) { + return false; + } + if (targetMethod.getDeclaringClass().getReference().equals(TypeReference.JavaLangObject)) { + // ramp down context: assuming methods on java.lang.Object don't cause pollution + // important for containers that invoke reflection + return false; + } + if (isContainer(targetMethod.getDeclaringClass())) { + return true; + } + + if (receiver == null) { + // any possible receiver. However, we will only handle this call + // if the concrete receiver type is interesting. + IClass klass = targetMethod.getDeclaringClass(); + int n = cha.getNumberOfImmediateSubclasses(klass); + if (n > 0) { + // the receiver is not "effectively final". + // give up and assume we might see an interesting subclass. + return true; + } + // only one possible receiver class + if (delegate.isInteresting(klass)) { + // we may create a receiver instance context for this call + return true; + } else { + // we will never create a receiver instance context for this call + return false; + } + } + if (!delegate.isInteresting(receiver.getConcreteType())) { + return false; + } + if (receiver instanceof AllocationSiteInNode) { + AllocationSiteInNode I = (AllocationSiteInNode) receiver; + CGNode N = I.getNode(); + if (N.getContext() instanceof ReceiverInstanceContext) { + return true; + } + } + return false; + } + } + + /** + * @return true iff C is a container class + */ + protected boolean isContainer(IClass C) { + if (DEBUG) { + System.err.println("isContainer? " + C + " " + ContainerUtil.isContainer(C)); + } + return ContainerUtil.isContainer(C); + } + + protected IClassHierarchy getClassHierarchy() { + return cha; + } + + private static final IntSet thisParameter = IntSetUtil.make(new int[]{0}); + + public IntSet getRelevantParameters(CGNode caller, CallSiteReference site) { + if (site.isDispatch() || site.getDeclaredTarget().getNumberOfParameters() > 0) { + return thisParameter; + } else { + return EmptyIntSet.instance; + } + } + +} diff --git a/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/cfa/ContextInsensitiveSSAInterpreter.java b/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/cfa/ContextInsensitiveSSAInterpreter.java index 4112c728e..6a12e650f 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/cfa/ContextInsensitiveSSAInterpreter.java +++ b/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/cfa/ContextInsensitiveSSAInterpreter.java @@ -1,75 +1,75 @@ -/******************************************************************************* - * 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.ipa.callgraph.propagation.cfa; - -import com.ibm.wala.cfg.ControlFlowGraph; -import com.ibm.wala.classLoader.IClass; -import com.ibm.wala.ipa.callgraph.AnalysisCache; -import com.ibm.wala.ipa.callgraph.AnalysisOptions; -import com.ibm.wala.ipa.callgraph.CGNode; -import com.ibm.wala.ipa.callgraph.impl.Everywhere; -import com.ibm.wala.ipa.callgraph.propagation.SSAContextInterpreter; -import com.ibm.wala.ipa.callgraph.propagation.rta.ContextInsensitiveRTAInterpreter; -import com.ibm.wala.ssa.DefUse; -import com.ibm.wala.ssa.IR; -import com.ibm.wala.ssa.ISSABasicBlock; -import com.ibm.wala.ssa.SSAInstruction; - -/** - * Default implementation of SSAContextInterpreter for context-insensitive - * analysis - */ -public class ContextInsensitiveSSAInterpreter extends ContextInsensitiveRTAInterpreter implements SSAContextInterpreter { - - protected final AnalysisOptions options; - - public ContextInsensitiveSSAInterpreter(AnalysisOptions options, AnalysisCache cache) { - super(cache); - this.options = options; - } - - public IR getIR(CGNode node) { - if (node == null) { - throw new IllegalArgumentException("node is null"); - } - // Note: since this is context-insensitive, we cache an IR based on the - // EVERYWHERE context - return getAnalysisCache().getSSACache().findOrCreateIR(node.getMethod(), Everywhere.EVERYWHERE, options.getSSAOptions()); - } - - public int getNumberOfStatements(CGNode node) { - IR ir = getIR(node); - return (ir == null) ? -1 : ir.getInstructions().length; - } - - @Override - public boolean recordFactoryType(CGNode node, IClass klass) { - return false; - } - - public ControlFlowGraph getCFG(CGNode N) { - IR ir = getIR(N); - if (ir == null) { - return null; - } else { - return ir.getControlFlowGraph(); - } - } - - public DefUse getDU(CGNode node) { - if (node == null) { - throw new IllegalArgumentException("node is null"); - } - // Note: since this is context-insensitive, we cache an IR based on the - // EVERYWHERE context - return getAnalysisCache().getSSACache().findOrCreateDU(node.getMethod(), Everywhere.EVERYWHERE, options.getSSAOptions()); - } -} +/******************************************************************************* + * 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.ipa.callgraph.propagation.cfa; + +import com.ibm.wala.cfg.ControlFlowGraph; +import com.ibm.wala.classLoader.IClass; +import com.ibm.wala.ipa.callgraph.AnalysisCache; +import com.ibm.wala.ipa.callgraph.AnalysisOptions; +import com.ibm.wala.ipa.callgraph.CGNode; +import com.ibm.wala.ipa.callgraph.impl.Everywhere; +import com.ibm.wala.ipa.callgraph.propagation.SSAContextInterpreter; +import com.ibm.wala.ipa.callgraph.propagation.rta.ContextInsensitiveRTAInterpreter; +import com.ibm.wala.ssa.DefUse; +import com.ibm.wala.ssa.IR; +import com.ibm.wala.ssa.ISSABasicBlock; +import com.ibm.wala.ssa.SSAInstruction; + +/** + * Default implementation of SSAContextInterpreter for context-insensitive + * analysis + */ +public class ContextInsensitiveSSAInterpreter extends ContextInsensitiveRTAInterpreter implements SSAContextInterpreter { + + protected final AnalysisOptions options; + + public ContextInsensitiveSSAInterpreter(AnalysisOptions options, AnalysisCache cache) { + super(cache); + this.options = options; + } + + public IR getIR(CGNode node) { + if (node == null) { + throw new IllegalArgumentException("node is null"); + } + // Note: since this is context-insensitive, we cache an IR based on the + // EVERYWHERE context + return getAnalysisCache().getSSACache().findOrCreateIR(node.getMethod(), Everywhere.EVERYWHERE, options.getSSAOptions()); + } + + public int getNumberOfStatements(CGNode node) { + IR ir = getIR(node); + return (ir == null) ? -1 : ir.getInstructions().length; + } + + @Override + public boolean recordFactoryType(CGNode node, IClass klass) { + return false; + } + + public ControlFlowGraph getCFG(CGNode N) { + IR ir = getIR(N); + if (ir == null) { + return null; + } else { + return ir.getControlFlowGraph(); + } + } + + public DefUse getDU(CGNode node) { + if (node == null) { + throw new IllegalArgumentException("node is null"); + } + // Note: since this is context-insensitive, we cache an IR based on the + // EVERYWHERE context + return getAnalysisCache().getSSACache().findOrCreateDU(node.getMethod(), Everywhere.EVERYWHERE, options.getSSAOptions()); + } +} diff --git a/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/cfa/DefaultPointerKeyFactory.java b/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/cfa/DefaultPointerKeyFactory.java index 21368227e..2d06e1f25 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/cfa/DefaultPointerKeyFactory.java +++ b/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/cfa/DefaultPointerKeyFactory.java @@ -1,75 +1,75 @@ -/******************************************************************************* - * 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.ipa.callgraph.propagation.cfa; - -import com.ibm.wala.classLoader.IField; -import com.ibm.wala.ipa.callgraph.CGNode; -import com.ibm.wala.ipa.callgraph.propagation.ArrayContentsKey; -import com.ibm.wala.ipa.callgraph.propagation.FilteredPointerKey; -import com.ibm.wala.ipa.callgraph.propagation.InstanceFieldKey; -import com.ibm.wala.ipa.callgraph.propagation.InstanceKey; -import com.ibm.wala.ipa.callgraph.propagation.LocalPointerKey; -import com.ibm.wala.ipa.callgraph.propagation.LocalPointerKeyWithFilter; -import com.ibm.wala.ipa.callgraph.propagation.PointerKey; -import com.ibm.wala.ipa.callgraph.propagation.PointerKeyFactory; -import com.ibm.wala.ipa.callgraph.propagation.ReturnValueKey; -import com.ibm.wala.ipa.callgraph.propag