1) added InstanceKey.getCreation sites and its implementations

2) fixes for issues with keys representing dynamic properties
  i) all properties are converted to strings, in an approximation of JS
semantics
3) fix to handling of instance keys representing numbers in binary +;
now it understands that adding constant keys of type Number requires
adding a non-constant Number key to the lval
This commit is contained in:
Julian Dolby 2013-01-07 20:18:27 -05:00
parent 583ebd3ce4
commit 9aa474fdb1
16 changed files with 213 additions and 26 deletions

View File

@ -623,7 +623,7 @@ public class RhinoToAstTranslator {
if (elt instanceof EmptyExpression) {
index++;
} else {
eltNodes.add(Ast.makeConstant(index++));
eltNodes.add(Ast.makeConstant("" + (index++)));
eltNodes.add(visit(elt, arg));
}
}

View File

@ -607,9 +607,24 @@ public abstract class TestSimpleCallGraphShape extends TestJSCallGraphShape {
PropagationCallGraphBuilder b = JSCallGraphBuilderUtil.makeScriptCGBuilder("tests", "array_index_conv2.js");
b.setContextSelector(new ForInContextSelector(b.getContextSelector()));
CallGraph cg = b.makeCallGraph(b.getOptions());
//JSCallGraphUtil.AVOID_DUMP = false;
//JSCallGraphUtil.dumpCG(b.getPointerAnalysis(), cg);
verifyGraphAssertions(cg, assertionsForArrayIndexConv2);
}
private static final Object[][] assertionsForDateProperty = new Object[][] {
new Object[] { ROOT, new String[] { "tests/date-property.js" } },
new Object[] { "tests/date-property.js", new String[] { "suffix:_fun" } }
};
@Test
public void testDateAsProperty() throws IllegalArgumentException, IOException, CancelException {
PropagationCallGraphBuilder B = JSCallGraphBuilderUtil.makeScriptCGBuilder("tests", "date-property.js");
CallGraph CG = B.makeCallGraph(B.getOptions());
//JSCallGraphUtil.AVOID_DUMP = false;
//JSCallGraphUtil.dumpCG(B.getPointerAnalysis(), CG);
verifyGraphAssertions(CG, assertionsForDateProperty);
}
protected IVector<Set<Pair<CGNode, Integer>>> computeIkIdToVns(PointerAnalysis pa) {

View File

@ -338,16 +338,18 @@ public class ForInContextSelector implements ContextSelector {
}
} else if(receiver.length > index) {
Frequency f = usesFirstArgAsPropertyName(callee);
/*
if(f == Frequency.ALWAYS) {
return new ForInContext(baseContext, simulateToString(caller.getClassHierarchy(), receiver[index]));
} else if(f == Frequency.SOMETIMES) {
*/
if(receiver[index] == null) {
IClass undef = caller.getClassHierarchy().lookupClass(JavaScriptTypes.Undefined);
return new ForInContext(baseContext, new ConcreteTypeKey(undef));
} else {
return new ForInContext(baseContext, receiver[index]);
}
}
//}
}
if (USE_CPA_IN_BODIES && FORIN_MARKER.equals(caller.getContext().get(FORIN_KEY))) {
return new SelectiveCPAContext(baseContext, receiver);

View File

@ -1,7 +1,14 @@
package com.ibm.wala.cast.js.ipa.callgraph;
import java.util.Iterator;
import com.ibm.wala.classLoader.IClass;
import com.ibm.wala.classLoader.NewSiteReference;
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.util.collections.EmptyIterator;
import com.ibm.wala.util.collections.Pair;
/**
* Represents the JavaScript global object.
@ -23,4 +30,9 @@ public class GlobalObjectKey implements InstanceKey {
public String toString() {
return "JS Global Object";
}
@Override
public Iterator<Pair<CGNode, NewSiteReference>> getCreationSites(CallGraph CG) {
return EmptyIterator.instance();
}
}

View File

@ -13,6 +13,7 @@ package com.ibm.wala.cast.js.ipa.callgraph;
import java.util.Iterator;
import com.ibm.wala.cast.ipa.callgraph.AstCFAPointerKeys;
import com.ibm.wala.cast.ipa.callgraph.ReflectedFieldPointerKey;
import com.ibm.wala.cast.js.types.JavaScriptTypes;
import com.ibm.wala.classLoader.IClass;
import com.ibm.wala.classLoader.IField;
@ -69,12 +70,8 @@ public abstract class JSCFABuilder extends JSSSAPropagationCallGraphBuilder {
@Override
public Iterator<PointerKey> getPointerKeysForReflectedFieldRead(InstanceKey I, InstanceKey F) {
IClassHierarchy cha = I.getConcreteType().getClassHierarchy();
IClass function = cha.lookupClass(JavaScriptTypes.Function);
if (isBogusKey(I)) {
return EmptyIterator.instance();
} else if (cha.isSubclassOf(F.getConcreteType(), function)) {
return super.getPointerKeysForReflectedFieldRead(I, new ConcreteTypeKey(function));
} else {
return super.getPointerKeysForReflectedFieldRead(I, F);
}
@ -82,12 +79,8 @@ public abstract class JSCFABuilder extends JSSSAPropagationCallGraphBuilder {
@Override
public Iterator<PointerKey> getPointerKeysForReflectedFieldWrite(InstanceKey I, InstanceKey F) {
IClassHierarchy cha = I.getConcreteType().getClassHierarchy();
IClass function = cha.lookupClass(JavaScriptTypes.Function);
if (isBogusKey(I)) {
if (isBogusKey(I)) {
return EmptyIterator.instance();
} else if (cha.isSubclassOf(F.getConcreteType(), function)) {
return super.getPointerKeysForReflectedFieldWrite(I, new ConcreteTypeKey(function));
} else {
return super.getPointerKeysForReflectedFieldWrite(I, F);
}
@ -96,23 +89,45 @@ public abstract class JSCFABuilder extends JSSSAPropagationCallGraphBuilder {
@Override
protected PointerKey getInstanceFieldPointerKeyForConstant(InstanceKey I, ConstantKey F) {
Object v = F.getValue();
if (v instanceof Double) {
String strVal = simulateNumberToString((Double)v);
IField f = I.getConcreteType().getField(Atom.findOrCreateUnicodeAtom((String) strVal));
String strVal = simulateToStringForPropertyNames(v);
// if we know the string representation of the constant, use it...
if (strVal != null) {
IField f = I.getConcreteType().getField(Atom.findOrCreateUnicodeAtom(strVal));
return getPointerKeyForInstanceField(I, f);
// ...otherwise it is some unknown string
} else {
return super.getInstanceFieldPointerKeyForConstant(I, F);
return ReflectedFieldPointerKey.mapped(new ConcreteTypeKey(getFieldNameType(F)), I);
}
}
private String simulateNumberToString(Double v) {
/**
* All values used as property names get implicitly converted to strings in JavaScript.
* @see com.ibm.wala.cast.ipa.callgraph.DelegatingAstPointerKeys#getFieldNameType(com.ibm.wala.ipa.callgraph.propagation.InstanceKey)
*/
protected IClass getFieldNameType(InstanceKey F) {
return F.getConcreteType().getClassHierarchy().lookupClass(JavaScriptTypes.String);
}
private String simulateToStringForPropertyNames(Object v) {
// TODO this is very incomplete --MS
String result = v.toString();
if (result.endsWith(".0")) {
result = result.substring(0, result.length() - 2);
if (v instanceof String) {
return (String)v;
} else if (v instanceof Double) {
String result = v.toString();
if (((double) Math.round((Double)v)) == ((Double)v).doubleValue()) {
result = Long.toString(Math.round((Double)v));
}
return result;
} else if (v instanceof Boolean) {
if (((Boolean)v).booleanValue()) {
return "true";
} else {
return "false";
}
} else {
return null;
}
return result;
}

View File

@ -776,7 +776,11 @@ public class JSSSAPropagationCallGraphBuilder extends AstSSAPropagationCallGraph
if (l.isStringType(left.getConcreteType().getReference()) || l.isStringType(right.getConcreteType().getReference())) {
return addKey(new ConcreteTypeKey(node.getClassHierarchy().lookupClass(l.getStringType())));
} else if (isNumberType(l, left.getConcreteType().getReference()) && isNumberType(l, right.getConcreteType().getReference())) {
return addKey(left) || addKey(right);
if (left instanceof ConstantKey && right instanceof ConstantKey) {
return addKey(new ConcreteTypeKey(node.getClassHierarchy().lookupClass(JavaScriptTypes.Number)));
} else {
return addKey(left) || addKey(right);
}
} else {
return false;
}
@ -943,7 +947,7 @@ public class JSSSAPropagationCallGraphBuilder extends AstSSAPropagationCallGraph
// pass actual arguments to formals in the normal way
for (int i = 0; i < Math.min(paramCount, argCount); i++) {
InstanceKey[] fn = new InstanceKey[] { getInstanceKeyForConstant(JavaScriptTypes.Number, i-num_pseudoargs) };
InstanceKey[] fn = new InstanceKey[] { getInstanceKeyForConstant(JavaScriptTypes.String, ""+(i-num_pseudoargs)) };
PointerKey F = getTargetPointerKey(target, i);
if (constParams != null && constParams[i] != null) {
@ -969,7 +973,7 @@ public class JSSSAPropagationCallGraphBuilder extends AstSSAPropagationCallGraph
if (paramCount < argCount) {
if (av != -1) {
for (int i = paramCount; i < argCount; i++) {
InstanceKey[] fn = new InstanceKey[] { getInstanceKeyForConstant(JavaScriptTypes.Number, i-num_pseudoargs) };
InstanceKey[] fn = new InstanceKey[] { getInstanceKeyForConstant(JavaScriptTypes.String, ""+(i-num_pseudoargs)) };
if (constParams != null && constParams[i] != null && i >= num_pseudoargs) {
targetVisitor.newFieldWrite(target, av, fn, constParams[i]);
} else if(i >= num_pseudoargs) {

View File

@ -238,6 +238,10 @@ public class JSAstTranslator extends AstTranslator {
String field = (String) elt.getValue();
if (isPrologueScript(context) && "__proto__".equals(field)) {
context.cfg().addInstruction(((JSInstructionFactory) insts).SetPrototype(receiver, rval));
return;
}
}
/*
} else {
context.currentScope().getConstantValue(field);
SSAPutInstruction put = ((JSInstructionFactory) insts).PutInstruction(receiver, rval, field);
@ -249,8 +253,9 @@ public class JSAstTranslator extends AstTranslator {
context.cfg().addInstruction(put);
}
} else {
*/
context.cfg().addInstruction(((JSInstructionFactory) insts).PropertyWrite(receiver, context.getValue(elt), rval));
}
// }
}
private void doPrimitiveNew(WalkContext context, int resultVal, String typeName) {

View File

@ -66,7 +66,7 @@ public class DelegatingAstPointerKeys implements AstPointerKeyFactory {
return base.getPointerKeyForArrayContents(I);
}
public Iterator<PointerKey> getPointerKeysForReflectedFieldRead(InstanceKey I, InstanceKey F) {
public Iterator<PointerKey> getPointerKeysForReflectedFieldWrite(InstanceKey I, InstanceKey F) {
List<PointerKey> result = new LinkedList<PointerKey>();
if (F instanceof ConstantKey) {
@ -106,7 +106,7 @@ public class DelegatingAstPointerKeys implements AstPointerKeyFactory {
return null;
}
public Iterator<PointerKey> getPointerKeysForReflectedFieldWrite(InstanceKey I, InstanceKey F) {
public Iterator<PointerKey> getPointerKeysForReflectedFieldRead(InstanceKey I, InstanceKey F) {
if (F instanceof ConstantKey) {
PointerKey ifk = getInstanceFieldPointerKeyForConstant(I, (ConstantKey) F);
if (ifk != null) {

View File

@ -19,6 +19,7 @@ import com.ibm.wala.classLoader.IClass;
import com.ibm.wala.classLoader.NewSiteReference;
import com.ibm.wala.classLoader.ProgramCounter;
import com.ibm.wala.ipa.callgraph.CGNode;
import com.ibm.wala.ipa.callgraph.CallGraph;
import com.ibm.wala.ipa.callgraph.ContextItem;
import com.ibm.wala.ipa.callgraph.propagation.InstanceKey;
import com.ibm.wala.ipa.callgraph.propagation.InstanceKeyFactory;
@ -27,6 +28,8 @@ import com.ibm.wala.ipa.callgraph.propagation.PropagationCallGraphBuilder;
import com.ibm.wala.types.TypeReference;
import com.ibm.wala.util.collections.CompoundIterator;
import com.ibm.wala.util.collections.EmptyIterator;
import com.ibm.wala.util.collections.Filter;
import com.ibm.wala.util.collections.FilterIterator;
import com.ibm.wala.util.collections.NonNullSingletonIterator;
import com.ibm.wala.util.collections.Pair;
import com.ibm.wala.util.intset.OrdinalSet;
@ -175,6 +178,16 @@ abstract public class ScopeMappingInstanceKeys implements InstanceKeyFactory {
public CGNode getCreator() {
return creator;
}
public Iterator<Pair<CGNode, NewSiteReference>> getCreationSites(CallGraph CG) {
return new FilterIterator<Pair<CGNode, NewSiteReference>>(
base.getCreationSites(CG),
new Filter<Pair<CGNode, NewSiteReference>>() {
public boolean accepts(Pair<CGNode, NewSiteReference> o) {
return o.fst.equals(creator);
}
});
}
}
public InstanceKey getInstanceKeyForAllocation(CGNode creatorNode, NewSiteReference allocationSite) {

View File

@ -10,11 +10,19 @@
*******************************************************************************/
package com.ibm.wala.ipa.callgraph.propagation;
import java.util.Iterator;
import com.ibm.wala.classLoader.IClass;
import com.ibm.wala.classLoader.IMethod;
import com.ibm.wala.classLoader.NewSiteReference;
import com.ibm.wala.ipa.callgraph.CGNode;
import com.ibm.wala.ipa.callgraph.CallGraph;
import com.ibm.wala.ipa.callgraph.Context;
import com.ibm.wala.util.collections.Filter;
import com.ibm.wala.util.collections.FilterIterator;
import com.ibm.wala.util.collections.MapIterator;
import com.ibm.wala.util.collections.Pair;
import com.ibm.wala.util.functions.Function;
/**
* An {@link InstanceKey} which represents a {@link NewSiteReference} in some {@link IMethod}. Note that this differs from
@ -81,4 +89,21 @@ public class AllocationSite implements InstanceKey {
return false;
return true;
}
public Iterator<Pair<CGNode, NewSiteReference>> getCreationSites(CallGraph CG) {
return new MapIterator<CGNode, Pair<CGNode, NewSiteReference>>(
new FilterIterator<CGNode>(
CG.getNodes(method.getReference()).iterator(),
new Filter<CGNode>() {
public boolean accepts(CGNode o) {
return o.getMethod().equals(method);
}
}
),
new Function<CGNode, Pair<CGNode, NewSiteReference>>() {
public Pair<CGNode, NewSiteReference> apply(CGNode object) {
return Pair.make(object, site);
}
});
}
}

View File

@ -10,9 +10,14 @@
*******************************************************************************/
package com.ibm.wala.ipa.callgraph.propagation;
import java.util.Iterator;
import com.ibm.wala.classLoader.IClass;
import com.ibm.wala.classLoader.NewSiteReference;
import com.ibm.wala.ipa.callgraph.CGNode;
import com.ibm.wala.ipa.callgraph.CallGraph;
import com.ibm.wala.util.collections.NonNullSingletonIterator;
import com.ibm.wala.util.collections.Pair;
/**
* An {@link InstanceKey} which represents a {@link NewSiteReference} in some {@link CGNode}.
@ -42,4 +47,9 @@ public abstract class AllocationSiteInNode extends AbstractTypeInNode {
public NewSiteReference getSite() {
return site;
}
public Iterator<Pair<CGNode, NewSiteReference>> getCreationSites(CallGraph CG) {
return new NonNullSingletonIterator<Pair<CGNode, NewSiteReference>>(Pair.make(getNode(), getSite()));
}
}

View File

@ -14,11 +14,20 @@ import java.util.Collection;
import java.util.Iterator;
import com.ibm.wala.classLoader.IClass;
import com.ibm.wala.classLoader.NewSiteReference;
import com.ibm.wala.ipa.callgraph.CGNode;
import com.ibm.wala.ipa.callgraph.CallGraph;
import com.ibm.wala.ipa.cha.IClassHierarchy;
import com.ibm.wala.ssa.IR;
import com.ibm.wala.ssa.SSAInstruction;
import com.ibm.wala.types.TypeReference;
import com.ibm.wala.util.collections.ComposedIterator;
import com.ibm.wala.util.collections.Filter;
import com.ibm.wala.util.collections.FilterIterator;
import com.ibm.wala.util.collections.MapIterator;
import com.ibm.wala.util.collections.Pair;
import com.ibm.wala.util.debug.Assertions;
import com.ibm.wala.util.functions.Function;
/**
* An instance key which represents a unique set for each concrete type
@ -92,4 +101,26 @@ public final class ConcreteTypeKey implements InstanceKey {
}
return result;
}
public Iterator<Pair<CGNode, NewSiteReference>> getCreationSites(CallGraph CG) {
return new ComposedIterator<CGNode, Pair<CGNode, NewSiteReference>>(CG.iterator()) {
@Override
public Iterator<? extends Pair<CGNode, NewSiteReference>> makeInner(final CGNode outer) {
return new MapIterator<NewSiteReference, Pair<CGNode, NewSiteReference>>(
new FilterIterator<NewSiteReference>(
outer.iterateNewSites(),
new Filter<NewSiteReference>() {
public boolean accepts(NewSiteReference o) {
return o.getDeclaredType().equals(type.getReference());
}
}
),
new Function<NewSiteReference, Pair<CGNode, NewSiteReference>>() {
public Pair<CGNode, NewSiteReference> apply(NewSiteReference object) {
return Pair.make(outer, object);
}
});
}
};
}
}

View File

@ -10,7 +10,14 @@
*******************************************************************************/
package com.ibm.wala.ipa.callgraph.propagation;
import java.util.Iterator;
import com.ibm.wala.classLoader.IClass;
import com.ibm.wala.classLoader.NewSiteReference;
import com.ibm.wala.ipa.callgraph.CGNode;
import com.ibm.wala.ipa.callgraph.CallGraph;
import com.ibm.wala.util.collections.EmptyIterator;
import com.ibm.wala.util.collections.Pair;
/**
* An instance key which represents a unique, constant object
@ -58,4 +65,8 @@ public final class ConstantKey<T> implements InstanceKey {
public T getValue() {
return value;
}
public Iterator<Pair<CGNode, NewSiteReference>> getCreationSites(CallGraph CG) {
return EmptyIterator.instance();
}
}

View File

@ -10,8 +10,14 @@
*******************************************************************************/
package com.ibm.wala.ipa.callgraph.propagation;
import java.util.Iterator;
import com.ibm.wala.classLoader.IClass;
import com.ibm.wala.classLoader.NewSiteReference;
import com.ibm.wala.ipa.callgraph.CGNode;
import com.ibm.wala.ipa.callgraph.CallGraph;
import com.ibm.wala.ipa.callgraph.ContextItem;
import com.ibm.wala.util.collections.Pair;
/**
* An InstanceKey serves as the representative for an equivalence class of
@ -32,5 +38,7 @@ public interface InstanceKey extends ContextItem {
*/
IClass getConcreteType();
Iterator<Pair<CGNode,NewSiteReference>> getCreationSites(CallGraph CG);
}

View File

@ -10,8 +10,17 @@
*******************************************************************************/
package com.ibm.wala.ipa.callgraph.propagation;
import java.util.Iterator;
import com.ibm.wala.classLoader.IClass;
import com.ibm.wala.classLoader.NewSiteReference;
import com.ibm.wala.ipa.callgraph.CGNode;
import com.ibm.wala.ipa.callgraph.CallGraph;
import com.ibm.wala.util.collections.Filter;
import com.ibm.wala.util.collections.FilterIterator;
import com.ibm.wala.util.collections.MapIterator;
import com.ibm.wala.util.collections.Pair;
import com.ibm.wala.util.functions.Function;
/**
* An {@link InstanceKey} which represents the set of all allocation sites
@ -44,4 +53,20 @@ public class SmushedAllocationSiteInNode extends AbstractTypeInNode {
public String toString() {
return "SMUSHED " + getNode() + " : " + getConcreteType();
}
public Iterator<Pair<CGNode, NewSiteReference>> getCreationSites(CallGraph CG) {
return new MapIterator<NewSiteReference,Pair<CGNode, NewSiteReference>>(
new FilterIterator<NewSiteReference>(
getNode().iterateNewSites(),
new Filter<NewSiteReference>() {
public boolean accepts(NewSiteReference o) {
return o.getDeclaredType().equals(getConcreteType().getReference());
}
}),
new Function<NewSiteReference,Pair<CGNode, NewSiteReference>>() {
public Pair<CGNode, NewSiteReference> apply(NewSiteReference object) {
return Pair.make(getNode(), object);
}
});
}
}

View File

@ -10,8 +10,15 @@
*******************************************************************************/
package com.ibm.wala.ipa.callgraph.propagation;
import java.util.Iterator;
import com.ibm.wala.classLoader.IClass;
import com.ibm.wala.classLoader.NewSiteReference;
import com.ibm.wala.ipa.callgraph.CGNode;
import com.ibm.wala.ipa.callgraph.CallGraph;
import com.ibm.wala.types.TypeReference;
import com.ibm.wala.util.collections.EmptyIterator;
import com.ibm.wala.util.collections.Pair;
/**
* An {@link InstanceKey} which represents the constant char[] contents
@ -65,4 +72,8 @@ public class StringConstantCharArray implements InstanceKey {
public String toString() {
return "StringConstantCharArray:" + constant;
}
public Iterator<Pair<CGNode, NewSiteReference>> getCreationSites(CallGraph CG) {
return EmptyIterator.instance();
}
}