WALA/com.ibm.wala.core/src/com/ibm/wala/ipa/modref/ModRefFieldAccess.java

227 lines
6.4 KiB
Java

/******************************************************************************
* Copyright (c) 2002 - 2014 IBM Corporation.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this 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.modref;
import java.util.HashMap;
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.IClass;
import com.ibm.wala.classLoader.IField;
import com.ibm.wala.ipa.callgraph.CGNode;
import com.ibm.wala.ipa.callgraph.CallGraph;
import com.ibm.wala.ssa.IR;
import com.ibm.wala.ssa.SSAGetInstruction;
import com.ibm.wala.ssa.SSAInstruction;
import com.ibm.wala.ssa.SSAPutInstruction;
import com.ibm.wala.types.FieldReference;
/**
* Computes interprocedural field accesses for a given method.
*
* @author Martin Seidel
* @author Juergen Graf <juergen.graf@gmail.com>
*
*/
public final class ModRefFieldAccess {
private class TwoMaps {
private Map<IClass, Set<IField>> mods;
private Map<IClass, Set<IField>> refs;
public TwoMaps(Map<IClass, Set<IField>> mods, Map<IClass, Set<IField>> refs) {
this.mods = mods;
this.refs = refs;
if (mods == null) {
this.mods = new HashMap<IClass, Set<IField>>();
}
if (refs == null) {
this.refs = new HashMap<IClass, Set<IField>>();
}
}
public Map<IClass, Set<IField>> getMods() {
return mods;
}
public Map<IClass, Set<IField>> getRefs() {
return refs;
}
}
private final CallGraph cg;
private Map<CGNode, Map<IClass, Set<IField>>> mods;
private Map<CGNode, Map<IClass, Set<IField>>> refs;
private Map<CGNode, Map<IClass, Set<IField>>> tmods;
private Map<CGNode, Map<IClass, Set<IField>>> trefs;
private List<CGNode> done;
private ModRefFieldAccess(CallGraph cg) {
this.cg = cg;
this.refs = new HashMap<CGNode, Map<IClass, Set<IField>>>();
this.mods = new HashMap<CGNode, Map<IClass, Set<IField>>>();
this.trefs = new HashMap<CGNode, Map<IClass, Set<IField>>>();
this.tmods = new HashMap<CGNode, Map<IClass, Set<IField>>>();
this.done = new LinkedList<CGNode>();
}
public static ModRefFieldAccess compute(CallGraph cg) {
ModRefFieldAccess fa = new ModRefFieldAccess(cg);
fa.run();
return fa;
}
public Map<IClass, Set<IField>> getMod(CGNode node) {
return mods.get(node);
}
public Map<IClass, Set<IField>> getRef(CGNode node) {
return refs.get(node);
}
public Map<IClass, Set<IField>> getTransitiveMod(CGNode node) {
return tmods.get(node);
}
public Map<IClass, Set<IField>> getTransitiveRef(CGNode node) {
return trefs.get(node);
}
private void run() {
for (CGNode cgNode : cg) {
if (!refs.containsKey(cgNode)) {
refs.put(cgNode, new HashMap<IClass, Set<IField>>());
}
if (!mods.containsKey(cgNode)) {
mods.put(cgNode, new HashMap<IClass, Set<IField>>());
}
final IR ir = cgNode.getIR();
if (ir == null) {
continue;
}
for (Iterator<SSAInstruction> it = ir.iterateNormalInstructions(); it.hasNext();) {
SSAInstruction instr = it.next();
if (instr instanceof SSAGetInstruction) {
SSAGetInstruction get = (SSAGetInstruction) instr;
FieldReference fref = get.getDeclaredField();
IField field = cg.getClassHierarchy().resolveField(fref);
if(field != null) {
IClass cls = field.getDeclaringClass();
if(cls != null) {
if (!refs.get(cgNode).containsKey(cls)) {
refs.get(cgNode).put(cls, new HashSet<IField>());
}
refs.get(cgNode).get(cls).add(field);
}
}
} else if (instr instanceof SSAPutInstruction) {
SSAPutInstruction put = (SSAPutInstruction) instr;
FieldReference fput = put.getDeclaredField();
IField field = cg.getClassHierarchy().resolveField(fput);
if(field != null) {
IClass cls = field.getDeclaringClass();
if(cls != null) {
if (!mods.get(cgNode).containsKey(cls)) {
mods.get(cgNode).put(cls, new HashSet<IField>());
}
mods.get(cgNode).get(cls).add(field);
}
}
}
}
}
recAdd(cg.getFakeRootNode());
}
private TwoMaps recAdd(CGNode node) {
if (!trefs.containsKey(node)) {
trefs.put(node, new HashMap<IClass, Set<IField>>());
}
if (!tmods.containsKey(node)) {
tmods.put(node, new HashMap<IClass, Set<IField>>());
}
final IR ir = node.getIR();
if (ir != null) {
for (Iterator<SSAInstruction> it = ir.iterateNormalInstructions(); it.hasNext();) {
SSAInstruction instr = it.next();
if (instr instanceof SSAGetInstruction) {
SSAGetInstruction get = (SSAGetInstruction) instr;
FieldReference fref = get.getDeclaredField();
IField field = cg.getClassHierarchy().resolveField(fref);
if(field != null) {
IClass cls = field.getDeclaringClass();
if(cls != null) {
if (!trefs.get(node).containsKey(cls)) {
trefs.get(node).put(cls, new HashSet<IField>());
}
trefs.get(node).get(cls).add(field);
}
}
} else if (instr instanceof SSAPutInstruction) {
SSAPutInstruction put = (SSAPutInstruction) instr;
FieldReference fput = put.getDeclaredField();
IField field = cg.getClassHierarchy().resolveField(fput);
if(field != null) {
IClass cls = field.getDeclaringClass();
if(cls != null) {
if (!tmods.get(node).containsKey(cls)) {
tmods.get(node).put(cls, new HashSet<IField>());
}
tmods.get(node).get(cls).add(field);
}
}
}
}
}
for (Iterator<CGNode> it = cg.getSuccNodes(node); it.hasNext();) {
CGNode n = it.next();
if (!done.contains(n)) {
done.add(n);
TwoMaps t = recAdd(n);
for (IClass c : t.getRefs().keySet()) {
if (trefs.get(node).containsKey(c)) {
trefs.get(node).get(c).addAll(t.getRefs().get(c));
} else {
trefs.get(node).put(c, t.getRefs().get(c));
}
}
for (IClass c : t.getMods().keySet()) {
if (tmods.get(node).containsKey(c)) {
tmods.get(node).get(c).addAll(t.getMods().get(c));
} else {
tmods.get(node).put(c, t.getMods().get(c));
}
}
}
}
return new TwoMaps(tmods.get(node), trefs.get(node));
}
}