fixes to source variable name tracking, and new test to verify fix
This commit is contained in:
parent
861bf48c7f
commit
5c0285c410
|
@ -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();
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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++) {
|
||||
|
|
Loading…
Reference in New Issue