/******************************************************************************* * This program and the accompanying materials * are made available under the 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.IR; import com.ibm.wala.ssa.ISSABasicBlock; import com.ibm.wala.ssa.SSAAbstractInvokeInstruction; 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; public AllValsStatementVisitor(CGNode node) { this.node = node; this.ir = node.getIR(); 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) { 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<IClass> 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<SSAAbstractInvokeInstruction> 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<ProgramCounter> peis = SSAPropagationCallGraphBuilder.getIncomingPEIs(ir, getBasicBlock()); PointerKey def = heapModel.getPointerKeyForLocal(node, instruction.getDef()); Set<IClass> 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! */ @Override public void setBasicBlock(ISSABasicBlock block) { basicBlock = block; } @Override public void visitLoadMetadata(SSALoadMetadataInstruction instruction) { Assertions.UNREACHABLE(); } } }