added coarser lexical-scoping resolver. reduces memory usage, but analysis seems to slower. disabled as regression tests don't pass

git-svn-id: https://wala.svn.sourceforge.net/svnroot/wala/trunk@4352 f5eafffb-2e1d-0410-98e4-8ec43c5233c4
This commit is contained in:
msridhar1 2012-01-06 21:31:15 +00:00
parent 6e4db282b6
commit 72c2c92294
2 changed files with 156 additions and 36 deletions

View File

@ -314,7 +314,7 @@ public abstract class AstSSAPropagationCallGraphBuilder extends SSAPropagationCa
} else { } else {
for(Access a : instruction.getAccesses()) { for(Access a : instruction.getAccesses()) {
Pair<String,String> name = a.getName(); Pair<String,String> name = a.getName();
if ((r.isReadOnly(name)? r.getReadOnlyValue(name): r.getLexicalSites(name)) == null) { if ((r.isReadOnly(name)? r.getReadOnlyValues(name): r.getLexicalSites(name)) == null) {
return false; return false;
} }
} }
@ -608,7 +608,10 @@ public abstract class AstSSAPropagationCallGraphBuilder extends SSAPropagationCa
if (r.isReadOnly(accesses[i].getName())) { if (r.isReadOnly(accesses[i].getName())) {
assert isLoad; assert isLoad;
foundOnStack = true; foundOnStack = true;
action(r.getReadOnlyValue(accesses[i].getName()), vn); Set<LocalPointerKey> vals = r.getReadOnlyValues(accesses[i].getName());
for (LocalPointerKey val : vals) {
action(val, vn);
}
} else { } else {
Iterator<Pair<CallSiteReference,CGNode>> sites = r.getLexicalSites(accesses[i].getName()); Iterator<Pair<CallSiteReference,CGNode>> sites = r.getLexicalSites(accesses[i].getName());
while(sites.hasNext()) { while(sites.hasNext()) {

View File

@ -1,7 +1,6 @@
package com.ibm.wala.cast.ipa.callgraph; package com.ibm.wala.cast.ipa.callgraph;
import java.util.HashMap; import java.util.Collections;
import java.util.HashSet;
import java.util.Iterator; import java.util.Iterator;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
@ -18,8 +17,12 @@ import com.ibm.wala.ipa.callgraph.ContextSelector;
import com.ibm.wala.ipa.callgraph.propagation.InstanceKey; import com.ibm.wala.ipa.callgraph.propagation.InstanceKey;
import com.ibm.wala.ipa.callgraph.propagation.LocalPointerKey; import com.ibm.wala.ipa.callgraph.propagation.LocalPointerKey;
import com.ibm.wala.ipa.callgraph.propagation.PropagationCallGraphBuilder; import com.ibm.wala.ipa.callgraph.propagation.PropagationCallGraphBuilder;
import com.ibm.wala.util.collections.CompoundIterator;
import com.ibm.wala.util.collections.EmptyIterator; 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.IteratorPlusOne; import com.ibm.wala.util.collections.IteratorPlusOne;
import com.ibm.wala.util.collections.MapUtil;
import com.ibm.wala.util.collections.NonNullSingletonIterator; import com.ibm.wala.util.collections.NonNullSingletonIterator;
import com.ibm.wala.util.collections.Pair; import com.ibm.wala.util.collections.Pair;
import com.ibm.wala.util.intset.IntSet; import com.ibm.wala.util.intset.IntSet;
@ -32,6 +35,8 @@ public final class LexicalScopingResolverContexts implements ContextSelector {
} }
}; };
private static final boolean USE_CGNODE_RESOLVER = false;
/** /**
* used to resolve lexical accesses during call graph construction * used to resolve lexical accesses during call graph construction
*/ */
@ -53,7 +58,7 @@ public final class LexicalScopingResolverContexts implements ContextSelector {
* {@link LocalPointerKey} corresponding to name from the {@link CGNode} * {@link LocalPointerKey} corresponding to name from the {@link CGNode}
* that defines it * that defines it
*/ */
LocalPointerKey getReadOnlyValue(Pair<String, String> name); Set<LocalPointerKey> getReadOnlyValues(Pair<String, String> name);
/** /**
* get the site-node pairs (s,n) in the scope-resolver chain such that n has * get the site-node pairs (s,n) in the scope-resolver chain such that n has
@ -88,8 +93,8 @@ public final class LexicalScopingResolverContexts implements ContextSelector {
parent = globalResolver; parent = globalResolver;
} }
Map<String, LocalPointerKey> readOnlyNames = new HashMap<String, LocalPointerKey>(); Map<String, LocalPointerKey> readOnlyNames = HashMapFactory.make();
Set<Pair<String, String>> readWritesNames = new HashSet<Pair<String, String>>(); Set<Pair<String, String>> readWriteNames = HashSetFactory.make();
LexicalInformation LI = ((AstMethod) caller.getMethod()).lexicalInfo(); LexicalInformation LI = ((AstMethod) caller.getMethod()).lexicalInfo();
int[] exposedUses = LI.getExposedUses(callSite.getProgramCounter()); int[] exposedUses = LI.getExposedUses(callSite.getProgramCounter());
@ -101,31 +106,46 @@ public final class LexicalScopingResolverContexts implements ContextSelector {
if (LI.isReadOnly(exposedNames[i].snd)) { if (LI.isReadOnly(exposedNames[i].snd)) {
readOnlyNames.put(exposedNames[i].snd, new LocalPointerKey(caller, exposedUses[i])); readOnlyNames.put(exposedNames[i].snd, new LocalPointerKey(caller, exposedUses[i]));
} else { } else {
readWritesNames.add(exposedNames[i]); readWriteNames.add(exposedNames[i]);
} }
} }
} }
} }
Object key; if (USE_CGNODE_RESOLVER) {
if (!readWritesNames.isEmpty()) { CGNodeResolver result = (CGNodeResolver) parent.children().get(caller);
key = Pair.make(caller, callSite); if (result == null) {
} else { result = new CGNodeResolver(parent, caller);
key = readOnlyNames.keySet(); parent.children().put(caller, result);
} }
for (String readOnlyName : readOnlyNames.keySet()) {
if (parent.children().containsKey(key)) { result.addReadOnlyName(readOnlyName, readOnlyNames.get(readOnlyName));
return parent.children().get(key); }
} for (Pair<String, String> readWriteName : readWriteNames) {
result.addReadWriteName(readWriteName, callSite);
if (!readWritesNames.isEmpty()) { }
SiteResolver result = new SiteResolver(parent, caller, readOnlyNames, callSite, readWritesNames);
parent.children().put(key, result);
return result; return result;
} else { } else {
ReadOnlyResolver result = new ReadOnlyResolver(parent, caller, readOnlyNames); Object key;
parent.children().put(key, result); if (!readWriteNames.isEmpty()) {
return result; key = Pair.make(caller, callSite);
} else {
key = readOnlyNames.keySet();
}
if (parent.children().containsKey(key)) {
return parent.children().get(key);
}
if (!readWriteNames.isEmpty()) {
SiteResolver result = new SiteResolver(parent, caller, readOnlyNames, callSite, readWriteNames);
parent.children().put(key, result);
return result;
} else {
ReadOnlyResolver result = new ReadOnlyResolver(parent, caller, readOnlyNames);
parent.children().put(key, result);
return result;
}
} }
} }
@ -138,7 +158,7 @@ public final class LexicalScopingResolverContexts implements ContextSelector {
return false; return false;
} }
public LocalPointerKey getReadOnlyValue(Pair<String, String> name) { public Set<LocalPointerKey> getReadOnlyValues(Pair<String, String> name) {
throw new UnsupportedOperationException("not expecting read only global"); throw new UnsupportedOperationException("not expecting read only global");
} }
@ -155,7 +175,7 @@ public final class LexicalScopingResolverContexts implements ContextSelector {
public Map<Object, LexicalScopingResolver> children() { public Map<Object, LexicalScopingResolver> children() {
if (children == null) { if (children == null) {
children = new HashMap<Object, LexicalScopingResolver>(); children = HashMapFactory.make();
} }
return children; return children;
} }
@ -177,6 +197,103 @@ public final class LexicalScopingResolverContexts implements ContextSelector {
} }
}; };
/**
* single {@link LexicalScopingResolver} for a CGNode, handling read-only and
* read-write names
*/
class CGNodeResolver implements LexicalScopingResolver {
private final LexicalScopingResolver parent;
private Map<Object, LexicalScopingResolver> children;
/**
* definer name for corresponding scope
*/
private final String myDefiner;
private final CGNode myNode;
/**
* maps a read-only name defined in this scope to the local pointer keys by
* which it is referenced at call sites encountered thus far
*/
private Map<String, Set<LocalPointerKey>> myReadOnlyDefs = null;
/**
* maps a name defined in this scope that may be defined in a nested scope
* to the set of call sites at which it is exposed for nested writes
*/
private Map<Pair<String, String>, Set<Pair<CallSiteReference, CGNode>>> myDefs = null;
public CGNodeResolver(LexicalScopingResolver parent, CGNode myNode) {
super();
this.parent = parent;
this.myDefiner = ((AstMethod) myNode.getMethod()).lexicalInfo().getScopingName();
this.myNode = myNode;
}
public void addReadWriteName(Pair<String, String> readWriteName, CallSiteReference callSite) {
if (myDefs == null) {
myDefs = HashMapFactory.make();
}
MapUtil.findOrCreateSet(myDefs, readWriteName).add(Pair.make(callSite, myNode));
}
public void addReadOnlyName(String readOnlyName, LocalPointerKey localPointerKey) {
if (myReadOnlyDefs == null) {
myReadOnlyDefs = HashMapFactory.make();
}
MapUtil.findOrCreateSet(myReadOnlyDefs, readOnlyName).add(localPointerKey);
}
public LexicalScopingResolver getParent() {
return parent;
}
public boolean isReadOnly(Pair<String, String> name) {
if (myDefiner.equals(name.fst)) {
return myReadOnlyDefs != null && myReadOnlyDefs.containsKey(name.snd);
} else {
return parent.isReadOnly(name);
}
}
public Set<LocalPointerKey> getReadOnlyValues(Pair<String, String> name) {
if (myDefiner.equals(name.fst)) {
return myReadOnlyDefs.get(name.snd);
} else {
return parent.getReadOnlyValues(name);
}
}
public Iterator<Pair<CallSiteReference, CGNode>> getLexicalSites(Pair<String, String> name) {
if (myDefs == null || myDefs.containsKey(name)) {
if (myDefiner.equals(name.snd)) {
// no need to recurse to parent
return myDefs.get(name).iterator();
} else {
return new CompoundIterator<Pair<CallSiteReference, CGNode>>(parent.getLexicalSites(name), myDefs.get(name).iterator());
}
} else {
return parent.getLexicalSites(name);
}
}
public Map<Object, LexicalScopingResolver> children() {
if (children == null) {
children = HashMapFactory.make();
}
return children;
}
public CGNode getOriginalDefiner(Pair<String, String> name) {
if (myDefiner.equals(name.snd)) {
return myNode;
} else {
return parent.getOriginalDefiner(name);
}
}
}
/** /**
* {@link LexicalScopingResolver} for case where all exposed names from the * {@link LexicalScopingResolver} for case where all exposed names from the
* corresponding scope are read-only * corresponding scope are read-only
@ -206,17 +323,17 @@ public final class LexicalScopingResolverContexts implements ContextSelector {
} }
} }
public LocalPointerKey getReadOnlyValue(Pair<String, String> name) { public Set<LocalPointerKey> getReadOnlyValues(Pair<String, String> name) {
if (myDefiner.equals(name.fst)) { if (myDefiner.equals(name.fst)) {
return myReadOnlyDefs.get(name.snd); return Collections.singleton(myReadOnlyDefs.get(name.snd));
} else { } else {
return parent.getReadOnlyValue(name); return parent.getReadOnlyValues(name);
} }
} }
public Map<Object, LexicalScopingResolver> children() { public Map<Object, LexicalScopingResolver> children() {
if (children == null) { if (children == null) {
children = new HashMap<Object, LexicalScopingResolver>(); children = HashMapFactory.make();
} }
return children; return children;
} }
@ -242,8 +359,8 @@ public final class LexicalScopingResolverContexts implements ContextSelector {
StringBuilder result = new StringBuilder(); StringBuilder result = new StringBuilder();
result.append("ReadOnlyResolver[myDefiner="); result.append("ReadOnlyResolver[myDefiner=");
result.append(myDefiner); result.append(myDefiner);
// result.append(", myNode="); // result.append(", myNode=");
// result.append(myNode); // result.append(myNode);
result.append(",\n myReadOnlyDefs="); result.append(",\n myReadOnlyDefs=");
result.append(myReadOnlyDefs); result.append(myReadOnlyDefs);
result.append(",\n parent="); result.append(",\n parent=");
@ -290,8 +407,8 @@ public final class LexicalScopingResolverContexts implements ContextSelector {
StringBuilder result = new StringBuilder(); StringBuilder result = new StringBuilder();
result.append("SiteResolver[myDefiner="); result.append("SiteResolver[myDefiner=");
result.append(myDefiner); result.append(myDefiner);
// result.append(", myNode="); // result.append(", myNode=");
// result.append(myNode); // result.append(myNode);
result.append(",\n mySite="); result.append(",\n mySite=");
result.append(mySite); result.append(mySite);
result.append(",\n myReadOnlyDefs="); result.append(",\n myReadOnlyDefs=");