fixes to source variable name tracking, and new test to verify fix

This commit is contained in:
Julian Dolby 2014-07-01 21:23:52 +02:00
parent 861bf48c7f
commit 5c0285c410
4 changed files with 109 additions and 41 deletions

View File

@ -0,0 +1,24 @@
function f() {
var x = 10;
var y;
y = x;
if(y == 100) {
return true;
}
return false;
}
function ff() {
var x = 10;
var y;
y = x;
var z;
z = y;
if(z == 100) {
return true;
}
return false;
}
var b = f();
var c = ff();

View File

@ -15,7 +15,6 @@ import java.util.List;
import junit.framework.Assert;
import org.eclipse.core.runtime.IProgressMonitor;
import org.junit.Test;
import com.ibm.wala.cast.ipa.callgraph.CAstCallGraphUtil;
@ -694,7 +693,7 @@ public abstract class TestSimpleCallGraphShape extends TestJSCallGraphShape {
CAstCallGraphUtil.dumpCG(B.getPointerAnalysis(), CG);
}
@Test
@Test
public void testTutorialExample() throws IllegalArgumentException, IOException, CancelException, WalaException {
PropagationCallGraphBuilder B = JSCallGraphBuilderUtil.makeScriptCGBuilder("tests", "tutorial-example.js");
CallGraph CG = B.makeCallGraph(B.getOptions());
@ -702,4 +701,16 @@ public abstract class TestSimpleCallGraphShape extends TestJSCallGraphShape {
// verifyGraphAssertions(CG, assertionsForDateProperty);
}
Object[][] renamingAssertions = {
{ "tests/rename-example.js/f", new Name[]{ new Name(9, 7, "x"), new Name(9, 7, "y") } },
{ "tests/rename-example.js/ff", new Name[]{ new Name(11, 10, "x"), new Name(11, 10, "y"), new Name(11, 10, "z") } }
};
@Test
public void testRenaming() throws IOException, WalaException, IllegalArgumentException, CancelException {
PropagationCallGraphBuilder B = JSCallGraphBuilderUtil.makeScriptCGBuilder("tests", "rename-example.js");
CallGraph CG = B.makeCallGraph(B.getOptions());
verifyNameAssertions(CG, renamingAssertions);
}
}

View File

