/******************************************************************************* * 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.slicer.thin; import java.util.Collection; import java.util.Collections; import java.util.Map; import java.util.Set; 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.PointerAnalysis; import com.ibm.wala.ipa.callgraph.propagation.PointerKey; import com.ibm.wala.ipa.modref.DelegatingExtendedHeapModel; import com.ibm.wala.ipa.modref.ExtendedHeapModel; import com.ibm.wala.ipa.modref.ModRef; import com.ibm.wala.ipa.slicer.NormalStatement; 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.ssa.IR; import com.ibm.wala.ssa.SSAInstruction; import com.ibm.wala.util.collections.HashMapFactory; import com.ibm.wala.util.graph.Graph; import com.ibm.wala.util.graph.impl.GraphInverter; import com.ibm.wala.util.graph.traverse.DFS; /** * A cheap, context-insensitive slicer based on reachability over a custom SDG. * * This is a prototype implementation; not tuned. * * Currently supports backward slices only. * * TODO: Introduce a slicer interface common between this and the CS slicer. TODO: This hasn't been tested much. Need regression * tests. */ public class CISlicer { /** * the dependence graph used for context-insensitive slicing */ private final Graph<Statement> depGraph; public CISlicer(CallGraph cg, PointerAnalysis<InstanceKey> pa, DataDependenceOptions dOptions, ControlDependenceOptions cOptions) { this(cg, pa, ModRef.make(), dOptions, cOptions); } public CISlicer(CallGraph cg, PointerAnalysis<InstanceKey> pa, ModRef modRef, DataDependenceOptions dOptions, ControlDependenceOptions cOptions) throws IllegalArgumentException { if (dOptions == null) { throw new IllegalArgumentException("dOptions == null"); } if (dOptions.equals(DataDependenceOptions.NO_BASE_PTRS) || dOptions.equals(DataDependenceOptions.FULL)) { throw new IllegalArgumentException("Heap data dependences requested in CISlicer!"); } SDG sdg = new SDG(cg, pa, modRef, dOptions, cOptions, null); Map<Statement, Set<PointerKey>> mod = scanForMod(sdg, pa, modRef); Map<Statement, Set<PointerKey>> ref = scanForRef(sdg, pa, modRef); depGraph = GraphInverter.invert(new CISDG(sdg, mod, ref)); } public CISlicer(final SDG sdg, final PointerAnalysis<InstanceKey> pa, final ModRef modRef) { Map<Statement, Set<PointerKey>> mod = scanForMod(sdg, pa, modRef); Map<Statement, Set<PointerKey>> ref = scanForRef(sdg, pa, modRef); depGraph = GraphInverter.invert(new CISDG(sdg, mod, ref)); } public Collection<Statement> computeBackwardThinSlice(Statement seed) { Collection<Statement> slice = DFS.getReachableNodes(depGraph, Collections.singleton(seed)); return slice; } public Collection<Statement> computeBackwardThinSlice(Collection<Statement> seeds) { Collection<Statement> slice = DFS.getReachableNodes(depGraph, seeds); return slice; } /** * Compute the set of pointer keys each statement mods */ public static Map<Statement, Set<PointerKey>> scanForMod(SDG sdg, PointerAnalysis<InstanceKey> pa) { return scanForMod(sdg, pa, false, ModRef.make()); } /** * Compute the set of pointer keys each statement refs */ public static Map<Statement, Set<PointerKey>> scanForRef(SDG sdg, PointerAnalysis<InstanceKey> pa) { if (sdg == null) { throw new IllegalArgumentException("null sdg"); } return scanForRef(sdg, pa, ModRef.make()); } /** * Compute the set of pointer keys each statement mods */ public static Map<Statement, Set<PointerKey>> scanForMod(SDG sdg, PointerAnalysis<InstanceKey> pa, ModRef modRef) { return scanForMod(sdg, pa, false, modRef); } /** * Compute the set of pointer keys each statement mods. Be careful to avoid eager PDG construction here! That means .. don't * iterate over SDG statements! */ public static Map<Statement, Set<PointerKey>> scanForMod(SDG sdg, PointerAnalysis<InstanceKey> pa, boolean ignoreAllocHeapDefs, ModRef modRef) { if (pa == null) { throw new IllegalArgumentException("null pa"); } ExtendedHeapModel h = new DelegatingExtendedHeapModel(pa.getHeapModel()); Map<Statement, Set<PointerKey>> result = HashMapFactory.make(); for (CGNode n : sdg.getCallGraph()) { IR ir = n.getIR(); if (ir != null) { for (int i = 0; i < ir.getInstructions().length; i++) { SSAInstruction st = ir.getInstructions()[i]; if (st != null) { Set<PointerKey> mod = modRef.getMod(n, h, pa, st, null, ignoreAllocHeapDefs); if (!mod.isEmpty()) { NormalStatement normal = new NormalStatement(n, i); result.put(normal, mod); } } } } } return result; } /** * Compute the set of PointerKeys each statement refs.Be careful to avoid eager PDG construction here! That means .. don't iterate * over SDG statements! */ public static Map<Statement, Set<PointerKey>> scanForRef(SDG sdg, PointerAnalysis<InstanceKey> pa, ModRef modRef) { if (pa == null) { throw new IllegalArgumentException("null pa"); } ExtendedHeapModel h = new DelegatingExtendedHeapModel(pa.getHeapModel()); Map<Statement, Set<PointerKey>> result = HashMapFactory.make(); for (CGNode n : sdg.getCallGraph()) { IR ir = n.getIR(); if (ir != null) { for (int i = 0; i < ir.getInstructions().length; i++) { SSAInstruction st = ir.getInstructions()[i]; if (st != null) { Set<PointerKey> mod = modRef.getRef(n, h, pa, st, null); if (!mod.isEmpty()) { NormalStatement normal = new NormalStatement(n, i); result.put(normal, mod); } } } } } return result; } }