/******************************************************************************* * 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 * <ul> * <li>flow from local -> local representing assignment (i.e. phi,pi) * <li>flow from instancekey -> local for news * <li>flow from formal -> actual parameter * <li>flow from return value -> local * <li>match edges * <li>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. * </ul> * * 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<Object> { 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<PointerKey, IField> getFieldDefs = HashMapFactory.make(); final Collection<PointerKey> 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<PointerKey, SSAInvokeInstruction> 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<PointerKey, CGNode> 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<Object> 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<Object> 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<MemoryAccess> 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<CallSiteReference> 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<CGNode> 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<MemoryAccess> fieldWrites = fam.getFieldWrites(null, f); addMatchHelper(pk, fieldWrites); } private void addMatchHelper(LocalPointerKey pk, Collection<MemoryAccess> 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<MemoryAccess> 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<ProgramCounter> 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<ProgramCounter> peis, PointerKey exceptionVar, Set<IClass> 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<TypeReference> 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<SSAInstruction, ISSABasicBlock> 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<SSAInstruction, ISSABasicBlock> cfg, ISSABasicBlock b, StatementVisitor v) { v.setBasicBlock(b); // visit each instruction in the basic block. for (Iterator<SSAInstruction> 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<SSAInstruction, ISSABasicBlock> cfg, ISSABasicBlock b) { // visit each phi instruction in each successor block for (Iterator<? extends IBasicBlock> 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<? extends IBasicBlock> back = cfg.getPredNodes(sb); back.hasNext(); n++) { if (back.next() == b) { break; } } assert n < cfg.getPredNodeCount(sb); for (Iterator<SSAPhiInstruction> 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<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()); // 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<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); } // 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(); // } // } }