@ -97,22 +97,24 @@ public class CorrelationFinder {
if(inst instanceof AbstractReflectivePut)
puts.addFirst((AbstractReflectivePut)inst);
instrs: for(SSAInstruction inst : Iterator2Iterable.make(ir.iterateNormalInstructions()))
SSAInstruction insts[] = ir.getInstructions();
instrs: for(int ii = 0; ii < insts.length; ii++) {
SSAInstruction inst = insts[ii];
if(inst instanceof AbstractReflectiveGet) {
AbstractReflectiveGet get = (AbstractReflectiveGet)inst;
int index = get.getMemberRef();
if(ir.getSymbolTable().isConstant(index))
continue;
if(ir.getSymbolTable().isParameter(index))
continue;
// try to determine what "index" is called at the source level
String indexName = getSourceLevelName(astMethod, index);
String indexName = getSourceLevelName(ir, ii, index);
if(indexName == null)
continue instrs;
// check that "index" is not accessed in an inner function
LexicalInformation lexicalInfo = astMethod.lexicalInfo();
if (lexicalInfo.getExposedNames() != null) {
@ -121,11 +123,11 @@ public class CorrelationFinder {
continue instrs;
}
}
// if "index" is a numeric variable, it is not worth extracting
if(IGNORE_NUMERIC_INDICES && mustBeNumeric(ir, du, index))
continue instrs;
// set of SSA variables into which the value read by 'get' may flow
MutableIntSet reached = new BitVectorIntSet();
reached.add(get.getDef());
@ -137,6 +139,7 @@ public class CorrelationFinder {
Integer i = worklist.pop();
done.add(i);
for(SSAInstruction inst2 : Iterator2Iterable.make(du.getUses(i))) {
int i2 = instrIndices.getMappedIndex(inst2);
if(inst2 instanceof SSAPhiInstruction) {
int def = inst2.getDef();
if(reached.add(def) && !done.contains(def))
@ -149,7 +152,7 @@ public class CorrelationFinder {
if(TRACK_ESCAPES) {
for(int j=0;j<inst2.getNumberOfUses();++j) {
if(inst2.getUse(j) == index) {
summary.addCorrelation(new EscapeCorrelation(get, (SSAAbstractInvokeInstruction)inst2, indexName, getSourceLevelNames(astMethod, reached)));
summary.addCorrelation(new EscapeCorrelation(get, (SSAAbstractInvokeInstruction)inst2, indexName, getSourceLevelNames(ir, i2, reached)));
break;
}
}
@ -160,22 +163,23 @@ public class CorrelationFinder {
// now find property writes with the same index whose RHS is in 'reached'
for(AbstractReflectivePut put : puts)
if(put.getMemberRef() == index && reached.contains(put.getValue()))
summary.addCorrelation(new ReadWriteCorrelation(get, put, indexName, getSourceLevelNames(astMethod, reached)));
summary.addCorrelation(new ReadWriteCorrelation(get, put, indexName, getSourceLevelNames(ir, ii, reached)));
}
}
return summary;
}
// tries to determine which source level variable an SSA variable corresponds to
// if it does not correspond to any variable, or to more than one, null is returned
private static String getSourceLevelName(AstMethod astMethod, int v) {
private static String getSourceLevelName(IR ir, int index, int vn) {
String indexName = null;
String[][] sourceNamesForValues = astMethod.debugInfo().getSourceNamesForValues();
String[] sourceNamesForValues = ir.getLocalNames(index, vn);
if(v >= sourceNamesForValues.length)
if(sourceNamesForValues == null)
return null;
for(String candidateName : sourceNamesForValues[v]) {
for(String candidateName : sourceNamesForValues) {
if(indexName != null) {
indexName = null;
break;
@ -186,10 +190,10 @@ public class CorrelationFinder {
return indexName;
}
private static Set<String> getSourceLevelNames(AstMethod astMethod, IntSet vs) {
private static Set<String> getSourceLevelNames(IR ir, int index, IntSet vs) {
Set<String> res = new HashSet<String>();
for(IntIterator iter=vs.intIterator();iter.hasNext();) {
String name = getSourceLevelName(astMethod, iter.next());
String name = getSourceLevelName(ir, index, iter.next());
if(name != null)
res.add(name);
}

View File

@ -10,6 +10,7 @@
*****************************************************************************/
package com.ibm.wala.cast.ir.ssa;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
@ -29,6 +30,7 @@ import com.ibm.wala.ssa.SSAPhiInstruction;
import com.ibm.wala.ssa.SymbolTable;
import com.ibm.wala.util.collections.HashMapFactory;
import com.ibm.wala.util.collections.HashSetFactory;
import com.ibm.wala.util.collections.Pair;
import com.ibm.wala.util.intset.BitVector;
import com.ibm.wala.util.intset.BitVectorIntSet;
import com.ibm.wala.util.intset.IntSet;
@ -63,6 +65,8 @@ public class SSAConversion extends AbstractSSAConversion {
private SSA2LocalMap computedLocalMap;
private Map<Integer,Integer> assignments = HashMapFactory.make();
//
// Copy propagation history
//
@ -81,6 +85,11 @@ public class SSAConversion extends AbstractSSAConversion {
this.instructionIndex = instructionIndex;
}
@Override
public String toString() {
return "[use " + useNumber + " of " + instructionIndex + "]";
}
@Override
public int hashCode() {
return useNumber * instructionIndex;
@ -106,6 +115,11 @@ public class SSAConversion extends AbstractSSAConversion {
this.useNumber = useNumber;
}
@Override
public String toString() {
return "[use " + useNumber + " of " + phiNumber + " of block " + BBnumber + "]";
}
@Override
public int hashCode() {
return phiNumber * BBnumber * useNumber;
@ -121,12 +135,24 @@ public class SSAConversion extends AbstractSSAConversion {
private class CopyPropagationRecord {
final int rhs;
final int lhs;
final int instructionIndex;
final Set<Object> renamedUses = HashSetFactory.make(2);
private final Set<CopyPropagationRecord> childRecords = HashSetFactory.make(1);
@Override
public String toString() {
StringBuffer sb = new StringBuffer("<vn " + rhs + " at " + instructionIndex);
for (CopyPropagationRecord c : childRecords) {
sb.append("\n " + c.toString());
}
sb.append(">");
return sb.toString();
}
@Override
public int hashCode() {
return instructionIndex;
@ -141,6 +167,7 @@ public class SSAConversion extends AbstractSSAConversion {
if (DEBUG_UNDO)
System.err.println(("new copy record for instruction #" + instructionIndex + ", rhs value is " + rhs));
this.rhs = rhs;
this.lhs = lhs;
this.instructionIndex = instructionIndex;
}
@ -242,10 +269,17 @@ public class SSAConversion extends AbstractSSAConversion {
public String[] getLocalNames(int pc, int vn) {
int v = skip(vn) || vn >= valueMap.length ? vn : valueMap[vn];
String[][] namesData = debugInfo.getSourceNamesForValues();
if (namesData == null || namesData.length <= v)
return new String[0];
else
return namesData[v];
String[] vNames = namesData[v];
Set<String> x = HashSetFactory.make();
x.addAll(Arrays.asList(vNames));
while (assignments.containsKey(v)) {
v = assignments.get(v);
vNames = namesData[v];
x.addAll(Arrays.asList(vNames));
}
return x.toArray(new String[x.size()]);
}
private void undoCopyPropagation(int instructionIndex, int useNumber) {
@ -269,6 +303,17 @@ public class SSAConversion extends AbstractSSAConversion {
private Map<Object, CopyPropagationRecord> getCopyHistory() {
return copyPropagationMap;
}
@Override
public String toString() {
StringBuffer sb = new StringBuffer( super.toString() );
for(Map.Entry<Object, CopyPropagationRecord> x : copyPropagationMap.entrySet()) {
sb.append(x.getKey().toString() + " --> " + x.getValue().toString() + "\n");
}
return sb.toString();
}
}
private CopyPropagationRecord topR(int v) {
@ -382,8 +427,8 @@ public class SSAConversion extends AbstractSSAConversion {
int lhs = getDef(inst, 0);
int rhs = getUse(inst, 0);
copyNames(rhs, lhs);
assignments.put(rhs, lhs);
CopyPropagationRecord rec = new CopyPropagationRecord(index, lhs, newRhs);
R[lhs].push(rec);
if (topR(rhs) != null) {
@ -510,22 +555,6 @@ public class SSAConversion extends AbstractSSAConversion {
return v;
}
private void copyNames(int to, int from) {
String[][] namesData = debugInfo.getSourceNamesForValues();
if (namesData != null && namesData.length > from && namesData[from] != null) {
if (namesData[to] == null) {
namesData[to] = namesData[from];
} else {
Set<String> newNames = HashSetFactory.make();
for(String fromName : namesData[from])
newNames.add(fromName);
for(String toName : namesData[to])
newNames.add(toName);
namesData[to] = newNames.toArray(new String[newNames.size()]);
}
}
}
@Override
protected void initializeVariables() {
for (int V = 1; V <= getMaxValueNumber(); V++) {