Merge branch 'wala' into master

This commit is contained in:
Juergen Graf 2014-07-28 17:09:02 +02:00
commit 6f8aee80c6
155 changed files with 2944 additions and 22977 deletions

View File

@ -7,6 +7,9 @@
<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_TYPES">
<listEntry value="1"/>
</listAttribute>
<mapAttribute key="org.eclipse.debug.core.preferred_launchers">
<mapEntry key="[run]" value="org.eclipse.jdt.junit.launchconfig"/>
</mapAttribute>
<stringAttribute key="org.eclipse.debug.ui.ATTR_CAPTURE_IN_FILE" value="/tmp/console.txt"/>
<stringAttribute key="org.eclipse.jdt.junit.CONTAINER" value=""/>
<booleanAttribute key="org.eclipse.jdt.junit.KEEPRUNNING_ATTR" value="false"/>

View File

@ -207,7 +207,7 @@ public class PolyglotIdentityMapper implements IdentityMapper<Type, CodeInstance
}
public String anonLocalTypeToTypeID(ClassType ctype) {
CodeInstance procInstance= (CodeInstance) fLocalTypeMap.get(ctype);
CodeInstance procInstance= fLocalTypeMap.get(ctype);
String outerTypeID= typeToTypeID(ctype.outer());
String shortName= (ctype.isAnonymous()) ? PolyglotJava2CAstTranslator.anonTypeName(ctype) : ctype.fullName().name().toString();

View File

@ -1122,7 +1122,7 @@ public class PolyglotJava2CAstTranslator {
Node stmt = l.statement();
while (stmt instanceof Block) {
stmt = (Node) ((Block) stmt).statements().iterator().next();
stmt = ((Block) stmt).statements().iterator().next();
}
wc.getLabelMap().put(stmt, l.labelNode().id().toString());
@ -1176,7 +1176,7 @@ public class PolyglotJava2CAstTranslator {
Node breakTarget = makeBreakTarget(d);
Node continueTarget = makeContinueTarget(d);
String loopLabel = (String) wc.getLabelMap().get(d);
String loopLabel = wc.getLabelMap().get(d);
CAstNode continueNode = walkNodes(continueTarget, wc);
CAstNode breakNode = walkNodes(breakTarget, wc);
@ -1194,17 +1194,17 @@ public class PolyglotJava2CAstTranslator {
public CAstNode visit(For f, WalkContext wc) {
Node breakTarget = makeBreakTarget(f);
Node continueTarget = makeContinueTarget(f);
String loopLabel = (String) wc.getLabelMap().get(f);
String loopLabel = wc.getLabelMap().get(f);
WalkContext lc = new LoopContext(wc, loopLabel, breakTarget, continueTarget);
CAstNode[] inits = new CAstNode[f.inits().size()];
for (int i = 0; i < inits.length; i++) {
inits[i] = walkNodes((Node) f.inits().get(i), wc);
inits[i] = walkNodes(f.inits().get(i), wc);
}
CAstNode[] iters = new CAstNode[f.iters().size()];
for (int i = 0; i < iters.length; i++) {
iters[i] = walkNodes((Node) f.iters().get(i), wc);
iters[i] = walkNodes(f.iters().get(i), wc);
}
CAstNode initsBlock = makeNode(wc, fFactory, f, CAstNode.BLOCK_STMT, inits);
@ -1223,7 +1223,7 @@ public class PolyglotJava2CAstTranslator {
Node breakTarget = makeBreakTarget(w);
Node continueTarget = makeContinueTarget(w);
String loopLabel = (String) wc.getLabelMap().get(w);
String loopLabel = wc.getLabelMap().get(w);
LoopContext lc = new LoopContext(wc, loopLabel, breakTarget, continueTarget);
/*
@ -1239,7 +1239,7 @@ public class PolyglotJava2CAstTranslator {
fNodeFactory.Id(s.position(), "switchBreakLabel" + s.position().toString().replace('.', '_')),
fNodeFactory.Empty(s.position()));
CAstNode breakAst = walkNodes(breakLabel, wc);
String loopLabel = (String) wc.getLabelMap().get(s);
String loopLabel = wc.getLabelMap().get(s);
WalkContext child = new BreakContext(wc, loopLabel, breakLabel);
Expr cond = s.expr();
List cases = s.elements();
@ -1455,7 +1455,7 @@ public class PolyglotJava2CAstTranslator {
}
@Override
public Iterator getScopedEntities(CAstNode construct) {
public Iterator<CAstEntity> getScopedEntities(CAstNode construct) {
Assertions.UNREACHABLE("CompilationUnitEntity asked for AST-related entities, but it has no AST.");
return null;
}
@ -1494,8 +1494,8 @@ public class PolyglotJava2CAstTranslator {
}
@Override
public Collection getQualifiers() {
return Collections.EMPTY_LIST;
public Collection<CAstQualifier> getQualifiers() {
return Collections.emptyList();
}
@Override
@ -1595,7 +1595,7 @@ public class PolyglotJava2CAstTranslator {
}
@Override
public Iterator getScopedEntities(CAstNode construct) {
public Iterator<CAstEntity> getScopedEntities(CAstNode construct) {
if (fEntities.containsKey(construct)) {
return (fEntities.get(construct)).iterator();
} else {
@ -1680,7 +1680,7 @@ public class PolyglotJava2CAstTranslator {
}
@Override
public Iterator getScopedEntities(CAstNode construct) {
public Iterator<CAstEntity> getScopedEntities(CAstNode construct) {
Assertions.UNREACHABLE("Non-AST-bearing entity (ClassEntity) asked for scoped entities related to a given AST node");
return null;
}
@ -1719,7 +1719,7 @@ public class PolyglotJava2CAstTranslator {
}
@Override
public Collection getQualifiers() {
public Collection<CAstQualifier> getQualifiers() {
if (fCT == fTypeSystem.Object()) { // pretend the root of the hierarchy is always a class
return mapFlagsToQualifiers(fCT.flags().clear(Flags.INTERFACE));
}
@ -1858,7 +1858,7 @@ public class PolyglotJava2CAstTranslator {
}
@Override
public Collection getQualifiers() {
public Collection<CAstQualifier> getQualifiers() {
return mapFlagsToQualifiers(getFlags());
}
@ -1882,7 +1882,7 @@ public class PolyglotJava2CAstTranslator {
fParameterTypes = new ArrayList<CAstType>(formalTypes.size());
for (Iterator iter = formalTypes.iterator(); iter.hasNext();) {
fParameterTypes.add(fMc.getTypeDictionary().getCAstTypeFor((Type) iter.next()));
fParameterTypes.add(fMc.getTypeDictionary().getCAstTypeFor(iter.next()));
}
}
return fParameterTypes;
@ -1980,7 +1980,7 @@ public class PolyglotJava2CAstTranslator {
}
@Override
public Iterator getScopedEntities(CAstNode construct) {
public Iterator<CAstEntity> getScopedEntities(CAstNode construct) {
return EmptyIterator.instance();
}
@ -2028,7 +2028,7 @@ public class PolyglotJava2CAstTranslator {
}
@Override
public Collection getQualifiers() {
public Collection<CAstQualifier> getQualifiers() {
return mapFlagsToQualifiers(fFI.flags());
}
@ -2641,9 +2641,9 @@ public class PolyglotJava2CAstTranslator {
* Maps front-end-specific representations into WALA references of the appropriate kind.
* @author rfuhrer
*
* @param <T> The front-end-specific representation of a type (e.g., for Polyglot, a Type)
* @param <M> The front-end-specific representation of a procedure/method (e.g., for Polyglot, a CodeInstance)
* @param <F> The front-end-specific representation of a field (e.g., for Polyglot, a FieldInstance)
* @param <TypeRep> The front-end-specific representation of a type (e.g., for Polyglot, a Type)
* @param <MethodRep> The front-end-specific representation of a procedure/method (e.g., for Polyglot, a CodeInstance)
* @param <FieldRep> The front-end-specific representation of a field (e.g., for Polyglot, a FieldInstance)
*/
public interface IdentityMapper<TypeRep, MethodRep, FieldRep> {
MemberReference getMethodRef(MethodRep method);
@ -2783,7 +2783,6 @@ public class PolyglotJava2CAstTranslator {
return ct.fullName() + "$" + pos.line() + "$" + pos.column();
}
@SuppressWarnings("unchecked")
protected CAstEntity walkEntity(Node rootNode, final WalkContext context) {
if (rootNode instanceof SourceFile) {
SourceFile file = (SourceFile) rootNode;
@ -2806,7 +2805,7 @@ public class PolyglotJava2CAstTranslator {
} else if (rootNode instanceof New) {
final New n = (New) rootNode;
final List<CAstEntity> memberEntities = new ArrayList<CAstEntity>();
ClassType anonType = (ClassType) n.anonType().asType();
ClassType anonType = n.anonType().asType();
String anonTypeName = anonTypeName(anonType);
final ClassContext classContext = new ClassContext(anonType, memberEntities, context);
@ -2865,7 +2864,7 @@ public class PolyglotJava2CAstTranslator {
if (body.statements().size() <= 0)
return false;
Stmt maybeSuper = (Stmt) body.statements().get(0);
Stmt maybeSuper = body.statements().get(0);
return isSpecialCallStmt(maybeSuper, kind);
}

View File

@ -135,7 +135,7 @@ public class AstJavaTypeInference extends AstTypeInference {
for (int i = 0; i < rhs.length; i++) {
if (rhs[i] != null) {
TypeVariable r = (TypeVariable) rhs[i];
TypeVariable r = rhs[i];
TypeAbstraction ta = r.getType();
if (ta instanceof PointType) {
if (ta.getType().equals(getStringClass())) {
@ -154,7 +154,7 @@ public class AstJavaTypeInference extends AstTypeInference {
if (meet == null) {
return super.evaluate(lhs, rhs);
} else {
TypeVariable L = (TypeVariable) lhs;
TypeVariable L = lhs;
TypeAbstraction lhsType = L.getType();
if (lhsType.equals(meet)) {

View File

@ -18,7 +18,6 @@ import com.ibm.wala.cast.tree.CAstControlFlowMap;
import com.ibm.wala.cast.tree.CAstEntity;
import com.ibm.wala.cast.tree.CAstNode;
import com.ibm.wala.cast.tree.CAstSourcePositionMap;
import com.ibm.wala.cast.tree.CAstType;
import com.ibm.wala.cast.tree.impl.CAstOperator;
import com.ibm.wala.cast.tree.rewrite.CAstRewriter;
import com.ibm.wala.classLoader.CallSiteReference;

View File

@ -174,7 +174,7 @@ public class AstJavaSSAPropagationCallGraphBuilder extends AstSSAPropagationCall
system.newSideEffect(new UnaryOperator<PointsToSetVariable>() {
@Override
public byte evaluate(PointsToSetVariable lhs, PointsToSetVariable rhs) {
IntSetVariable tv = (IntSetVariable) rhs;
IntSetVariable tv = rhs;
if (tv.getValue() != null) {
tv.getValue().foreach(new IntSetAction() {
@Override

View File

@ -31,11 +31,9 @@ public class AstJavaZeroOneContainerCFABuilder extends AstJavaCFABuilder {
/**
* @param cha governing class hierarchy
* @param warnings object to track analysis warnings
* @param options call graph construction options
* @param appContextSelector application-specific logic to choose contexts
* @param appContextInterpreter application-specific logic to interpret a method in context
* @param reflect reflection specification
*/
public AstJavaZeroOneContainerCFABuilder(IClassHierarchy cha, AnalysisOptions options, AnalysisCache cache,
ContextSelector appContextSelector, SSAContextInterpreter appContextInterpreter) {

View File

@ -21,7 +21,7 @@ import com.ibm.wala.ipa.callgraph.propagation.cfa.ZeroXInstanceKeys;
import com.ibm.wala.ipa.cha.IClassHierarchy;
/**
* 0-1-CFA Call graph builder, optimized to not disambiguate instances of "uninteresting" types
* 0-1-CFA Call graph builder, optimized to not disambiguate instances of "uninteresting" types.
*/
public class AstJavaZeroXCFABuilder extends AstJavaCFABuilder {
@ -47,7 +47,6 @@ public class AstJavaZeroXCFABuilder extends AstJavaCFABuilder {
* @param cl classloader that can find DOMO resources
* @param scope representation of the analysis scope
* @param xmlFiles set of Strings that are names of XML files holding bypass logic specifications.
* @param dmd deployment descriptor abstraction
* @return a 0-1-Opt-CFA Call Graph Builder.
*/
public static AstJavaCFABuilder make(AnalysisOptions options, AnalysisCache cache, IClassHierarchy cha, ClassLoader cl,

View File

@ -57,7 +57,7 @@ public class JavaScopeMappingInstanceKeys extends ScopeMappingInstanceKeys {
if (AstTranslator.DEBUG_LEXICAL)
System.err.println((base + " has parents: " + result));
return (LexicalParent[]) result.toArray(new LexicalParent[result.size()]);
return result.toArray(new LexicalParent[result.size()]);
}
}

View File

@ -12,6 +12,7 @@ package com.ibm.wala.cast.java.ipa.modref;
import java.util.Collection;
import com.ibm.wala.cast.ipa.callgraph.AstHeapModel;
import com.ibm.wala.cast.ipa.modref.AstModRef;
import com.ibm.wala.cast.java.ssa.AstJavaInstructionVisitor;
import com.ibm.wala.cast.java.ssa.AstJavaInvokeInstruction;
@ -30,7 +31,7 @@ public class AstJavaModRef extends AstModRef {
{
protected AstJavaRefVisitor(CGNode n, Collection<PointerKey> result, PointerAnalysis<InstanceKey> pa, ExtendedHeapModel h) {
super(n, result, pa, h);
super(n, result, pa, (AstHeapModel)h);
}
@Override
@ -56,7 +57,7 @@ public class AstJavaModRef extends AstModRef {
{
protected AstJavaModVisitor(CGNode n, Collection<PointerKey> result, ExtendedHeapModel h, PointerAnalysis<InstanceKey> pa) {
super(n, result, h, pa);
super(n, result, (AstHeapModel)h, pa);
}

View File

@ -49,11 +49,11 @@ public class JavaPrimitiveTypeMap {
}
public static String getShortName(String longName) {
return ((JavaPrimitiveType) primNameMap.get(longName)).getName();
return primNameMap.get(longName).getName();
}
public static JavaPrimitiveType lookupType(String longName) {
return (JavaPrimitiveType) primNameMap.get(longName);
return primNameMap.get(longName);
}
public static final JavaPrimitiveType VoidType = new JavaPrimitiveType("void", "V");

View File

@ -44,6 +44,7 @@ public abstract class AbstractFieldBasedTest extends TestJSCallGraphShape {
ProgressMaster monitor = ProgressMaster.make(new NullProgressMonitor(), 30000, true);
try {
cg = util.buildCG(url, builderType, monitor);
System.err.println(cg);
verifyGraphAssertions(cg, assertions);
} catch(AssertionFailedError afe) {
throw new AssertionFailedError(builderType + ": " + afe.getMessage());
@ -52,6 +53,17 @@ public abstract class AbstractFieldBasedTest extends TestJSCallGraphShape {
return cg;
}
/**
* for long-running tests that tend to time out on Travis
*/
protected JSCallGraph runTestExceptOnTravis(URL url, Object[][] assertions, BuilderType... builderTypes) throws IOException, WalaException, Error, CancelException {
if (System.getenv("TRAVIS") == null) {
return runTest(url, assertions, builderTypes);
} else {
return null;
}
}
@SuppressWarnings("unused")
private void dumpCG(JSCallGraph cg) {
CallGraph2JSON.IGNORE_HARNESS = false;

View File

@ -7,7 +7,6 @@ import org.junit.Test;
import com.ibm.wala.cast.ir.translator.TranslatorToCAst.Error;
import com.ibm.wala.cast.js.rhino.callgraph.fieldbased.test.CGUtil.BuilderType;
import com.ibm.wala.ipa.callgraph.CallGraphBuilderCancelException;
import com.ibm.wala.util.CancelException;
import com.ibm.wala.util.WalaException;
@ -15,52 +14,56 @@ public class FieldBasedCGGamesTest extends AbstractFieldBasedTest {
@Test
public void testBunnyHunt() throws IOException, WalaException, Error, CancelException {
System.err.println(runTest(new URL("http://www.themaninblue.com/experiment/BunnyHunt/"), new Object[][]{}, BuilderType.OPTIMISTIC_WORKLIST));
runTestExceptOnTravis(new URL("http://www.themaninblue.com/experiment/BunnyHunt/"), new Object[][]{}, BuilderType.OPTIMISTIC_WORKLIST);
}
@Test
public void testBomberman() throws IOException, WalaException, Error, CancelException {
System.err.println(runTest(new URL("http://www.e-forum.ro/bomberman/dynagame.html"), new Object[][]{}, BuilderType.OPTIMISTIC_WORKLIST));
runTestExceptOnTravis(new URL("http://www.e-forum.ro/bomberman/dynagame.html"), new Object[][]{}, BuilderType.OPTIMISTIC_WORKLIST);
}
@Test
public void testBeslimed() throws IOException, WalaException, Error, CancelException {
System.err.println(runTest(new URL("http://www.markus-inger.de/test/game.php"), new Object[][]{}, BuilderType.OPTIMISTIC_WORKLIST));
runTestExceptOnTravis(new URL("http://www.markus-inger.de/test/game.php"), new Object[][]{}, BuilderType.OPTIMISTIC_WORKLIST);
}
@Test
public void testDiggAttack() throws IOException, WalaException, Error, CancelException {
System.err.println(runTest(new URL("http://www.pixastic.com/labs/digg_attack/"), new Object[][]{}, BuilderType.OPTIMISTIC_WORKLIST));
runTestExceptOnTravis(new URL("http://www.pixastic.com/labs/digg_attack/"), new Object[][]{}, BuilderType.OPTIMISTIC_WORKLIST);
}
@Test
public void testRiverRaider() throws IOException, WalaException, Error, CancelException {
System.err.println(runTest(new URL("http://playstar.mobi/games/riverraider/index.html?playerId=&gameId=8&highscore=102425"), new Object[][]{}, BuilderType.OPTIMISTIC_WORKLIST));
runTestExceptOnTravis(new URL("http://playstar.mobi/games/riverraider/index.html?playerId=&gameId=8&highscore=102425"), new Object[][]{}, BuilderType.OPTIMISTIC_WORKLIST);
}
@Test
public void testSolitaire() throws IOException, WalaException, Error, CancelException {
System.err.println(runTest(new URL("http://www.inmensia.com/files/solitaire1.0.html"), new Object[][]{}, BuilderType.OPTIMISTIC_WORKLIST));
runTestExceptOnTravis(new URL("http://www.inmensia.com/files/solitaire1.0.html"), new Object[][]{}, BuilderType.OPTIMISTIC_WORKLIST);
}
@Test(expected = CancelException.class)
public void testWorldOfSolitaire() throws IOException, WalaException, Error, CancelException {
System.err.println(runTest(new URL("http://worldofsolitaire.com/"), new Object[][]{}, BuilderType.OPTIMISTIC_WORKLIST));
runTestExceptOnTravis(new URL("http://worldofsolitaire.com/"), new Object[][]{}, BuilderType.OPTIMISTIC_WORKLIST);
if (System.getenv("TRAVIS") != null) {
// fake it
throw new CancelException(null);
}
}
@Test
public void testMinesweeper() throws IOException, WalaException, Error, CancelException {
System.err.println(runTest(new URL("http://www.inmensia.com/files/minesweeper1.0.html"), new Object[][]{}, BuilderType.OPTIMISTIC_WORKLIST));
runTestExceptOnTravis(new URL("http://www.inmensia.com/files/minesweeper1.0.html"), new Object[][]{}, BuilderType.OPTIMISTIC_WORKLIST);
}
@Test
public void testProtoRPG() throws IOException, WalaException, Error, CancelException {
System.err.println(runTest(new URL("http://www.protorpg.com/games/protorpg/?game=prologue"), new Object[][]{}, BuilderType.OPTIMISTIC_WORKLIST));
runTestExceptOnTravis(new URL("http://www.protorpg.com/games/protorpg/?game=prologue"), new Object[][]{}, BuilderType.OPTIMISTIC_WORKLIST);
}
@Test
public void testBattleship() throws IOException, WalaException, Error, CancelException {
System.err.println(runTest(new URL("http://www.sinkmyship.com/battleship/single.html"), new Object[][]{}, BuilderType.OPTIMISTIC_WORKLIST));
runTestExceptOnTravis(new URL("http://www.sinkmyship.com/battleship/single.html"), new Object[][]{}, BuilderType.OPTIMISTIC_WORKLIST);
}

View File

@ -0,0 +1,58 @@
package com.ibm.wala.cast.js.rhino.callgraph.fieldbased.test;
import java.io.IOException;
import junit.framework.AssertionFailedError;
import org.junit.Test;
import com.ibm.wala.cast.ir.translator.TranslatorToCAst.Error;
import com.ibm.wala.cast.js.html.JSSourceExtractor;
import com.ibm.wala.cast.js.rhino.callgraph.fieldbased.test.CGUtil.BuilderType;
import com.ibm.wala.cast.js.test.TestSimplePageCallGraphShape;
import com.ibm.wala.util.CancelException;
import com.ibm.wala.util.WalaException;
public class FieldBasedComparisonTest extends AbstractFieldBasedTest {
private void test(String file, Object[][] assertions, BuilderType builderType) throws IOException, WalaException, Error, CancelException {
boolean save = JSSourceExtractor.USE_TEMP_NAME;
try {
JSSourceExtractor.USE_TEMP_NAME = false;
runTest(file, assertions, builderType);
} finally {
JSSourceExtractor.USE_TEMP_NAME = save;
}
}
@Test(expected = AssertionFailedError.class)
public void testSkeletonPessimistic() throws IOException, WalaException, Error, CancelException {
test("pages/skeleton.html", TestSimplePageCallGraphShape.assertionsForSkeleton, BuilderType.PESSIMISTIC);
}
@Test
public void testSkeletonOptimistic() throws IOException, WalaException, Error, CancelException {
test("pages/skeleton.html", TestSimplePageCallGraphShape.assertionsForSkeleton, BuilderType.OPTIMISTIC);
}
@Test
public void testSkeletonWorklist() throws IOException, WalaException, Error, CancelException {
test("pages/skeleton.html", TestSimplePageCallGraphShape.assertionsForSkeleton, BuilderType.OPTIMISTIC_WORKLIST);
}
@Test(expected = AssertionFailedError.class)
public void testSkeleton2Pessimistic() throws IOException, WalaException, Error, CancelException {
test("pages/skeleton2.html", TestSimplePageCallGraphShape.assertionsForSkeleton2, BuilderType.PESSIMISTIC);
}
@Test
public void testSkeleton2Optimistic() throws IOException, WalaException, Error, CancelException {
test("pages/skeleton2.html", TestSimplePageCallGraphShape.assertionsForSkeleton2, BuilderType.OPTIMISTIC);
}
@Test
public void testSkeleton2Worklist() throws IOException, WalaException, Error, CancelException {
test("pages/skeleton2.html", TestSimplePageCallGraphShape.assertionsForSkeleton2, BuilderType.OPTIMISTIC_WORKLIST);
}
}

View File

@ -23,14 +23,24 @@ import com.ibm.wala.util.WalaException;
public class TestFieldBasedCG extends AbstractFieldBasedTest {
private static final Object[][] assertionsForSimpleJS = new Object[][] {
new Object[] { ROOT, new String[] { "suffix:simple.js" } },
new Object[] { "suffix:simple.js", new String[] { "suffix:foo", "suffix:bar", "suffix:A", "suffix:Function" } },
new Object[] { "suffix:simple.js", new String[] { "suffix:foo", "suffix:bar", "suffix:A" } },
new Object[] { "suffix:foo", new String[] { "suffix:bar" } },
new Object[] { "suffix:aluis", new String[] { "suffix:aluis" } }
};
@Test
public void testSimpleJS() throws IOException, WalaException, Error, CancelException {
runTest("tests/fieldbased/simple.js", assertionsForSimpleJS, BuilderType.PESSIMISTIC, BuilderType.OPTIMISTIC, BuilderType.OPTIMISTIC_WORKLIST);
public void testSimpleJSPessimistic() throws IOException, WalaException, Error, CancelException {
runTest("tests/fieldbased/simple.js", assertionsForSimpleJS, BuilderType.PESSIMISTIC);
}
@Test
public void testSimpleJSOptimistic() throws IOException, WalaException, Error, CancelException {
runTest("tests/fieldbased/simple.js", assertionsForSimpleJS, BuilderType.OPTIMISTIC);
}
@Test
public void testSimpleJSWorklist() throws IOException, WalaException, Error, CancelException {
runTest("tests/fieldbased/simple.js", assertionsForSimpleJS, BuilderType.OPTIMISTIC_WORKLIST);
}
private static final Object[][] assertionsForOneShot = new Object[][] {
@ -40,11 +50,21 @@ public class TestFieldBasedCG extends AbstractFieldBasedTest {
};
@Test
public void testOneshot() throws IOException, WalaException, Error, CancelException {
runTest("tests/fieldbased/oneshot.js", assertionsForOneShot, BuilderType.PESSIMISTIC, BuilderType.OPTIMISTIC, BuilderType.OPTIMISTIC_WORKLIST);
public void testOneshotPessimistic() throws IOException, WalaException, Error, CancelException {
runTest("tests/fieldbased/oneshot.js", assertionsForOneShot, BuilderType.PESSIMISTIC);
}
private static final Object[][] assertionsForCallbacks = new Object[][] {
@Test
public void testOneshotOptimistic() throws IOException, WalaException, Error, CancelException {
runTest("tests/fieldbased/oneshot.js", assertionsForOneShot, BuilderType.OPTIMISTIC);
}
@Test
public void testOneshotWorklist() throws IOException, WalaException, Error, CancelException {
runTest("tests/fieldbased/oneshot.js", assertionsForOneShot, BuilderType.OPTIMISTIC_WORKLIST);
}
private static final Object[][] assertionsForCallbacks = new Object[][] {
new Object[] { ROOT, new String[] { "suffix:callbacks.js" } },
new Object[] { "suffix:callbacks.js", new String[] { "suffix:f" } },
new Object[] { "suffix:f", new String[] { "suffix:k", "suffix:n" } },
@ -52,49 +72,79 @@ public class TestFieldBasedCG extends AbstractFieldBasedTest {
};
@Test
public void testCallbacks() throws IOException, WalaException, Error, CancelException {
runTest("tests/fieldbased/callbacks.js", assertionsForCallbacks, BuilderType.OPTIMISTIC, BuilderType.OPTIMISTIC_WORKLIST);
public void testCallbacksOptimistic() throws IOException, WalaException, Error, CancelException {
runTest("tests/fieldbased/callbacks.js", assertionsForCallbacks, BuilderType.OPTIMISTIC_WORKLIST);
}
private static final Object[][] assertionsForLexical = new Object[][] {
@Test
public void testCallbacksWorklist() throws IOException, WalaException, Error, CancelException {
runTest("tests/fieldbased/callbacks.js", assertionsForCallbacks, BuilderType.OPTIMISTIC_WORKLIST);
}
private static final Object[][] assertionsForLexical = new Object[][] {
new Object[] { "suffix:h", new String[] { "suffix:g" } }
};
@Test
public void testLexical() throws IOException, WalaException, Error, CancelException {
runTest("tests/fieldbased/lexical.js", assertionsForLexical, BuilderType.PESSIMISTIC, BuilderType.OPTIMISTIC, BuilderType.OPTIMISTIC_WORKLIST);
public void testLexicalPessimistic() throws IOException, WalaException, Error, CancelException {
runTest("tests/fieldbased/lexical.js", assertionsForLexical, BuilderType.PESSIMISTIC);
}
private static final Object[][] assertionsForReflectiveCall = new Object[][] {
@Test
public void testLexicalOptimistic() throws IOException, WalaException, Error, CancelException {
runTest("tests/fieldbased/lexical.js", assertionsForLexical, BuilderType.OPTIMISTIC);
}
@Test
public void testLexicalWorklist() throws IOException, WalaException, Error, CancelException {
runTest("tests/fieldbased/lexical.js", assertionsForLexical, BuilderType.OPTIMISTIC_WORKLIST);
}
private static final Object[][] assertionsForReflectiveCall = new Object[][] {
new Object[] { "suffix:h", new String[] { "suffix:Function_prototype_call" } },
new Object[] { "suffix:f", new String[] { "suffix:k" } }
};
@Test
public void testReflectiveCall() throws IOException, WalaException, Error, CancelException {
runTest("tests/fieldbased/reflective_calls.js", assertionsForReflectiveCall, BuilderType.OPTIMISTIC, BuilderType.OPTIMISTIC_WORKLIST);
public void testReflectiveCallOptimistic() throws IOException, WalaException, Error, CancelException {
runTest("tests/fieldbased/reflective_calls.js", assertionsForReflectiveCall, BuilderType.OPTIMISTIC);
}
private static final Object[][] assertionsForNew = new Object[][] {
@Test
public void testReflectiveCallWorklist() throws IOException, WalaException, Error, CancelException {
runTest("tests/fieldbased/reflective_calls.js", assertionsForReflectiveCall, BuilderType.OPTIMISTIC_WORKLIST);
}
private static final Object[][] assertionsForNew = new Object[][] {
new Object[] { "suffix:new.js", new String[] { "suffix:g", "suffix:f" } },
new Object[] { "suffix:g", new String[] { "!suffix:k" } }
};
@Test
public void testNew() throws IOException, WalaException, Error, CancelException {
runTest("tests/fieldbased/new.js", assertionsForNew, BuilderType.OPTIMISTIC, BuilderType.OPTIMISTIC_WORKLIST);
public void testNewOptimistic() throws IOException, WalaException, Error, CancelException {
runTest("tests/fieldbased/new.js", assertionsForNew, BuilderType.OPTIMISTIC);
}
@Test
public void testNewWorklist() throws IOException, WalaException, Error, CancelException {
runTest("tests/fieldbased/new.js", assertionsForNew, BuilderType.OPTIMISTIC_WORKLIST);
}
private static final Object[][] assertionsForCallbacks2 = new Object[][] {
new Object[] { "suffix:callbacks2.js", new String[] { "suffix:g" } },
new Object[] { "suffix:g", new String[] { "suffix:k", "!suffix:l" } }
};
@Test
public void testCallbacks2() throws IOException, WalaException, Error, CancelException {
runTest("tests/fieldbased/callbacks2.js", assertionsForCallbacks2, BuilderType.OPTIMISTIC, BuilderType.OPTIMISTIC_WORKLIST);
public void testCallbacks2Optimistic() throws IOException, WalaException, Error, CancelException {
runTest("tests/fieldbased/callbacks2.js", assertionsForCallbacks2, BuilderType.OPTIMISTIC);
}
@Test
public void testCallbacks2Worklist() throws IOException, WalaException, Error, CancelException {
runTest("tests/fieldbased/callbacks2.js", assertionsForCallbacks2, BuilderType.OPTIMISTIC_WORKLIST);
}
// @Test
public void testBug2979() throws IOException, WalaException, Error, CancelException {
System.err.println(runTest("pages/2979.html", new Object[][]{}, BuilderType.PESSIMISTIC, BuilderType.OPTIMISTIC, BuilderType.OPTIMISTIC_WORKLIST));

View File

@ -0,0 +1,19 @@
package com.ibm.wala.cast.js.test;
import org.junit.Before;
import com.ibm.wala.cast.js.translator.CAstRhinoTranslatorFactory;
public class TestJavaScriptSlicerRhino extends TestJavaScriptSlicer {
public static void main(String[] args) {
justThisTest(TestJavaScriptSlicerRhino.class);
}
@Override
@Before
public void setUp() {
com.ibm.wala.cast.js.ipa.callgraph.JSCallGraphUtil.setTranslatorFactory(new CAstRhinoTranslatorFactory());
}
}

View File

@ -106,6 +106,9 @@ import com.ibm.wala.cast.tree.CAstSourcePositionMap.Position;
import com.ibm.wala.cast.tree.CAstType;
import com.ibm.wala.cast.tree.impl.CAstOperator;
import com.ibm.wala.cast.tree.impl.CAstSymbolImpl;
import com.ibm.wala.cast.tree.visit.CAstVisitor;
import com.ibm.wala.cast.tree.visit.CAstVisitor.Context;
import com.ibm.wala.cast.util.CAstPattern;
import com.ibm.wala.classLoader.SourceModule;
import com.ibm.wala.util.collections.EmptyIterator;
import com.ibm.wala.util.collections.HashMapFactory;
@ -511,8 +514,11 @@ public class RhinoToAstTranslator {
// new first statement will be a block declaring all names.
CAstNode[] newStmts = new CAstNode[stmts.length + 1];
newStmts[0] = Ast.makeNode(CAstNode.BLOCK_STMT, child.getNameDecls().toArray(new CAstNode[child.getNameDecls().size()]));
if (child.getNameDecls().size() == 1) {
newStmts[0] = child.getNameDecls().iterator().next();
} else {
newStmts[0] = Ast.makeNode(CAstNode.BLOCK_STMT, child.getNameDecls().toArray(new CAstNode[child.getNameDecls().size()]));
}
System.arraycopy(stmts, 0, newStmts, 1, stmts.length);
stmts = newStmts;
@ -658,7 +664,9 @@ public class RhinoToAstTranslator {
}
}
return Ast.makeNode(CAstNode.OBJECT_LITERAL, eltNodes.toArray(new CAstNode[eltNodes.size()]));
CAstNode lit = Ast.makeNode(CAstNode.OBJECT_LITERAL, eltNodes.toArray(new CAstNode[eltNodes.size()]));
arg.cfg().map(node, lit);
return lit;
}
@Override
@ -781,9 +789,12 @@ public class RhinoToAstTranslator {
result = get = Ast.makeNode(CAstNode.OBJECT_REF, obj, elt);
}
if (get != null && context.getCatchTarget() != null) {
if (get != null) {
context.cfg().map(get, get);
context.cfg().add(get, context.getCatchTarget(), JavaScriptTypes.TypeError);
context.cfg().add(
get,
context.getCatchTarget() != null? context.getCatchTarget(): CAstControlFlowMap.EXCEPTION_TO_EXIT,
JavaScriptTypes.TypeError);
}
return result;
@ -955,6 +966,19 @@ public class RhinoToAstTranslator {
}
}
private String getParentName(AstNode fn) {
for(int i = 5; fn != null && i > 0; i--, fn = fn.getParent()) {
if (fn instanceof ObjectProperty) {
ObjectProperty prop = (ObjectProperty) fn;
AstNode label = prop.getLeft();
if (label instanceof Name) {
return (((Name)label).getString());
}
}
}
return null;
}
@Override
public CAstNode visitFunctionNode(FunctionNode fn, WalkContext context) {
WalkContext child = new FunctionContext(context, fn);
@ -965,6 +989,10 @@ public class RhinoToAstTranslator {
Name x = fn.getFunctionName();
if (x == null || x.getIdentifier() == null || "".equals(x.getIdentifier())) {
name = scriptName + "@" + fn.getAbsolutePosition();
String label = getParentName(fn);
if (label != null) {
name = name + ":" + label;
}
} else {
name = fn.getFunctionName().getIdentifier();
}
@ -1155,7 +1183,10 @@ public class RhinoToAstTranslator {
visit(label, context);
args[i++] = visit(prop, context);
}
return Ast.makeNode(CAstNode.OBJECT_LITERAL, args);
CAstNode lit = Ast.makeNode(CAstNode.OBJECT_LITERAL, args);
context.cfg().map(n, lit);
return lit;
}
@Override
@ -1368,14 +1399,37 @@ public class RhinoToAstTranslator {
if (init.getInitializer() == null) {
children[i++] = Ast.makeNode(CAstNode.EMPTY);
} else {
CAstNode initCode = visit(init, arg);
CAstPattern nameVarPattern = CAstPattern.parse("VAR(\"" + init.getTarget().getString() + "\")");
if (! nameVarPattern.new Matcher() {
@Override
protected boolean enterEntity(CAstEntity n, Context context, CAstVisitor<Context> visitor) {
return true;
}
@Override
protected boolean doVisit(CAstNode n, Context context, CAstVisitor<Context> visitor) {
return true;
}
}.findAll(null, initCode).isEmpty()) {
initCode =
Ast.makeNode(CAstNode.SPECIAL_PARENT_SCOPE,
Ast.makeConstant(init.getTarget().getString()),
initCode);
}
children[i++] =
Ast.makeNode(CAstNode.ASSIGN,
Ast.makeNode(CAstNode.VAR, Ast.makeConstant(init.getTarget().getString())),
visit(init, arg));
Ast.makeNode(CAstNode.ASSIGN, readName(arg, null, init.getTarget().getString()),initCode);
}
}
return Ast.makeNode(CAstNode.BLOCK_STMT, children);
if (i == 1) {
return children[0];
} else {
return Ast.makeNode(CAstNode.BLOCK_STMT, children);
}
}
@Override

View File

@ -0,0 +1,26 @@
<HTML>
<TITLE>Tests of random constructs</TITLE>
Hi
<SCRIPT>
$ = function dollar(x) {
if ((typeof x) === "function") {
x();
} else {
document.write(x);
}
};
$(function bad_guy(){
try { $(location.hash) } catch(e) {}
});
</SCRIPT>
<BR>
Welcome to our system
</HTML>

View File

@ -0,0 +1,33 @@
<HTML>
<TITLE>Tests of random constructs</TITLE>
Hi
<SCRIPT>
var x = function dollar(selector) {
return new x.fn.init(selector);
}
x.fn = { };
x.fn.init = function dollar_init(x) {
if ((typeof x) === "function") {
x();
} else {
document.write(x);
}
};
window.$ = x;
$(function bad_guy(){
try { $(location.hash) } catch(e) {}
});
</SCRIPT>
<BR>
Welcome to our system
</HTML>

View File

@ -0,0 +1,55 @@
<HTML>
<TITLE>Tests of random constructs</TITLE>
Hi
<SCRIPT>
var x = function dollar(selector) {
return new x.fn.init(selector);
}
x.fn = { };
x.fn.init = function dollar_init(selector) {
var quickExpr = /^(?:[^<]*(<[\w\W]+>)[^>]*$|#([\w\-]*)$)/;
var rsingleTag = /^<(\w+)\s*\/?>(?:<\/\1>)?$/;
if ((typeof selector) === "function") {
selector();
} else if ((typeof selector) === "string") {
var match;
if ( selector.charAt(0) === "<" &&
selector.charAt( selector.length - 1 ) === ">" &&
selector.length >= 3 )
{
match = [ null, selector, null ];
} else {
match = quickExpr.exec( selector );
}
if ( match && (match[1] || !context) ) {
if ( match[1] ) {
ret = rsingleTag.exec( selector );
if ( ret ) {
document.createElement( "xx" ).innerHTML = ret[1];
}
}
}
}
};
window.$ = x;
$(function bad_guy(){
try { $(location.hash) } catch(e) {}
});
</SCRIPT>
<BR>
Welcome to our system
</HTML>

View File

@ -7,3 +7,5 @@ function h() {
}
function k() {}
h();

View File

@ -1,4 +1,10 @@
function f() {
lbl:
break lbl;
function dead_code() {
}
function f() {
lbl: {
break lbl;
dead_code();
}
}

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

@ -0,0 +1,15 @@
var f = {
m: function bad(x) { return x; }
};
g = {
n: function global_bad(x) { return x; }
};
function test(y) {
var f = f ? f : { };
var g = g ? g : { };
return f.m(y) + " " + g.n(y);
}
test(3);

View File

@ -0,0 +1,15 @@
function _slice_target_fn(x) {
}
var x = 7;
var o = { f: 7 };
if (o != null) {
o = (function _push_o(x) { return x>0? x: -1; })(o.f);
var p = { };
_slice_target_fn(o);
}

View File

@ -71,12 +71,13 @@ public abstract class TestCorrelatedPairExtraction {
String expected = new CAstDumper().dump(parseJS(tmp, ast));
expected = TestForInBodyExtraction.eraseGeneratedNames(expected);
if(ASSERT_EQUALS) {
FileUtil.writeFile(new File("expected.dump"), expected);
FileUtil.writeFile(new File("actual.dump"), actual);
if(ASSERT_EQUALS) {
Assert.assertEquals(testName, expected, actual);
} else {
FileUtil.writeFile(new File("expected.dump"), expected);
FileUtil.writeFile(new File("actual.dump"), actual);
}
}
} catch (IOException e) {
e.printStackTrace();
} catch (ClassHierarchyException e) {
@ -429,7 +430,7 @@ public abstract class TestCorrelatedPairExtraction {
"function addMethods(source) {\n" +
" var properties = Object.keys(source);\n" +
" for (var i = 0, length = properties.length; i < length; i++) {\n" +
" var property = properties[i], value; value = (function _forin_body_0(property, thi$) { var value; value = source[property];\n" +
" var property, value; property = properties[i]; value = (function _forin_body_0(property, thi$) { var value = source[property]; \n" +
" thi$.prototype[property] = value; return value; })(property, this);\n" +
" }\n" +
" return this;\n" +
@ -450,7 +451,7 @@ public abstract class TestCorrelatedPairExtraction {
"function addMethods(source) {\n" +
" var properties = Object.keys(source);\n" +
" for (var i = 0, length = properties.length; i < length; i++) {\n" +
" var property = properties[i], foo = 23, value; value = (function _forin_body_0(property, thi$) { var value; value = source[property];\n" +
" var property, foo, value; property = properties[i]; foo = 23; value = (function _forin_body_0(property, thi$) { var value = source[property];\n" +
" thi$.prototype[property] = value; return value; })(property, this);\n" +
" }\n" +
" return this;\n" +
@ -471,8 +472,8 @@ public abstract class TestCorrelatedPairExtraction {
"function addMethods(source) {\n" +
" var properties = Object.keys(source);\n" +
" for (var i = 0, length = properties.length; i < length; i++) {\n" +
" var property = properties[i], foo = 23, value, bar; value = (function _forin_body_0(property, thi$) { var value; value = source[property], bar = 42;\n" +
" thi$.prototype[property] = value; return value; })(property, this);\n" +
" var property, foo, value, bar; property = properties[i]; foo = 23; value = function _forin_body_0(property, thi$) { var value = source[property]; bar = 42;\n" +
" thi$.prototype[property] = value; return value; }(property, this);\n" +
" }\n" +
" return this;\n" +
"}");
@ -587,4 +588,33 @@ public abstract class TestCorrelatedPairExtraction {
" }" +
"}");
}
@Test
public void test25() {
testRewriter(
"function eachProp(obj, func) {" +
" var prop;" +
" for (prop in obj) {" +
" if (hasProp(obj, prop)) {" +
" if (func(obj[prop], prop)) {" +
" break;" +
" }" +
" }" +
" }" +
"}",
"function eachProp(obj, func) {" +
" var prop;" +
" for (prop in obj) {" +
" if (hasProp(obj, prop)) {" +
" re$ = (function _forin_body_0 (prop) { if (func(obj[prop], prop)) { return { type: \"goto\", target: 0 }; } })(prop);" +
" if (re$) {" +
" if (re$.type == \"goto\") {" +
" if (re$.target == 0)" +
" break;" +
" }" +
" }" +
" }" +
" }" +
"}");
}
}

View File

@ -0,0 +1,103 @@
/*******************************************************************************
* Copyright (c) 2007 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.cast.js.test;
import java.io.IOException;
import java.util.Collection;
import java.util.Iterator;
import junit.framework.Assert;
import org.junit.Test;
import com.ibm.wala.cast.js.ipa.callgraph.JSCFABuilder;
import com.ibm.wala.cast.js.ipa.modref.JavaScriptModRef;
import com.ibm.wala.classLoader.CallSiteReference;
import com.ibm.wala.core.tests.slicer.SlicerTest;
import com.ibm.wala.ipa.callgraph.CGNode;
import com.ibm.wala.ipa.callgraph.CallGraph;
import com.ibm.wala.ipa.slicer.NormalStatement;
import com.ibm.wala.ipa.slicer.SDG;
import com.ibm.wala.ipa.slicer.Slicer;
import com.ibm.wala.ipa.slicer.Slicer.ControlDependenceOptions;
import com.ibm.wala.ipa.slicer.Slicer.DataDependenceOptions;
import com.ibm.wala.ipa.slicer.Statement;
import com.ibm.wala.util.CancelException;
import com.ibm.wala.util.WalaException;
import com.ibm.wala.util.collections.HashSetFactory;
import com.ibm.wala.util.intset.IntSetAction;
public abstract class TestJavaScriptSlicer extends TestJSCallGraphShape {
@Test
public void testSimpleData() throws IOException, WalaException, IllegalArgumentException, CancelException {
Collection<Statement> result = slice("slice1.js", DataDependenceOptions.FULL, ControlDependenceOptions.NONE);
for(Statement r : result) {
System.err.println(r);
}
Assert.assertEquals(0, SlicerTest.countConditionals(result));
}
@Test
public void testSimpleAll() throws IOException, WalaException, IllegalArgumentException, CancelException {
Collection<Statement> result = slice("slice1.js", DataDependenceOptions.FULL, ControlDependenceOptions.FULL);
for(Statement r : result) {
System.err.println(r);
}
Assert.assertEquals(2, SlicerTest.countConditionals(result));
}
@Test
public void testSimpleControl() throws IOException, WalaException, IllegalArgumentException, CancelException {
Collection<Statement> result = slice("slice1.js", DataDependenceOptions.NONE, ControlDependenceOptions.FULL);
for(Statement r : result) {
System.err.println(r);
}
Assert.assertEquals(1, SlicerTest.countConditionals(result));
}
private Collection<Statement> slice(String file, DataDependenceOptions data, ControlDependenceOptions ctrl) throws IOException, WalaException, CancelException {
JSCFABuilder B = JSCallGraphBuilderUtil.makeScriptCGBuilder("tests", file);
CallGraph CG = B.makeCallGraph(B.getOptions());
final Collection<Statement> ss = findTargetStatement(CG);
SDG sdg = new SDG(CG, B.getPointerAnalysis(), new JavaScriptModRef(), data, ctrl);
Collection<Statement> result = Slicer.computeBackwardSlice(sdg, ss);
return result;
}
private Collection<Statement> findTargetStatement(CallGraph CG) {
final Collection<Statement> ss = HashSetFactory.make();
for(CGNode n : getNodes(CG, "suffix:_slice_target_fn")) {
for(Iterator<CGNode> callers = CG.getPredNodes(n); callers.hasNext(); ) {
final CGNode caller = callers.next();
for(Iterator<CallSiteReference> sites = CG.getPossibleSites(caller, n); sites.hasNext(); ) {
caller.getIR().getCallInstructionIndices(sites.next()).foreach(new IntSetAction() {
@Override
public void act(int x) {
ss.add(new NormalStatement(caller, x));
}
});
}
}
}
return ss;
}
}

View File

@ -81,6 +81,15 @@ public abstract class TestSimpleCallGraphShape extends TestJSCallGraphShape {
verifyGraphAssertions(CG, assertionsForObjects);
}
private static final Object[][] cfgAssertionsForInherit = new Object[][] {
new Object[]{"ctor:tests/inherit.js/objectMasquerading/Rectangle",
new int[][]{{1,7},{2},{3,7},{4,7},{5,6},{7},{7}}
},
new Object[]{"ctor:tests/inherit.js/sharedClassObject/Rectangle",
new int[][]{{1,7},{2},{3,7},{4,7},{5,6},{7},{7}}
}
};
private static final Object[][] assertionsForInherit = new Object[][] {
new Object[] { ROOT, new String[] { "tests/inherit.js" } },
new Object[] {
@ -88,18 +97,26 @@ public abstract class TestSimpleCallGraphShape extends TestJSCallGraphShape {
new String[] { "tests/inherit.js/objectMasquerading", "tests/inherit.js/objectMasquerading/Rectangle/area",
"tests/inherit.js/Polygon/shape", "tests/inherit.js/sharedClassObject",
"tests/inherit.js/sharedClassObject/Rectangle/area" } },
/*
* new Object[]{"tests/inherit.js/objectMasquerading", new
* String[]{"ctor:tests/inherit.js/objectMasquerading/Rectangle"}}, new
* Object[]{"tests/inherit.js/sharedClassObject", new
* String[]{"ctor:tests/inherit.js/sharedClassObject/Rectangle"}},
*/
new Object[]{
"tests/inherit.js/objectMasquerading",
new String[]{"ctor:tests/inherit.js/objectMasquerading/Rectangle"}},
new Object[]{
"ctor:tests/inherit.js/objectMasquerading/Rectangle" ,
new String[]{"tests/inherit.js/objectMasquerading/Rectangle"}},
new Object[]{"tests/inherit.js/objectMasquerading/Rectangle",
new String[]{"tests/inherit.js/Polygon"}},
new Object[]{
"tests/inherit.js/sharedClassObject",
new String[]{"ctor:tests/inherit.js/sharedClassObject/Rectangle"}},
new Object[]{"ctor:tests/inherit.js/sharedClassObject/Rectangle",
new String[]{"tests/inherit.js/sharedClassObject/Rectangle"}}
};
@Test
public void testInherit() throws IOException, IllegalArgumentException, CancelException, WalaException {
CallGraph CG = JSCallGraphBuilderUtil.makeScriptCG("tests", "inherit.js");
verifyGraphAssertions(CG, assertionsForInherit);
verifyCFGAssertions(CG, cfgAssertionsForInherit);
}
private static final Object[][] assertionsForNewfn = new Object[][] {
@ -640,6 +657,20 @@ public abstract class TestSimpleCallGraphShape extends TestJSCallGraphShape {
verifyGraphAssertions(CG, assertionsForDeadCode);
}
private static final Object[][] assertionsForShadow = new Object[][] {
new Object[] { ROOT, new String[] { "tests/shadow_test.js" } },
new Object[] { "tests/shadow_test.js", new String[] { "tests/shadow_test.js/test" } },
new Object[] { "tests/shadow_test.js/test", new String[] { "tests/shadow_test.js/bad" } },
new Object[] { "tests/shadow_test.js/test", new String[] { "tests/shadow_test.js/global_bad" } }
};
@Test
public void testShadow() throws IOException, WalaException, IllegalArgumentException, CancelException {
JSCFABuilder builder = JSCallGraphBuilderUtil.makeScriptCGBuilder("tests", "shadow_test.js");
CallGraph cg = builder.makeCallGraph(builder.getOptions());
verifyGraphAssertions(cg, assertionsForShadow);
}
private static final Object[][] assertionsForExtend = new Object[][] {
new Object[] { ROOT, new String[] { "tests/extend.js" } },
new Object[] { "tests/extend.js", new String[] { "suffix:bar", "!suffix:foo" } }
@ -679,7 +710,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());
@ -687,4 +718,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

@ -309,7 +309,38 @@ public abstract class TestSimplePageCallGraphShape extends TestJSCallGraphShape
CAstCallGraphUtil.dumpCG(builder.getPointerAnalysis(), CG);
verifyGraphAssertions(CG, assertionsForWindowOnload);
}
public static final Object[][] assertionsForSkeleton = new Object[][] {
new Object[] { ROOT, new String[] { "skeleton.html" } },
new Object[] { "skeleton.html", new String[] { "skeleton.html/__WINDOW_MAIN__" } },
new Object[] { "skeleton.html/__WINDOW_MAIN__", new String[] { "skeleton.html/__WINDOW_MAIN__/dollar" } },
new Object[] { "skeleton.html/__WINDOW_MAIN__/dollar", new String[] { "skeleton.html/__WINDOW_MAIN__/bad_guy" } },
new Object[] { "skeleton.html/__WINDOW_MAIN__/bad_guy", new String[] { "skeleton.html/__WINDOW_MAIN__/dollar" } },
};
@Test public void testSkeleton() throws IOException, IllegalArgumentException, CancelException, WalaException {
URL url = getClass().getClassLoader().getResource("pages/skeleton.html");
CallGraph CG = JSCallGraphBuilderUtil.makeHTMLCG(url);
verifyGraphAssertions(CG, assertionsForSkeleton);
}
public static final Object[][] assertionsForSkeleton2 = new Object[][] {
new Object[] { ROOT, new String[] { "skeleton2.html" } },
new Object[] { "skeleton2.html", new String[] { "skeleton2.html/__WINDOW_MAIN__" } },
new Object[] { "skeleton2.html/__WINDOW_MAIN__", new String[] { "skeleton2.html/__WINDOW_MAIN__/dollar" } },
new Object[] { "skeleton2.html/__WINDOW_MAIN__/dollar", new String[] { "ctor:skeleton2.html/__WINDOW_MAIN__/dollar_init" } },
new Object[] { "ctor:skeleton2.html/__WINDOW_MAIN__/dollar_init", new String[] { "skeleton2.html/__WINDOW_MAIN__/dollar_init" } },
new Object[] { "skeleton2.html/__WINDOW_MAIN__/dollar_init", new String[] { "skeleton2.html/__WINDOW_MAIN__/bad_guy" } },
new Object[] { "skeleton2.html/__WINDOW_MAIN__/bad_guy", new String[] { "skeleton2.html/__WINDOW_MAIN__/dollar" } },
};
@Test public void testSkeleton2() throws IOException, IllegalArgumentException, CancelException, WalaException {
URL url = getClass().getClassLoader().getResource("pages/skeleton2.html");
CallGraph CG = JSCallGraphBuilderUtil.makeHTMLCG(url);
System.err.println(CG);
verifyGraphAssertions(CG, assertionsForSkeleton2);
}
/*
@Test public void testJQuery() throws IOException, IllegalArgumentException, CancelException, WalaException {
URL url = getClass().getClassLoader().getResource("pages/jquery.html");

View File

@ -1,4 +1,4 @@
<?xml version="1.0" encoding="UTF-8"?>
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<launchConfiguration type="org.eclipse.jdt.junit.launchconfig">
<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_PATHS">
<listEntry value="/com.ibm.wala.cast.js.test/harness-src/com/ibm/wala/cast/js/test/TestSimpleCallGraphShape.java"/>
@ -7,6 +7,9 @@
<listEntry value="1"/>
</listAttribute>
<booleanAttribute key="org.eclipse.debug.core.appendEnvironmentVariables" value="true"/>
<mapAttribute key="org.eclipse.debug.core.preferred_launchers">
<mapEntry key="[run]" value="org.eclipse.jdt.junit.launchconfig"/>
</mapAttribute>
<stringAttribute key="org.eclipse.jdt.junit.CONTAINER" value=""/>
<booleanAttribute key="org.eclipse.jdt.junit.KEEPRUNNING_ATTR" value="false"/>
<stringAttribute key="org.eclipse.jdt.junit.TESTNAME" value=""/>

View File

@ -5,5 +5,6 @@
<classpathentry kind="lib" path="lib/jericho-html-3.2.jar"/>
<classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.6"/>
<classpathentry kind="lib" path="lib/commons-io-2.4.jar"/>
<classpathentry kind="output" path="bin"/>
</classpath>

View File

@ -4,7 +4,8 @@ Bundle-Name: JavaScript Plug-in
Bundle-SymbolicName: com.ibm.wala.cast.js;singleton:=true
Bundle-Version: 1.3.4.qualifier
Bundle-ClassPath: .,
lib/jericho-html-3.2.jar
lib/jericho-html-3.2.jar,
lib/commons-io-2.4.jar
Bundle-Activator: com.ibm.wala.cast.js.JavaScriptPlugin
Bundle-Vendor: IBM
Export-Package: .,
@ -21,6 +22,7 @@ Export-Package: .,
com.ibm.wala.cast.js.ipa.callgraph,
com.ibm.wala.cast.js.ipa.callgraph.correlations,
com.ibm.wala.cast.js.ipa.callgraph.correlations.extraction,
com.ibm.wala.cast.js.ipa.modref,
com.ibm.wala.cast.js.ipa.summaries,
com.ibm.wala.cast.js.loader,
com.ibm.wala.cast.js.ssa,

View File

@ -1,6 +1,7 @@
bin.includes = .,\
META-INF/,\
lib/,\
lib/commons-io-2.4.jar,\
lib/jericho-html-3.2.jar
source.. = source/,\
dat/

View File

@ -36,6 +36,10 @@
<available file="${plugin.destination}/lib/jericho-html-3.2.jar" property="jericho.present"/>
</target>
<target name="CommonsIoPresent" depends="init">
<available file="${plugin.destination}/lib/commons-io-2.4.jar" property="commons.io.present"/>
</target>
<target name="fetchJericho" depends="JerichoPresent" unless="jericho.present">
<delete dir="${temp.folder}"/>
<mkdir dir="${temp.folder}"/>
@ -45,8 +49,17 @@
<delete dir="${temp.folder}"/>
</target>
<target name="fetchCommonsIo" depends="CommonsIoPresent" unless="commons.io.present">
<delete dir="${temp.folder}"/>
<mkdir dir="${temp.folder}"/>
<get src="http://apache.petsads.us/commons/io/binaries/commons-io-2.4-bin.zip" dest="${temp.folder}/commons-io-2.4.zip"/>
<unzip src="${temp.folder}/commons-io-2.4.zip" dest="${temp.folder}"/>
<copy file="${temp.folder}/commons-io-2.4/commons-io-2.4.jar" tofile="${plugin.destination}/lib/commons-io-2.4.jar" />
<delete dir="${temp.folder}"/>
</target>
<target name="getJars" depends="fetchJericho" />
<target name="getJars" depends="fetchJericho,fetchCommonsIo" />
<target name="init" depends="properties">
<condition property="pluginTemp" value="${buildTempFolder}/plugins">

View File

@ -190,7 +190,7 @@ DOMDocument = function DOMDocument() {
};
};
DOMDocument.prototype.createDocumentFragment = function Document_prototype_createDocumentFragment() {
// TODO: model me
return new DOMDocument();
};
DOMDocument.prototype.createComment = function Document_prototype_createComment() {
// TODO: model me

View File

@ -358,6 +358,15 @@ local_string.prototype = {
return new Number(primitive("StringCharCodeAt", pos));
},
concat: function String_prototype_concat () {
var result = this;
for(i = 0; i < arguments.length; i++)
result = result + arguments[i];
return result;
},
toUpperCase: function String_prototype_toUpperCase() {
return new String(primitive("StringToUpperCase", this));
},
@ -402,7 +411,8 @@ local_string.prototype = {
},
replace: function String_prototype_replace(regex, withStr) {
return new String(primitive("StringReplace", this, regex, withStr));
// return new String(primitive("StringReplace", this, regex, withStr));
return this || withStr;
},
match: function String_prototype_match(regexp) {
@ -534,7 +544,7 @@ local_regexp.prototype = {
constructor: RegExp,
exec: function RegExp_prototype_exec(string) {
return new Array(primitive("RegexpExec", this, string));
return [ string, string, string, string, string ] || null;
},
test: function RegExp_prototype_test(string) {

View File

@ -22,6 +22,13 @@
</goals>
<configuration>
<artifactItems>
<artifactItem>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.4</version>
<type>jar</type>
<overWrite>false</overWrite>
</artifactItem>
<artifactItem>
<groupId>net.htmlparser.jericho</groupId>
<artifactId>jericho-html</artifactId>

View File

@ -24,6 +24,9 @@ import com.ibm.wala.cast.js.ipa.callgraph.JSAnalysisOptions;
import com.ibm.wala.cast.js.ipa.callgraph.JSCallGraph;
import com.ibm.wala.cast.js.ipa.callgraph.JavaScriptConstructTargetSelector;
import com.ibm.wala.cast.js.ipa.callgraph.JavaScriptFunctionDotCallTargetSelector;
import com.ibm.wala.cast.js.ipa.summaries.JavaScriptConstructorFunctions;
import com.ibm.wala.cast.js.ipa.summaries.JavaScriptConstructorFunctions.JavaScriptConstructor;
import com.ibm.wala.cast.js.types.JavaScriptMethods;
import com.ibm.wala.cast.types.AstMethodReference;
import com.ibm.wala.classLoader.CallSiteReference;
import com.ibm.wala.classLoader.IClass;
@ -65,6 +68,7 @@ public abstract class FieldBasedCallGraphBuilder {
// standard call graph machinery
protected final AnalysisOptions options;
protected final AnalysisCache cache;
protected final JavaScriptConstructorFunctions constructors;
protected final MethodTargetSelector targetSelector;
private static final boolean LOG_TIMINGS = true;
@ -73,11 +77,12 @@ public abstract class FieldBasedCallGraphBuilder {
this.cha = cha;
this.options = options;
this.cache = cache;
this.targetSelector = setupMethodTargetSelector(cha, options);
this.constructors = new JavaScriptConstructorFunctions(cha);
this.targetSelector = setupMethodTargetSelector(cha, constructors, options);
}
private MethodTargetSelector setupMethodTargetSelector(IClassHierarchy cha, AnalysisOptions options) {
MethodTargetSelector result = new JavaScriptConstructTargetSelector(cha, options.getMethodTargetSelector());
private MethodTargetSelector setupMethodTargetSelector(IClassHierarchy cha, JavaScriptConstructorFunctions constructors2, AnalysisOptions options) {
MethodTargetSelector result = new JavaScriptConstructTargetSelector(constructors2, options.getMethodTargetSelector());
if (options instanceof JSAnalysisOptions && ((JSAnalysisOptions)options).handleCallApply()) {
// TODO handle Function.prototype.apply
result = new JavaScriptFunctionDotCallTargetSelector(result);
@ -85,15 +90,16 @@ public abstract class FieldBasedCallGraphBuilder {
return result;
}
protected FlowGraph flowGraphFactory() {
FlowGraphBuilder builder = new FlowGraphBuilder(cha, cache);
protected FlowGraph flowGraphFactory(JavaScriptConstructorFunctions selector) {
FlowGraphBuilder builder = new FlowGraphBuilder(cha, cache, selector);
return builder.buildFlowGraph();
}
/**
* Build a flow graph for the program to be analysed.
* @param selector TODO
*/
public abstract FlowGraph buildFlowGraph(IProgressMonitor monitor) throws CancelException;
public abstract FlowGraph buildFlowGraph(IProgressMonitor monitor, JavaScriptConstructorFunctions selector) throws CancelException;
/**
* Main entry point: builds a flow graph, then extracts a call graph and returns it.
@ -104,7 +110,7 @@ public abstract class FieldBasedCallGraphBuilder {
if(LOG_TIMINGS) fgBegin = System.currentTimeMillis();
MonitorUtil.beginTask(monitor, "flow graph", 1);
FlowGraph flowGraph = buildFlowGraph(monitor);
FlowGraph flowGraph = buildFlowGraph(monitor, constructors);
MonitorUtil.done(monitor);
if(LOG_TIMINGS) {
@ -157,14 +163,32 @@ public abstract class FieldBasedCallGraphBuilder {
CGNode caller = cg.findOrCreateNode(kaller.getMethod(AstMethodReference.fnSelector), Everywhere.EVERYWHERE);
CallSiteReference site = callVertex.getSite();
IMethod target = targetSelector.getCalleeTarget(caller, site, targetVertex.getConcreteType());
if (caller.toString().contains("string_ctor"))
System.err.println(caller + " " + site + " " + target);
boolean isFunctionPrototypeCall = target != null
&& target.getName().toString().startsWith(JavaScriptFunctionDotCallTargetSelector.SYNTHETIC_CALL_METHOD_PREFIX);
if (isFunctionPrototypeCall) {
handleFunctionPrototypeCallInvocation(flowgraph, monitor, cg, callVertex, caller, site, target);
} else {
addEdgeToJSCallGraph(cg, site, target, caller);
addEdgeToJSCallGraph(cg, site, target, caller);
if (target instanceof JavaScriptConstructor) {
IMethod fun = ((JavaScriptConstructor)target).constructedType().getMethod(AstMethodReference.fnSelector);
CGNode ctorCaller = cg.findOrCreateNode(target, Everywhere.EVERYWHERE);
CallSiteReference ref = null;
Iterator<CallSiteReference> sites = ctorCaller.iterateCallSites();
while(sites.hasNext()) {
CallSiteReference r = sites.next();
if (r.getDeclaredTarget().getSelector().equals(AstMethodReference.fnSelector)) {
ref = r;
break;
}
}
if (ref != null) {
addEdgeToJSCallGraph(cg, ref, fun, ctorCaller);
}
}
}
}
@ -183,6 +207,7 @@ public abstract class FieldBasedCallGraphBuilder {
// need to create nodes for reflective targets of call, and then add them
// as callees of the synthetic method
OrdinalSet<FuncVertex> reflectiveTargets = getReflectiveTargets(flowgraph, callVertex, monitor);
System.err.println("adding callees " + reflectiveTargets + " for " + caller);
// there should only be one call site in the synthetic method
CallSiteReference reflectiveCallSite = functionPrototypeCallNode.getIR().iterateCallSites().next();
for (FuncVertex f : reflectiveTargets) {
@ -230,6 +255,13 @@ public abstract class FieldBasedCallGraphBuilder {
return flowGraph.getReachingSet(functionParam, monitor);
}
private OrdinalSet<FuncVertex> getConstructorTargets(FlowGraph flowGraph, CallVertex callVertex, IProgressMonitor monitor) throws CancelException {
SSAAbstractInvokeInstruction invoke = callVertex.getInstruction();
assert invoke.getDeclaredTarget().getName().equals(JavaScriptMethods.ctorAtom);
VarVertex objectParam = flowGraph.getVertexFactory().makeVarVertex(callVertex.getCaller(), invoke.getUse(0));
return flowGraph.getReachingSet(objectParam, monitor);
}
/**
* Extract call edges from the flow graph into high-level representation.
*/
@ -239,11 +271,6 @@ public abstract class FieldBasedCallGraphBuilder {
// find all pairs <call, func> such that call is reachable from func in the flow graph
for(final CallVertex callVertex : factory.getCallVertices()) {
if (callVertex.getCaller().getFullName().contains("string_ctor")) {
System.err.println(callVertex.getCaller().getFullName());
System.err.println(callVertex.getInstruction());
System.err.println(flowgraph.getReachingSet(callVertex, monitor));
}
for(FuncVertex funcVertex : flowgraph.getReachingSet(callVertex, monitor)) {
result.add(Pair.make(callVertex, funcVertex));
}

View File

@ -55,7 +55,7 @@ public class JSMethodInstructionVisitor extends JSAbstractInstructionVisitor {
if(fndef instanceof AstGlobalRead) {
AstGlobalRead agr = (AstGlobalRead)fndef;
if(agr.getGlobalName().equals("global Function")) {
if(invk.getNumberOfParameters() < 2)
if(invk.getNumberOfParameters() != 2)
return false;
// this may be a genuine use of "new Function()", not a declaration/expression
if(!symtab.isStringConstant(invk.getUse(1)))

View File

@ -18,10 +18,13 @@ import com.ibm.wala.cast.js.callgraph.fieldbased.flowgraph.vertices.FuncVertex;
import com.ibm.wala.cast.js.callgraph.fieldbased.flowgraph.vertices.VarVertex;
import com.ibm.wala.cast.js.callgraph.fieldbased.flowgraph.vertices.VertexFactory;
import com.ibm.wala.cast.js.ipa.callgraph.JSAnalysisOptions;
import com.ibm.wala.cast.js.ipa.summaries.JavaScriptConstructorFunctions;
import com.ibm.wala.cast.js.ssa.JavaScriptInvoke;
import com.ibm.wala.cast.js.types.JavaScriptMethods;
import com.ibm.wala.cast.types.AstMethodReference;
import com.ibm.wala.ipa.callgraph.AnalysisCache;
import com.ibm.wala.ipa.callgraph.AnalysisOptions;
import com.ibm.wala.ipa.callgraph.MethodTargetSelector;
import com.ibm.wala.ipa.cha.IClassHierarchy;
import com.ibm.wala.util.CancelException;
import com.ibm.wala.util.MonitorUtil;
@ -49,8 +52,8 @@ public class OptimisticCallgraphBuilder extends FieldBasedCallGraphBuilder {
}
@Override
public FlowGraph buildFlowGraph(IProgressMonitor monitor) throws CancelException {
FlowGraph flowgraph = flowGraphFactory();
public FlowGraph buildFlowGraph(IProgressMonitor monitor, JavaScriptConstructorFunctions selector) throws CancelException {
FlowGraph flowgraph = flowGraphFactory(selector);
// keep track of which call edges we already know about
Set<Pair<CallVertex, FuncVertex>> knownEdges = HashSetFactory.make();
@ -94,14 +97,19 @@ public class OptimisticCallgraphBuilder extends FieldBasedCallGraphBuilder {
VertexFactory factory = flowgraph.getVertexFactory();
JavaScriptInvoke invk = c.getInstruction();
FuncVertex caller = c.getCaller();
for(int i=1;i<invk.getNumberOfParameters();++i) {
// only flow receiver into 'this' if invk is, in fact, a method call
flowgraph.addEdge(factory.makeVarVertex(caller, invk.getUse(i)), factory.makeArgVertex(callee));
if(i > 1 || invk.getDeclaredTarget().equals(JavaScriptMethods.dispatchReference))
flowgraph.addEdge(factory.makeVarVertex(caller, invk.getUse(i)), factory.makeParamVertex(callee, i-1));
int offset = 0;
if (invk.getDeclaredTarget().getSelector().equals(JavaScriptMethods.ctorReference.getSelector())) {
offset = 1;
}
for(int i=0;i<invk.getNumberOfParameters();++i) {
// only flow receiver into 'this' if invk is, in fact, a method call
flowgraph.addEdge(factory.makeVarVertex(caller, invk.getUse(i)), factory.makeArgVertex(callee));
if(i != 1 || !invk.getDeclaredTarget().getSelector().equals(AstMethodReference.fnSelector))
flowgraph.addEdge(factory.makeVarVertex(caller, invk.getUse(i)), factory.makeParamVertex(callee, i+offset));
}
// flow from return vertex to result vertex
flowgraph.addEdge(factory.makeRetVertex(callee), factory.makeVarVertex(caller, invk.getDef()));
}
@ -115,10 +123,11 @@ public class OptimisticCallgraphBuilder extends FieldBasedCallGraphBuilder {
VarVertex receiverVertex = factory.makeVarVertex(caller, invk.getUse(1));
OrdinalSet<FuncVertex> realCallees = flowgraph.getReachingSet(receiverVertex, monitor);
System.err.println("callees " + realCallees + " for " + caller);
for(FuncVertex realCallee: realCallees) {
// flow from arguments to parameters
for(int i=2;i<invk.getNumberOfParameters();++i)
flowgraph.addEdge(factory.makeVarVertex(caller, invk.getUse(i)), factory.makeParamVertex(realCallee, i-2));
flowgraph.addEdge(factory.makeVarVertex(caller, invk.getUse(i)), factory.makeParamVertex(realCallee, i-1));
// flow from return vertex to result vertex
flowgraph.addEdge(factory.makeRetVertex(realCallee), factory.makeVarVertex(caller, invk.getDef()));

View File

@ -15,6 +15,7 @@ import java.util.Iterator;
import com.ibm.wala.cast.js.callgraph.fieldbased.flowgraph.FlowGraph;
import com.ibm.wala.cast.js.callgraph.fieldbased.flowgraph.vertices.FuncVertex;
import com.ibm.wala.cast.js.callgraph.fieldbased.flowgraph.vertices.VertexFactory;
import com.ibm.wala.cast.js.ipa.summaries.JavaScriptConstructorFunctions;
import com.ibm.wala.cast.js.ssa.JavaScriptInvoke;
import com.ibm.wala.cast.js.types.JavaScriptTypes;
import com.ibm.wala.cast.loader.AstMethod;
@ -23,6 +24,7 @@ import com.ibm.wala.classLoader.IClass;
import com.ibm.wala.classLoader.IMethod;
import com.ibm.wala.ipa.callgraph.AnalysisCache;
import com.ibm.wala.ipa.callgraph.AnalysisOptions;
import com.ibm.wala.ipa.callgraph.MethodTargetSelector;
import com.ibm.wala.ipa.cha.IClassHierarchy;
import com.ibm.wala.ssa.DefUse;
import com.ibm.wala.ssa.IR;
@ -45,8 +47,8 @@ public class PessimisticCallGraphBuilder extends FieldBasedCallGraphBuilder {
}
@Override
public FlowGraph buildFlowGraph(IProgressMonitor monitor) {
FlowGraph flowgraph = flowGraphFactory();
public FlowGraph buildFlowGraph(IProgressMonitor monitor, JavaScriptConstructorFunctions selector) {
FlowGraph flowgraph = flowGraphFactory(selector);
resolveLocalCalls(flowgraph);
return flowgraph;
}
@ -112,7 +114,7 @@ public class PessimisticCallGraphBuilder extends FieldBasedCallGraphBuilder {
// yes, so add edges from arguments to parameters...
for(int i=2;i<use_invk.getNumberOfParameters();++i)
flowgraph.addEdge(factory.makeVarVertex(caller, use_invk.getUse(i)), factory.makeParamVertex(callee, i-1));
flowgraph.addEdge(factory.makeVarVertex(caller, use_invk.getUse(i)), factory.makeParamVertex(callee, i));
// ...and from return to result
flowgraph.addEdge(factory.makeRetVertex(callee), factory.makeVarVertex(caller, use.getDef()));

View File

@ -21,11 +21,15 @@ import com.ibm.wala.cast.js.callgraph.fieldbased.flowgraph.vertices.VarVertex;
import com.ibm.wala.cast.js.callgraph.fieldbased.flowgraph.vertices.Vertex;
import com.ibm.wala.cast.js.callgraph.fieldbased.flowgraph.vertices.VertexFactory;
import com.ibm.wala.cast.js.ipa.callgraph.JSAnalysisOptions;
import com.ibm.wala.cast.js.ipa.summaries.JavaScriptConstructorFunctions;
import com.ibm.wala.cast.js.ssa.JavaScriptInvoke;
import com.ibm.wala.cast.js.types.JavaScriptMethods;
import com.ibm.wala.cast.types.AstMethodReference;
import com.ibm.wala.classLoader.IMethod;
import com.ibm.wala.ipa.callgraph.AnalysisCache;
import com.ibm.wala.ipa.callgraph.AnalysisOptions;
import com.ibm.wala.ipa.cha.IClassHierarchy;
import com.ibm.wala.ssa.IR;
import com.ibm.wala.util.CancelException;
import com.ibm.wala.util.MonitorUtil;
import com.ibm.wala.util.MonitorUtil.IProgressMonitor;
@ -51,14 +55,17 @@ public class WorklistBasedOptimisticCallgraphBuilder extends FieldBasedCallGraph
private final boolean handleCallApply;
private FlowGraphBuilder builder;
public WorklistBasedOptimisticCallgraphBuilder(IClassHierarchy cha, AnalysisOptions options, AnalysisCache cache) {
super(cha, options, cache);
handleCallApply = options instanceof JSAnalysisOptions && ((JSAnalysisOptions)options).handleCallApply();
}
@Override
public FlowGraph buildFlowGraph(IProgressMonitor monitor) throws CancelException {
return new FlowGraphBuilder(cha, cache).buildFlowGraph();
public FlowGraph buildFlowGraph(IProgressMonitor monitor, JavaScriptConstructorFunctions selector) throws CancelException {
builder = new FlowGraphBuilder(cha, cache, selector);
return builder.buildFlowGraph();
}
@Override
@ -133,12 +140,17 @@ public class WorklistBasedOptimisticCallgraphBuilder extends FieldBasedCallGraph
VertexFactory factory = flowgraph.getVertexFactory();
FuncVertex caller = c.getCaller();
JavaScriptInvoke invk = c.getInstruction();
for(int i=1;i<invk.getNumberOfParameters();++i) {
int offset = 0;
if (invk.getDeclaredTarget().getSelector().equals(JavaScriptMethods.ctorReference.getSelector())) {
offset = 1;
}
for(int i=0;i<invk.getNumberOfParameters();++i) {
// only flow receiver into 'this' if invk is, in fact, a method call
flowgraph.addEdge(factory.makeVarVertex(caller, invk.getUse(i)), factory.makeArgVertex(callee));
if(i > 1 || invk.getDeclaredTarget().equals(JavaScriptMethods.dispatchReference))
addFlowEdge(flowgraph, factory.makeVarVertex(caller, invk.getUse(i)), factory.makeParamVertex(callee, i-1), worklist);
if(i != 1 || !invk.getDeclaredTarget().getSelector().equals(AstMethodReference.fnSelector))
addFlowEdge(flowgraph, factory.makeVarVertex(caller, invk.getUse(i)), factory.makeParamVertex(callee, i+offset), worklist);
}
// flow from return vertex to result vertex
@ -158,7 +170,7 @@ public class WorklistBasedOptimisticCallgraphBuilder extends FieldBasedCallGraph
// flow from arguments to parameters
for(int i=2;i<invk.getNumberOfParameters();++i) {
addFlowEdge(flowgraph, factory.makeVarVertex(caller, invk.getUse(i)), factory.makeParamVertex(realCallee, i-2), worklist);
addFlowEdge(flowgraph, factory.makeVarVertex(caller, invk.getUse(i)), factory.makeParamVertex(realCallee, i-1), worklist);
// flow from return vertex to result vertex
addFlowEdge(flowgraph, factory.makeRetVertex(realCallee), factory.makeVarVertex(caller, invk.getDef()), worklist);

View File

@ -22,6 +22,7 @@ import com.ibm.wala.cast.js.callgraph.fieldbased.flowgraph.vertices.FuncVertex;
import com.ibm.wala.cast.js.callgraph.fieldbased.flowgraph.vertices.VarVertex;
import com.ibm.wala.cast.js.callgraph.fieldbased.flowgraph.vertices.Vertex;
import com.ibm.wala.cast.js.callgraph.fieldbased.flowgraph.vertices.VertexFactory;
import com.ibm.wala.cast.js.ipa.summaries.JavaScriptConstructorFunctions;
import com.ibm.wala.cast.js.ssa.JavaScriptInvoke;
import com.ibm.wala.cast.js.ssa.JavaScriptPropertyRead;
import com.ibm.wala.cast.js.ssa.JavaScriptPropertyWrite;
@ -56,10 +57,12 @@ import com.ibm.wala.util.intset.IntSet;
public class FlowGraphBuilder {
private final IClassHierarchy cha;
private final AnalysisCache cache;
private final JavaScriptConstructorFunctions selector;
public FlowGraphBuilder(IClassHierarchy cha, AnalysisCache cache) {
public FlowGraphBuilder(IClassHierarchy cha, AnalysisCache cache, JavaScriptConstructorFunctions selector) {
this.cha = cha;
this.cache = cache;
this.selector = selector;
}
/**
@ -85,17 +88,21 @@ public class FlowGraphBuilder {
return flowgraph;
}
protected void visitProgram(FlowGraph flowgraph) {
public void visitProgram(FlowGraph flowgraph) {
for(IClass klass : cha) {
for(IMethod method : klass.getDeclaredMethods()) {
if(method.getDescriptor().equals(AstMethodReference.fnDesc))
visitFunction(flowgraph, method);
if(method.getDescriptor().equals(AstMethodReference.fnDesc)) {
visitFunction(flowgraph, method);
}
}
}
}
protected void visitFunction(FlowGraph flowgraph, IMethod method) {
public void visitFunction(FlowGraph flowgraph, IMethod method) {
{
if (method.toString().contains("ctor") && method.toString().contains("dollar_init")) {
System.err.println("found it");
}
IR ir = cache.getIR(method);
FlowGraphSSAVisitor visitor = new FlowGraphSSAVisitor(ir, flowgraph);
@ -354,8 +361,8 @@ public class FlowGraphBuilder {
flowgraph.addEdge(fnVertex, factory.makeVarVertex(fnVertex, 1));
// flow parameters into local variables
for(int i=0;i<fn.getNumberOfParameters()-1;++i)
flowgraph.addEdge(factory.makeParamVertex(fnVertex, i), factory.makeVarVertex(fnVertex, i+2));
for(int i=0;i<fn.getNumberOfParameters();++i)
flowgraph.addEdge(factory.makeParamVertex(fnVertex, i), factory.makeVarVertex(fnVertex, i+1));
// flow function into result variable
flowgraph.addEdge(fnVertex, factory.makeVarVertex(func, invk.getDef()));

View File

@ -50,7 +50,7 @@ public class JavaScriptAnalysisEngine extends AbstractAnalysisEngine {
try {
loaderFactory = new JavaScriptLoaderFactory(translatorFactory);
SourceModule[] files = (SourceModule[]) moduleFiles.toArray(new SourceModule[moduleFiles.size()]);
SourceModule[] files = moduleFiles.toArray(new SourceModule[moduleFiles.size()]);
scope = new CAstAnalysisScope(files, loaderFactory, Collections.singleton(JavaScriptLoader.JS));
} catch (IOException e) {

View File

@ -25,6 +25,9 @@ import java.util.Map.Entry;
import java.util.Set;
import java.util.regex.Pattern;
import org.apache.commons.io.ByteOrderMark;
import org.apache.commons.io.input.BOMInputStream;
import com.ibm.wala.cast.ir.translator.TranslatorToCAst.Error;
import com.ibm.wala.cast.js.html.jericho.JerichoHtmlParser;
import com.ibm.wala.cast.tree.CAstSourcePositionMap.Position;
@ -55,6 +58,7 @@ public class DomLessSourceExtractor extends JSSourceExtractor {
protected final SourceRegion entrypointRegion;
private ITag currentScriptTag;
private ITag currentCommentTag;
private int nodeCounter = 0;
private int scriptNodeCounter = 0;
@ -86,12 +90,15 @@ public class DomLessSourceExtractor extends JSSourceExtractor {
if (tag.getName().equalsIgnoreCase("script")) {
assert currentScriptTag != null;
currentScriptTag = null;
} else if (currentScriptTag != null && tag.getName().equals("!--")) {
assert currentCommentTag != null;
currentCommentTag = null;
}
}
@Override
public void handleText(Position p, String text) {
if (currentScriptTag != null) {
if (currentScriptTag != null && currentCommentTag == null) {
if (text.startsWith("<![CDATA[")) {
assert text.endsWith("]]>");
text = text.substring(9, text.length()-11);
@ -116,6 +123,8 @@ public class DomLessSourceExtractor extends JSSourceExtractor {
assert currentScriptTag == null;
currentScriptTag = tag;
scriptNodeCounter++;
} else if (currentScriptTag != null && tag.getName().equals("!--")){
currentCommentTag = tag;
}
handleDOM(tag);
}
@ -226,16 +235,17 @@ public class DomLessSourceExtractor extends JSSourceExtractor {
}
private void getScriptFromUrl(String urlAsString, ITag scriptTag) throws IOException, MalformedURLException {
// URL absoluteUrl = UrlManipulator.relativeToAbsoluteUrl(urlAsString, this.entrypointUrl);
// URL scriptSrc = urlResolver.resolve(absoluteUrl);
URL scriptSrc = new URL(entrypointUrl, urlAsString);
if (scriptSrc == null) { //Error resolving URL
return;
}
Reader scriptInputStream;
try {
scriptInputStream = new InputStreamReader(scriptSrc.openConnection().getInputStream());
BOMInputStream bs = new BOMInputStream(scriptSrc.openConnection().getInputStream(), false,
ByteOrderMark.UTF_8,
ByteOrderMark.UTF_16LE, ByteOrderMark.UTF_16BE,
ByteOrderMark.UTF_32LE, ByteOrderMark.UTF_32BE);
if (bs.hasBOM()) {
System.err.println("removing BOM " + bs.getBOM());
}
scriptInputStream = new InputStreamReader(bs);
} catch (Exception e) {
//it looks like this happens when we can't resolve the url?
if (DEBUG) {

View File

@ -57,7 +57,7 @@ public class WebPageLoaderFactory extends JavaScriptLoaderFactory {
@Override
protected int doGlobalRead(CAstNode n, WalkContext context, String name, TypeReference type) {
int result = context.currentScope().allocateTempValue();
if (isNestedWithinScriptBody(context) && ! "$$undefined".equals(name) && ! "window".equals(name)) {
if (isNestedWithinScriptBody(context) && ! "$$undefined".equals(name) && !"window".equals(name) && !name.startsWith("$$destructure")) {
// check if field is defined on 'window'
int windowVal = isScriptBody(context)? super.doLocalRead(context, "this", JavaScriptTypes.Root): super.doGlobalRead(n, context, "window", type);
@ -69,13 +69,15 @@ public class WebPageLoaderFactory extends JavaScriptLoaderFactory {
translateConditionOpcode(CAstOperator.OP_NE),
null,
isDefined,
context.currentScope().getConstantValue(new Integer(0))));
context.currentScope().getConstantValue(new Integer(0)),
-1));
PreBasicBlock srcB = context.cfg().getCurrentBlock();
// field lookup of value
context.cfg().newBlock(true);
context.cfg().addInstruction(((JSInstructionFactory) insts).GetInstruction(context.cfg().getCurrentInstruction(), result, windowVal, name));
context.cfg().addInstruction(insts.GotoInstruction(context.cfg().getCurrentInstruction()));
context.cfg().newBlock(true);
context.cfg().addInstruction(insts.GotoInstruction(context.cfg().getCurrentInstruction(), -1));
PreBasicBlock trueB = context.cfg().getCurrentBlock();
// read global
@ -99,7 +101,7 @@ public class WebPageLoaderFactory extends JavaScriptLoaderFactory {
@Override
protected void doLocalWrite(WalkContext context, String nm, TypeReference type, int rval) {
if (isScriptBody(context)) {
if (isNestedWithinScriptBody(context) && ! "$$undefined".equals(nm) && !"window".equals(nm) && !nm.startsWith("$$destructure")) {
int windowVal = super.doLocalRead(context, "this", type);
context.currentScope().getConstantValue(nm);
context.cfg().addInstruction(((JSInstructionFactory) insts).PutInstruction(context.cfg().getCurrentInstruction(), windowVal, rval, nm));

View File

@ -10,564 +10,45 @@
*****************************************************************************/
package com.ibm.wala.cast.js.ipa.callgraph;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.util.Map;
import java.util.Set;
import com.ibm.wala.cast.js.ipa.summaries.JavaScriptSummarizedFunction;
import com.ibm.wala.cast.js.ipa.summaries.JavaScriptSummary;
import com.ibm.wala.cast.js.loader.JSCallSiteReference;
import com.ibm.wala.cast.js.loader.JavaScriptLoader;
import com.ibm.wala.cast.js.ssa.JSInstructionFactory;
import com.ibm.wala.cast.js.ipa.summaries.JavaScriptConstructorFunctions;
import com.ibm.wala.cast.js.types.JavaScriptMethods;
import com.ibm.wala.cast.js.types.JavaScriptTypes;
import com.ibm.wala.cast.types.AstMethodReference;
import com.ibm.wala.classLoader.CallSiteReference;
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.MethodTargetSelector;
import com.ibm.wala.ipa.cha.IClassHierarchy;
import com.ibm.wala.ipa.summaries.MethodSummary;
import com.ibm.wala.ssa.ConstantValue;
import com.ibm.wala.ssa.IR;
import com.ibm.wala.ssa.SSAAbstractInvokeInstruction;
import com.ibm.wala.ssa.SymbolTable;
import com.ibm.wala.types.MethodReference;
import com.ibm.wala.types.TypeName;
import com.ibm.wala.types.TypeReference;
import com.ibm.wala.util.collections.HashMapFactory;
import com.ibm.wala.util.collections.Pair;
/**
* generates instructions to simulate the semantics of JS constructor invocations
*
*/
public class JavaScriptConstructTargetSelector implements MethodTargetSelector {
private static final boolean DEBUG = false;
private final IClassHierarchy cha;
private final MethodTargetSelector base;
private final Map<Object, IMethod> constructors = HashMapFactory.make();
public static class JavaScriptConstructor extends JavaScriptSummarizedFunction {
private final String toStringExtra;
private final IClass constructorForType;
private JavaScriptConstructor(MethodReference ref, MethodSummary summary, IClass declaringClass, IClass constructorForType, String toStringExtra) {
super(ref, summary, declaringClass);
this.toStringExtra = toStringExtra;
this.constructorForType = constructorForType;
}
private JavaScriptConstructor(MethodReference ref, MethodSummary summary, IClass declaringClass, IClass constructorForType) {
this(ref, summary, declaringClass, constructorForType, "");
}
@Override
public String toString() {
return "<ctor for " + getReference().getDeclaringClass() + toStringExtra + ">";
}
public IClass constructedType() {
return constructorForType;
}
}
private final JavaScriptConstructorFunctions constructors;
public JavaScriptConstructTargetSelector(IClassHierarchy cha, MethodTargetSelector base) {
this.cha = cha;
this.constructors = new JavaScriptConstructorFunctions(cha);
this.base = base;
}
private IMethod record(Object key, IMethod m) {
constructors.put(key, m);
return m;
}
private IMethod makeNullaryValueConstructor(IClass cls, Object value) {
JSInstructionFactory insts = (JSInstructionFactory)cls.getClassLoader().getInstructionFactory();
MethodReference ref = JavaScriptMethods.makeCtorReference(cls.getReference());
JavaScriptSummary S = new JavaScriptSummary(ref, 1);
S.addStatement(insts.GetInstruction(S.getNumberOfStatements(), 4, 1, "prototype"));
S.getNextProgramCounter();
S.addStatement(insts.NewInstruction(S.getNumberOfStatements(), 5, NewSiteReference.make(S.getNextProgramCounter(), cls.getReference())));
S.addStatement(insts.SetPrototype(S.getNumberOfStatements(), 5, 4));
//S.addStatement(insts.PutInstruction(5, 4, "__proto__"));
S.getNextProgramCounter();
S.addConstant(new Integer(8), new ConstantValue(value));
S.addStatement(insts.PutInstruction(S.getNumberOfStatements(), 5, 8, "$value"));
S.getNextProgramCounter();
S.addStatement(insts.ReturnInstruction(S.getNumberOfStatements(), 5, false));
S.getNextProgramCounter();
//S.addConstant(9, new ConstantValue("__proto__"));
return new JavaScriptConstructor(ref, S, cls, cls);
}
private IMethod makeUnaryValueConstructor(IClass cls) {
JSInstructionFactory insts = (JSInstructionFactory)cls.getClassLoader().getInstructionFactory();
MethodReference ref = JavaScriptMethods.makeCtorReference(cls.getReference());
JavaScriptSummary S = new JavaScriptSummary(ref, 2);
S.addStatement(insts.GetInstruction(S.getNumberOfStatements(), 5, 1, "prototype"));
S.getNextProgramCounter();
S.addStatement(insts.NewInstruction(S.getNumberOfStatements(), 6, NewSiteReference.make(S.getNextProgramCounter(), cls.getReference())));
S.addStatement(insts.SetPrototype(S.getNumberOfStatements(), 6, 5));
//S.addStatement(insts.PutInstruction(6, 5, "__proto__"));
S.getNextProgramCounter();
S.addStatement(insts.PutInstruction(S.getNumberOfStatements(), 6, 2, "$value"));
S.getNextProgramCounter();
S.addStatement(insts.ReturnInstruction(S.getNumberOfStatements(), 6, false));
S.getNextProgramCounter();
//S.addConstant(7, new ConstantValue("__proto__"));
return new JavaScriptConstructor(ref, S, cls, cls);
}
private IMethod makeValueConstructor(IClass cls, int nargs, Object value) {
if (nargs == 0 || nargs == 1) {
Object key = Pair.make(cls, new Integer(nargs));
if (constructors.containsKey(key))
return constructors.get(key);
else
return record(key, (nargs == 0) ? makeNullaryValueConstructor(cls, value) : makeUnaryValueConstructor(cls));
} else {
// not a legal call, likely due to dataflow imprecision
return null;
}
}
/**
* create a method for constructing an Object with no arguments passed
*/
private IMethod makeNullaryObjectConstructor(IClass cls) {
JSInstructionFactory insts = (JSInstructionFactory)cls.getClassLoader().getInstructionFactory();
MethodReference ref = JavaScriptMethods.makeCtorReference(JavaScriptTypes.Object);
JavaScriptSummary S = new JavaScriptSummary(ref, 1);
S.addStatement(insts.GetInstruction(S.getNumberOfStatements(), 4, 1, "prototype"));
S.getNextProgramCounter();
S.addStatement(insts.NewInstruction(S.getNumberOfStatements(), 5, NewSiteReference.make(S.getNextProgramCounter(), JavaScriptTypes.Object)));
S.addStatement(insts.SetPrototype(S.getNumberOfStatements(), 5, 4));
//S.addStatement(insts.PutInstruction(5, 4, "__proto__"));
S.getNextProgramCounter();
S.addStatement(insts.ReturnInstruction(S.getNumberOfStatements(), 5, false));
S.getNextProgramCounter();
//S.addConstant(6, new ConstantValue("__proto__"));
return new JavaScriptConstructor(ref, S, cls, cha.lookupClass(JavaScriptTypes.Object));
}
private IMethod makeUnaryObjectConstructor(IClass cls) {
JSInstructionFactory insts = (JSInstructionFactory)cls.getClassLoader().getInstructionFactory();
MethodReference ref = JavaScriptMethods.makeCtorReference(JavaScriptTypes.Object);
JavaScriptSummary S = new JavaScriptSummary(ref, 2);
S.addStatement(insts.ReturnInstruction(S.getNumberOfStatements(), 2, false));
S.getNextProgramCounter();
return new JavaScriptConstructor(ref, S, cls, cha.lookupClass(JavaScriptTypes.Object));
}
private IMethod makeObjectConstructor(IClass cls, int nargs) {
if (nargs == 0 || nargs == 1) {
Object key = Pair.make(cls, new Integer(nargs));
if (constructors.containsKey(key))
return constructors.get(key);
else
return record(key, (nargs == 0) ? makeNullaryObjectConstructor(cls) : makeUnaryObjectConstructor(cls));
} else {
// not a legal call, likely the result of analysis imprecision
return null;
}
}
private IMethod makeObjectCall(IClass cls, int nargs) {
assert nargs == 0;
Object key = Pair.make(cls, new Integer(nargs));
if (constructors.containsKey(key))
return constructors.get(key);
else
return record(key, makeNullaryObjectConstructor(cls));
}
private IMethod makeArrayLengthConstructor(IClass cls) {
JSInstructionFactory insts = (JSInstructionFactory)cls.getClassLoader().getInstructionFactory();
MethodReference ref = JavaScriptMethods.makeCtorReference(JavaScriptTypes.Array);
JavaScriptSummary S = new JavaScriptSummary(ref, 2);
S.addStatement(insts.GetInstruction(S.getNumberOfStatements(), 5, 1, "prototype"));
S.getNextProgramCounter();
S.addStatement(insts.NewInstruction(S.getNumberOfStatements(), 6, NewSiteReference.make(S.getNextProgramCounter(), JavaScriptTypes.Array)));
S.addStatement(insts.SetPrototype(S.getNumberOfStatements(), 6, 5));
//S.addStatement(insts.PutInstruction(6, 5, "__proto__"));
S.getNextProgramCounter();
S.addStatement(insts.PutInstruction(S.getNumberOfStatements(), 6, 2, "length"));
S.getNextProgramCounter();
S.addStatement(insts.ReturnInstruction(S.getNumberOfStatements(), 6, false));
S.getNextProgramCounter();
//S.addConstant(7, new ConstantValue("__proto__"));
return new JavaScriptConstructor(ref, S, cls, cha.lookupClass(JavaScriptTypes.Array));
}
private IMethod makeArrayContentsConstructor(IClass cls, int nargs) {
JSInstructionFactory insts = (JSInstructionFactory)cls.getClassLoader().getInstructionFactory();
MethodReference ref = JavaScriptMethods.makeCtorReference(JavaScriptTypes.Array);
JavaScriptSummary S = new JavaScriptSummary(ref, nargs + 1);
S.addConstant(new Integer(nargs + 3), new ConstantValue("prototype"));
S.addStatement(insts.PropertyRead(S.getNumberOfStatements(), nargs + 4, 1, nargs + 3));
S.getNextProgramCounter();
S.addStatement(
insts.NewInstruction(S.getNumberOfStatements(), nargs + 5, NewSiteReference.make(S.getNextProgramCounter(),
JavaScriptTypes.Array)));
S.addStatement(insts.SetPrototype(S.getNumberOfStatements(), nargs + 5, nargs + 4));
//S.addStatement(insts.PutInstruction(nargs + 5, nargs + 4, "__proto__"));
S.getNextProgramCounter();
S.addConstant(new Integer(nargs + 7), new ConstantValue(nargs));
S.addStatement(insts.PutInstruction(S.getNumberOfStatements(), nargs + 5, nargs + 7, "length"));
S.getNextProgramCounter();
int vn = nargs + 9;
for (int i = 0; i < nargs; i++, vn += 2) {
S.addConstant(new Integer(vn), new ConstantValue(i));
S.addStatement(insts.PropertyWrite(S.getNumberOfStatements(), nargs + 5, vn, i + 1));
S.getNextProgramCounter();
}
S.addStatement(insts.ReturnInstruction(S.getNumberOfStatements(), 5, false));
S.getNextProgramCounter();
//S.addConstant(vn, new ConstantValue("__proto__"));
return new JavaScriptConstructor(ref, S, cls, cha.lookupClass(JavaScriptTypes.Array));
}
private IMethod makeArrayConstructor(IClass cls, int nargs) {
Object key = Pair.make(cls, new Integer(nargs));
if (constructors.containsKey(key))
return constructors.get(key);
else
return record(key, (nargs == 1) ? makeArrayLengthConstructor(cls) : makeArrayContentsConstructor(cls, nargs));
}
private IMethod makeNullaryStringCall(IClass cls) {
JSInstructionFactory insts = (JSInstructionFactory)cls.getClassLoader().getInstructionFactory();
MethodReference ref = AstMethodReference.fnReference(JavaScriptTypes.String);
JavaScriptSummary S = new JavaScriptSummary(ref, 1);
S.addConstant(new Integer(2), new ConstantValue(""));
S.addStatement(insts.ReturnInstruction(S.getNumberOfStatements(), 2, false));
S.getNextProgramCounter();
return new JavaScriptConstructor(ref, S, cls, cha.lookupClass(JavaScriptTypes.String));
}
private IMethod makeUnaryStringCall(IClass cls) {
JSInstructionFactory insts = (JSInstructionFactory)cls.getClassLoader().getInstructionFactory();
MethodReference ref = AstMethodReference.fnReference(JavaScriptTypes.String);
JavaScriptSummary S = new JavaScriptSummary(ref, 2);
S.addStatement(insts.GetInstruction(S.getNumberOfStatements(), 4, 2, "toString"));
S.getNextProgramCounter();
CallSiteReference cs = new JSCallSiteReference(S.getNextProgramCounter());
S.addStatement(insts.Invoke(4, 5, new int[] { 2 }, 6, cs));
S.addStatement(insts.ReturnInstruction(S.getNumberOfStatements(), 5, false));
S.getNextProgramCounter();
return new JavaScriptConstructor(ref, S, cls, cha.lookupClass(JavaScriptTypes.String));
}
private IMethod makeStringCall(IClass cls, int nargs) {
assert nargs == 0 || nargs == 1;
Object key = Pair.make(cls, new Integer(nargs));
if (constructors.containsKey(key))
return constructors.get(key);
else
return record(key, (nargs == 0) ? makeNullaryStringCall(cls) : makeUnaryStringCall(cls));
}
private IMethod makeNullaryNumberCall(IClass cls) {
JSInstructionFactory insts = (JSInstructionFactory)cls.getClassLoader().getInstructionFactory();
MethodReference ref = AstMethodReference.fnReference(JavaScriptTypes.Number);
JavaScriptSummary S = new JavaScriptSummary(ref, 1);
S.addConstant(new Integer(2), new ConstantValue(0.0));
S.addStatement(insts.ReturnInstruction(S.getNumberOfStatements(), 2, false));
S.getNextProgramCounter();
return new JavaScriptConstructor(ref, S, cls, cha.lookupClass(JavaScriptTypes.Number));
}
private IMethod makeUnaryNumberCall(IClass cls) {
JSInstructionFactory insts = (JSInstructionFactory)cls.getClassLoader().getInstructionFactory();
MethodReference ref = AstMethodReference.fnReference(JavaScriptTypes.Number);
JavaScriptSummary S = new JavaScriptSummary(ref, 2);
S.addStatement(insts.GetInstruction(S.getNumberOfStatements(), 4, 2, "toNumber"));
S.getNextProgramCounter();
CallSiteReference cs = new JSCallSiteReference(S.getNextProgramCounter());
S.addStatement(insts.Invoke(S.getNumberOfStatements(), 4, 5, new int[] { 2 }, 6, cs));
S.addStatement(insts.ReturnInstruction(S.getNumberOfStatements(), 5, false));
S.getNextProgramCounter();
return new JavaScriptConstructor(ref, S, cls, cha.lookupClass(JavaScriptTypes.Number));
}
private IMethod makeNumberCall(IClass cls, int nargs) {
assert nargs == 0 || nargs == 1;
Object key = Pair.make(cls, new Integer(nargs));
if (constructors.containsKey(key))
return constructors.get(key);
else
return record(key, (nargs == 0) ? makeNullaryNumberCall(cls) : makeUnaryNumberCall(cls));
}
private IMethod makeFunctionConstructor(IClass receiver, IClass cls) {
JSInstructionFactory insts = (JSInstructionFactory)cls.getClassLoader().getInstructionFactory();
Pair<IClass, IClass> tableKey = Pair.make(receiver, cls);
if (constructors.containsKey(tableKey))
return constructors.get(tableKey);
MethodReference ref = JavaScriptMethods.makeCtorReference(receiver.getReference());
JavaScriptSummary S = new JavaScriptSummary(ref, 1);
S.addStatement(insts.GetInstruction(S.getNumberOfStatements(), 4, 1, "prototype"));
S.getNextProgramCounter();
S.addStatement(insts.NewInstruction(S.getNumberOfStatements(), 5, NewSiteReference.make(S.getNextProgramCounter(), cls.getReference())));
S.addStatement(insts.NewInstruction(S.getNumberOfStatements(), 7, NewSiteReference.make(S.getNextProgramCounter(), JavaScriptTypes.Object)));
S.addStatement(insts.SetPrototype(S.getNumberOfStatements(), 5, 4));
//S.addStatement(insts.PutInstruction(5, 4, "__proto__"));
S.getNextProgramCounter();
S.addStatement(insts.PutInstruction(S.getNumberOfStatements(), 5, 7, "prototype"));
S.getNextProgramCounter();
S.addStatement(insts.PutInstruction(S.getNumberOfStatements(), 7, 5, "constructor"));
S.getNextProgramCounter();
// TODO we need to set v7.__proto__ to Object.prototype
S.addStatement(insts.ReturnInstruction(S.getNumberOfStatements(), 5, false));
S.getNextProgramCounter();
//S.addConstant(8, new ConstantValue("__proto__"));
if (receiver != cls)
return record(tableKey, new JavaScriptConstructor(ref, S, receiver, cls, "(" + cls.getReference().getName() + ")"));
else
return record(tableKey, new JavaScriptConstructor(ref, S, receiver, cls));
}
private int ctorCount = 0;
private IMethod makeFunctionConstructor(IR callerIR, SSAAbstractInvokeInstruction callStmt, IClass cls, int nargs) {
SymbolTable ST = callerIR.getSymbolTable();
if (nargs == 0) {
return makeFunctionConstructor(cls, cls);
} else if (nargs == 1) {
if (ST.isStringConstant(callStmt.getUse(1))) {
TypeReference ref = TypeReference.findOrCreate(JavaScriptTypes.jsLoader, TypeName.string2TypeName(ST
.getStringValue(callStmt.getUse(1))));
if (DEBUG) {
System.err.println(("ctor type name is " + ST.getStringValue(callStmt.getUse(1))));
}
IClass cls2 = cha.lookupClass(ref);
if (cls2 != null) {
return makeFunctionConstructor(cls, cls2);
}
}
return makeFunctionConstructor(cls, cls);
} else {
assert nargs > 1;
JavaScriptLoader cl = (JavaScriptLoader) cha.getLoader(JavaScriptTypes.jsLoader);
for (int i = 1; i < callStmt.getNumberOfUses(); i++)
if (!ST.isStringConstant(callStmt.getUse(i)))
return makeFunctionConstructor(cls, cls);
StringBuffer fun = new StringBuffer("function _fromctor (");
for (int j = 1; j < callStmt.getNumberOfUses() - 1; j++) {
if (j != 1)
fun.append(",");
fun.append(ST.getStringValue(callStmt.getUse(j)));
}
fun.append(") {");
fun.append(ST.getStringValue(callStmt.getUse(callStmt.getNumberOfUses() - 1)));
fun.append("}");
try {
String fileName = "ctor$" + ++ctorCount;
File f = new File(System.getProperty("java.io.tmpdir") + File.separator + fileName);
FileWriter FO = new FileWriter(f);
FO.write(fun.toString());
FO.close();
Set<String> fnNames = JSCallGraphUtil.loadAdditionalFile(cha, cl, fileName, f.toURI().toURL());
IClass fcls = null;
for(String nm : fnNames) {
if (nm.endsWith("_fromctor")) {
fcls = cl.lookupClass(nm, cha);
}
}
assert fcls != null : "cannot find class for " + fileName + " in " + f;
f.delete();
if (DEBUG)
System.err.println(("looking for ctor " + ctorCount + " and got " + fcls));
if (fcls != null)
return makeFunctionConstructor(cls, fcls);
} catch (IOException e) {
}
return makeFunctionConstructor(cls, cls);
}
}
private IMethod makeFunctionObjectConstructor(IClass cls, int nargs) {
JSInstructionFactory insts = (JSInstructionFactory)cls.getClassLoader().getInstructionFactory();
Object key = Pair.make(cls, new Integer(nargs));
if (constructors.containsKey(key))
return constructors.get(key);
MethodReference ref = JavaScriptMethods.makeCtorReference(cls.getReference());
JavaScriptSummary S = new JavaScriptSummary(ref, nargs + 1);
S.addStatement(insts.GetInstruction(S.getNumberOfStatements(), nargs + 4, 1, "prototype"));
S.getNextProgramCounter();
S.addStatement(
insts.NewInstruction(S.getNumberOfStatements(), nargs + 5,
NewSiteReference.make(S.getNextProgramCounter(),
JavaScriptTypes.Object)));
S.addStatement(insts.SetPrototype(S.getNumberOfStatements(), nargs + 5, nargs + 4));
//S.addStatement(insts.PutInstruction(nargs + 5, nargs + 4, "__proto__"));
S.getNextProgramCounter();
CallSiteReference cs = new JSCallSiteReference(S.getNextProgramCounter());
int[] args = new int[nargs + 1];
args[0] = nargs + 5;
for (int i = 0; i < nargs; i++)
args[i + 1] = i + 2;
S.addStatement(insts.Invoke(1, nargs + 7, args, nargs + 8, cs));
S.addStatement(insts.ReturnInstruction(S.getNumberOfStatements(), nargs + 7, false));
S.getNextProgramCounter();
S.addStatement(insts.ReturnInstruction(S.getNumberOfStatements(), nargs + 5, false));
S.getNextProgramCounter();
//S.addConstant(nargs + 9, new ConstantValue("__proto__"));
return record(key, new JavaScriptConstructor(ref, S, cls, cls));
}
private IMethod findOrCreateConstructorMethod(IR callerIR, SSAAbstractInvokeInstruction callStmt, IClass receiver, int nargs) {
if (receiver.getReference().equals(JavaScriptTypes.Object))
return makeObjectConstructor(receiver, nargs);
else if (receiver.getReference().equals(JavaScriptTypes.Array))
return makeArrayConstructor(receiver, nargs);
else if (receiver.getReference().equals(JavaScriptTypes.StringObject))
return makeValueConstructor(receiver, nargs, "");
else if (receiver.getReference().equals(JavaScriptTypes.BooleanObject)) {
assert nargs == 1;
return makeValueConstructor(receiver, nargs, null);
} else if (receiver.getReference().equals(JavaScriptTypes.NumberObject))
return makeValueConstructor(receiver, nargs, new Integer(0));
else if (receiver.getReference().equals(JavaScriptTypes.Function))
return makeFunctionConstructor(callerIR, callStmt, receiver, nargs);
else if (cha.isSubclassOf(receiver, cha.lookupClass(JavaScriptTypes.CodeBody)))
return makeFunctionObjectConstructor(receiver, nargs);
else {
return null;
}
}
@SuppressWarnings("unused")
private IMethod findOrCreateCallMethod(IR callerIR, SSAAbstractInvokeInstruction callStmt, IClass receiver, int nargs) {
if (receiver.getReference().equals(JavaScriptTypes.Object))
return makeObjectCall(receiver, nargs);
else if (receiver.getReference().equals(JavaScriptTypes.Array))
return makeArrayConstructor(receiver, nargs);
else if (receiver.getReference().equals(JavaScriptTypes.StringObject))
return makeStringCall(receiver, nargs);
else if (receiver.getReference().equals(JavaScriptTypes.NumberObject))
return makeNumberCall(receiver, nargs);
else if (receiver.getReference().equals(JavaScriptTypes.Function))
return makeFunctionConstructor(callerIR, callStmt, receiver, nargs);
else {
return null;
}
public JavaScriptConstructTargetSelector(JavaScriptConstructorFunctions constructors, MethodTargetSelector base) {
this.constructors = constructors;
this.base = base;
}
@Override
public IMethod getCalleeTarget(CGNode caller, CallSiteReference site, IClass receiver) {
if (site.getDeclaredTarget().equals(JavaScriptMethods.ctorReference)) {
assert cha.isSubclassOf(receiver, cha.lookupClass(JavaScriptTypes.Root));
IR callerIR = caller.getIR();
SSAAbstractInvokeInstruction callStmts[] = callerIR.getCalls(site);
assert callStmts.length == 1;
int nargs = callStmts[0].getNumberOfParameters();
return findOrCreateConstructorMethod(callerIR, callStmts[0], receiver, nargs - 1);
return constructors.findOrCreateConstructorMethod(callerIR, callStmts[0], receiver, nargs - 1);
} else {
return base.getCalleeTarget(caller, site, receiver);
}

View File

@ -11,7 +11,7 @@
package com.ibm.wala.cast.js.ipa.callgraph;
import com.ibm.wala.cast.ir.translator.AstTranslator.AstLexicalInformation;
import com.ibm.wala.cast.js.ipa.callgraph.JavaScriptConstructTargetSelector.JavaScriptConstructor;
import com.ibm.wala.cast.js.ipa.summaries.JavaScriptConstructorFunctions.JavaScriptConstructor;
import com.ibm.wala.classLoader.CallSiteReference;
import com.ibm.wala.classLoader.IMethod;
import com.ibm.wala.ipa.callgraph.CGNode;

View File

@ -10,6 +10,7 @@
*******************************************************************************/
package com.ibm.wala.cast.js.ipa.callgraph;
import com.ibm.wala.cast.js.ipa.summaries.JavaScriptConstructorFunctions.JavaScriptConstructor;
import com.ibm.wala.classLoader.NewSiteReference;
import com.ibm.wala.classLoader.ProgramCounter;
import com.ibm.wala.ipa.callgraph.CGNode;
@ -28,7 +29,7 @@ public class JavaScriptConstructorInstanceKeys implements InstanceKeyFactory {
@Override
public InstanceKey getInstanceKeyForAllocation(CGNode node, NewSiteReference allocation) {
if (node.getMethod() instanceof JavaScriptConstructTargetSelector.JavaScriptConstructor) {
if (node.getMethod() instanceof JavaScriptConstructor) {
InstanceKey bk = base.getInstanceKeyForAllocation(node, allocation);
return new NormalAllocationInNode(node, allocation, bk.getConcreteType());
} else {

View File

@ -219,6 +219,9 @@ public class PropertyNameContextSelector implements ContextSelector {
// use a MarkerForInContext to clone based on the InstanceKey used in the caller context
// TODO the cast below isn't safe; fix
InstanceKey callerIk = ((PropNameContext)caller.getContext()).getInstanceKey();
if (caller.toString().contains("_mixin_for_each_fn")) {
System.err.println(callerIk + "@" + site);
}
return new MarkerForInContext(baseContext, callerIk);
} else {
return baseContext;

View File

@ -12,7 +12,7 @@ package com.ibm.wala.cast.js.ipa.callgraph;
import com.ibm.wala.analysis.reflection.InstanceKeyWithNode;
import com.ibm.wala.cast.ipa.callgraph.ScopeMappingInstanceKeys.ScopeMappingInstanceKey;
import com.ibm.wala.cast.js.ipa.callgraph.JavaScriptConstructTargetSelector.JavaScriptConstructor;
import com.ibm.wala.cast.js.ipa.summaries.JavaScriptConstructorFunctions.JavaScriptConstructor;
import com.ibm.wala.classLoader.CallSiteReference;
import com.ibm.wala.classLoader.IMethod;
import com.ibm.wala.ipa.callgraph.CGNode;

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

@ -13,7 +13,6 @@ package com.ibm.wala.cast.js.ipa.callgraph.correlations.extraction;
import static com.ibm.wala.cast.tree.CAstNode.ASSIGN;
import static com.ibm.wala.cast.tree.CAstNode.BINARY_EXPR;
import static com.ibm.wala.cast.tree.CAstNode.BLOCK_EXPR;
import static com.ibm.wala.cast.tree.CAstNode.BLOCK_STMT;
import static com.ibm.wala.cast.tree.CAstNode.CALL;
import static com.ibm.wala.cast.tree.CAstNode.CONSTANT;
@ -296,16 +295,16 @@ public class ClosureExtractor extends CAstRewriterExt {
epos.addGotoTarget(root.getChildCount() > 0 ? (String)root.getChild(0).getValue(): null, target);
int label = labeller.addNode(target);
// return { type: 'goto', target: <label> }
CAstNode newNode =
Ast.makeNode(RETURN,
Ast.makeNode(OBJECT_LITERAL,
addExnFlow(Ast.makeNode(CALL,
addExnFlow(makeVarRef("Object"), JavaScriptTypes.ReferenceError, getCurrentEntity(), context),
Ast.makeConstant("ctor")), null, getCurrentEntity(), context),
Ast.makeConstant("type"),
Ast.makeConstant("goto"),
Ast.makeConstant("target"),
Ast.makeConstant(((double)label)+"")));
CAstNode returnLit = Ast.makeNode(OBJECT_LITERAL,
addExnFlow(Ast.makeNode(CALL,
addExnFlow(makeVarRef("Object"), JavaScriptTypes.ReferenceError, getCurrentEntity(), context),
Ast.makeConstant("ctor")), null, getCurrentEntity(), context),
Ast.makeConstant("type"),
Ast.makeConstant("goto"),
Ast.makeConstant("target"),
Ast.makeConstant(((double)label)+""));
addNode(returnLit, getCurrentEntity().getControlFlow());
CAstNode newNode = Ast.makeNode(RETURN, returnLit);
// remove outgoing cfg edges of the old node
deleteFlow(root, getCurrentEntity());
nodeMap.put(Pair.make(root, context.key()), newNode);
@ -454,14 +453,18 @@ public class ClosureExtractor extends CAstRewriterExt {
CAstNode[] before = new CAstNode[tler.getStartInner()];
for(i=0;i<tler.getStartInner();++i)
before[i] = copyNodes(start.getChild(i), cfg, context, nodeMap);
prologue.add(Ast.makeNode(BLOCK_STMT, before));
for(int x = 0; x < before.length; x++) {
prologue.add(before[x]);
}
if(i+1 == start.getChildCount()) {
fun_body_stmts.add(addSpuriousExnFlow(start.getChild(i), cfg));
} else {
CAstNode[] after = new CAstNode[start.getChildCount()-i];
for(int j=0;j+i<start.getChildCount();++j)
after[j] = addSpuriousExnFlow(start.getChild(j+i), cfg);
fun_body_stmts.add(Ast.makeNode(BLOCK_EXPR, after));
for(int x = 0; x < after.length; x++) {
fun_body_stmts.add(after[x]);
}
}
for(i=context.getStart()+1;i<context.getEnd();++i)
fun_body_stmts.add(root.getChild(i));
@ -511,12 +514,16 @@ public class ClosureExtractor extends CAstRewriterExt {
// prepend declaration "var <theLocal>;"
CAstNode theLocalDecl = Ast.makeNode(DECL_STMT, Ast.makeConstant(new CAstSymbolImpl(theLocal, JSAstTranslator.Any)),
addExnFlow(makeVarRef("$$undefined"), JavaScriptTypes.ReferenceError, entity, context));
if(fun_body_stmts.size() > 1) {
CAstNode newBlock = Ast.makeNode(BLOCK_STMT, fun_body_stmts.toArray(new CAstNode[0]));
fun_body_stmts.clear();
fun_body_stmts.add(newBlock);
}
fun_body_stmts.add(0, Ast.makeNode(BLOCK_STMT, theLocalDecl));
// fun_body_stmts.add(0, Ast.makeNode(BLOCK_STMT, theLocalDecl));
fun_body_stmts.add(0, theLocalDecl);
}
CAstNode fun_body = Ast.makeNode(BLOCK_STMT, fun_body_stmts.toArray(new CAstNode[0]));
@ -621,10 +628,13 @@ public class ClosureExtractor extends CAstRewriterExt {
addExnFlow(makeVarRef("re$"), JavaScriptTypes.ReferenceError, entity, context),
Ast.makeNode(LOCAL_SCOPE, wrapIn(BLOCK_STMT, fixup == null ? Ast.makeNode(EMPTY) : fixup)));
stmts.add(Ast.makeNode(BLOCK_STMT, decl, fixup));
stmts.add(decl);
stmts.add(fixup);
} else if(theLocal != null) {
// assign final value of the localised variable back
stmts.add(Ast.makeNode(CAstNode.ASSIGN, addExnFlow(makeVarRef(theLocal), JavaScriptTypes.ReferenceError, entity, context), call));
stmts.add(Ast.makeNode(CAstNode.ASSIGN,
addExnFlow(makeVarRef(theLocal), JavaScriptTypes.ReferenceError, entity, context),
call));
} else {
stmts.add(call);
}

View File

@ -50,7 +50,7 @@ import com.ibm.wala.util.collections.Pair;
*
*/
public class CorrelatedPairExtractionPolicy extends ExtractionPolicy {
private static final boolean DEBUG = false;
private static final boolean DEBUG = true;
private final Map<CAstNode, List<ExtractionRegion>> region_map = HashMapFactory.make();
private CorrelatedPairExtractionPolicy() {}
@ -68,7 +68,8 @@ public class CorrelatedPairExtractionPolicy extends ExtractionPolicy {
if(pos.getLastLine() >= 0 && ndpos.getFirstLine() > pos.getLastLine())
return;
if(node.getKind() == kind && ndpos.getFirstLine() == pos.getFirstLine() && ndpos.getLastLine() == pos.getLastLine())
//if(node.getKind() == kind && ndpos.getFirstLine() == pos.getFirstLine() && ndpos.getLastLine() == pos.getLastLine())
if(node.getKind() == kind && ndpos.getFirstOffset() == pos.getFirstOffset() && ndpos.getLastOffset() == pos.getLastOffset())
res.add(nodep);
}
for(int i=0;i<node.getChildCount();++i)
@ -101,7 +102,7 @@ public class CorrelatedPairExtractionPolicy extends ExtractionPolicy {
return true;
startNodes = findNodesAtPos(CAstNode.OBJECT_REF, startPos, entity);
if(corr instanceof ReadWriteCorrelation) {
endNodes = findNodesAtPos(CAstNode.OBJECT_REF, endPos, entity);
endNodes = findNodesAtPos(CAstNode.ASSIGN, endPos, entity);
} else if(corr instanceof EscapeCorrelation) {
int arity = ((EscapeCorrelation)corr).getNumberOfArguments();
endNodes = findNodesAtPos(CAstNode.CALL, endPos, entity);
@ -116,7 +117,7 @@ public class CorrelatedPairExtractionPolicy extends ExtractionPolicy {
}
if(startNodes.isEmpty() || endNodes.isEmpty()) {
if(DEBUG)
System.err.println("Couldn't find any start/end nodes for correlation " + corr.pp(correlations.getPositions()));
System.err.println("Couldn't find any " + (startNodes.isEmpty()? endNodes.isEmpty()? "boundary": "start": "end") + " nodes for correlation " + corr.pp(correlations.getPositions()));
return true;
}
ChildPos startNode, endNode;

View File

@ -0,0 +1,163 @@
package com.ibm.wala.cast.js.ipa.modref;
import java.util.Collection;
import java.util.Iterator;
import com.ibm.wala.cast.ipa.callgraph.AstHeapModel;
import com.ibm.wala.cast.ipa.modref.AstModRef;
import com.ibm.wala.cast.js.ssa.JSInstructionVisitor;
import com.ibm.wala.cast.js.ssa.JavaScriptCheckReference;
import com.ibm.wala.cast.js.ssa.JavaScriptInstanceOf;
import com.ibm.wala.cast.js.ssa.JavaScriptInvoke;
import com.ibm.wala.cast.js.ssa.JavaScriptPropertyRead;
import com.ibm.wala.cast.js.ssa.JavaScriptPropertyWrite;
import com.ibm.wala.cast.js.ssa.JavaScriptTypeOfInstruction;
import com.ibm.wala.cast.js.ssa.JavaScriptWithRegion;
import com.ibm.wala.cast.js.ssa.PrototypeLookup;
import com.ibm.wala.cast.js.ssa.SetPrototype;
import com.ibm.wala.ipa.callgraph.CGNode;
import com.ibm.wala.ipa.callgraph.propagation.InstanceKey;
import com.ibm.wala.ipa.callgraph.propagation.PointerAnalysis;
import com.ibm.wala.ipa.callgraph.propagation.PointerKey;
import com.ibm.wala.ipa.modref.ExtendedHeapModel;
public class JavaScriptModRef extends AstModRef {
protected static class JavaScriptRefVisitor extends AstRefVisitor implements JSInstructionVisitor {
protected JavaScriptRefVisitor(CGNode n, Collection<PointerKey> result, PointerAnalysis<InstanceKey> pa, ExtendedHeapModel h) {
super(n, result, pa, (AstHeapModel)h);
}
@Override
public void visitJavaScriptInvoke(JavaScriptInvoke instruction) {
// do nothing
}
@Override
public void visitTypeOf(JavaScriptTypeOfInstruction instruction) {
// do nothing
}
@Override
public void visitJavaScriptPropertyRead(JavaScriptPropertyRead instruction) {
PointerKey obj = h.getPointerKeyForLocal(n, instruction.getObjectRef());
PointerKey prop = h.getPointerKeyForLocal(n, instruction.getMemberRef());
for(InstanceKey o : pa.getPointsToSet(obj)) {
for(InstanceKey p : pa.getPointsToSet(prop)) {
for(Iterator<PointerKey> keys = h.getPointerKeysForReflectedFieldRead(o, p); keys.hasNext(); ) {
PointerKey x = keys.next();
assert x != null : instruction;
result.add(x);
}
}
}
}
@Override
public void visitJavaScriptPropertyWrite(JavaScriptPropertyWrite instruction) {
// do nothing
}
@Override
public void visitJavaScriptInstanceOf(JavaScriptInstanceOf instruction) {
// do nothing
}
@Override
public void visitWithRegion(JavaScriptWithRegion instruction) {
// do nothing
}
@Override
public void visitCheckRef(JavaScriptCheckReference instruction) {
// do nothing
}
@Override
public void visitSetPrototype(SetPrototype instruction) {
// do nothing
}
@Override
public void visitPrototypeLookup(PrototypeLookup instruction) {
// TODO Auto-generated method stub
}
}
@Override
protected RefVisitor makeRefVisitor(CGNode n, Collection<PointerKey> result, PointerAnalysis<InstanceKey> pa, ExtendedHeapModel h) {
return new JavaScriptRefVisitor(n, result, pa, h);
}
protected static class JavaScriptModVisitor extends AstModVisitor implements JSInstructionVisitor {
protected JavaScriptModVisitor(CGNode n, Collection<PointerKey> result, ExtendedHeapModel h, PointerAnalysis pa) {
super(n, result, (AstHeapModel)h, pa);
}
@Override
public void visitJavaScriptInvoke(JavaScriptInvoke instruction) {
// do nothing
}
@Override
public void visitTypeOf(JavaScriptTypeOfInstruction instruction) {
// do nothing
}
@Override
public void visitJavaScriptPropertyRead(JavaScriptPropertyRead instruction) {
// do nothing
}
@Override
public void visitJavaScriptPropertyWrite(JavaScriptPropertyWrite instruction) {
PointerKey obj = h.getPointerKeyForLocal(n, instruction.getObjectRef());
PointerKey prop = h.getPointerKeyForLocal(n, instruction.getMemberRef());
for(InstanceKey o : pa.getPointsToSet(obj)) {
for(InstanceKey p : pa.getPointsToSet(prop)) {
for(Iterator<PointerKey> keys = h.getPointerKeysForReflectedFieldWrite(o, p); keys.hasNext(); ) {
PointerKey x = keys.next();
assert x != null : instruction;
result.add(x);
}
}
}
}
@Override
public void visitJavaScriptInstanceOf(JavaScriptInstanceOf instruction) {
// do nothing
}
@Override
public void visitWithRegion(JavaScriptWithRegion instruction) {
// do nothing
}
@Override
public void visitCheckRef(JavaScriptCheckReference instruction) {
// do nothing
}
@Override
public void visitSetPrototype(SetPrototype instruction) {
// TODO Auto-generated method stub
}
@Override
public void visitPrototypeLookup(PrototypeLookup instruction) {
// do nothing
}
}
@Override
protected ModVisitor makeModVisitor(CGNode n, Collection<PointerKey> result, PointerAnalysis<InstanceKey> pa, ExtendedHeapModel h, boolean ignoreAllocHeapDefs) {
return new JavaScriptModVisitor(n, result, h, pa);
}
}

View File

@ -0,0 +1,537 @@
package com.ibm.wala.cast.js.ipa.summaries;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.util.Map;
import java.util.Set;
import com.ibm.wala.cast.js.ipa.callgraph.JSCallGraphUtil;
import com.ibm.wala.cast.js.loader.JSCallSiteReference;
import com.ibm.wala.cast.js.loader.JavaScriptLoader;
import com.ibm.wala.cast.js.ssa.JSInstructionFactory;
import com.ibm.wala.cast.js.types.JavaScriptMethods;
import com.ibm.wala.cast.js.types.JavaScriptTypes;
import com.ibm.wala.cast.types.AstMethodReference;
import com.ibm.wala.classLoader.CallSiteReference;
import com.ibm.wala.classLoader.IClass;
import com.ibm.wala.classLoader.IMethod;
import com.ibm.wala.classLoader.NewSiteReference;
import com.ibm.wala.ipa.cha.IClassHierarchy;
import com.ibm.wala.ipa.summaries.MethodSummary;
import com.ibm.wala.shrikeBT.IConditionalBranchInstruction.IOperator;
import com.ibm.wala.shrikeBT.IConditionalBranchInstruction.Operator;
import com.ibm.wala.ssa.ConstantValue;
import com.ibm.wala.ssa.IR;
import com.ibm.wala.ssa.SSAAbstractInvokeInstruction;
import com.ibm.wala.ssa.SymbolTable;
import com.ibm.wala.types.MethodReference;
import com.ibm.wala.types.TypeName;
import com.ibm.wala.types.TypeReference;
import com.ibm.wala.util.collections.HashMapFactory;
import com.ibm.wala.util.collections.Pair;
public class JavaScriptConstructorFunctions {
private final Map<Object, IMethod> constructors = HashMapFactory.make();
private final IClassHierarchy cha;
public JavaScriptConstructorFunctions(IClassHierarchy cha) {
this.cha = cha;
}
public static class JavaScriptConstructor extends JavaScriptSummarizedFunction {
private final String toStringExtra;
private final IClass constructorForType;
private JavaScriptConstructor(MethodReference ref, MethodSummary summary, IClass declaringClass, IClass constructorForType, String toStringExtra) {
super(ref, summary, declaringClass);
this.toStringExtra = toStringExtra;
this.constructorForType = constructorForType;
}
private JavaScriptConstructor(MethodReference ref, MethodSummary summary, IClass declaringClass, IClass constructorForType) {
this(ref, summary, declaringClass, constructorForType, "");
}
@Override
public String toString() {
return "<ctor for " + getReference().getDeclaringClass() + toStringExtra + ">";
}
public IClass constructedType() {
return constructorForType;
}
}
private IMethod record(Object key, IMethod m) {
constructors.put(key, m);
return m;
}
private IMethod makeNullaryValueConstructor(IClass cls, Object value) {
JSInstructionFactory insts = (JSInstructionFactory)cls.getClassLoader().getInstructionFactory();
MethodReference ref = JavaScriptMethods.makeCtorReference(cls.getReference());
JavaScriptSummary S = new JavaScriptSummary(ref, 1);
S.addStatement(insts.GetInstruction(S.getNumberOfStatements(), 4, 1, "prototype"));
S.getNextProgramCounter();
S.addStatement(insts.NewInstruction(S.getNumberOfStatements(), 5, NewSiteReference.make(S.getNextProgramCounter(), cls.getReference())));
S.addStatement(insts.SetPrototype(S.getNumberOfStatements(), 5, 4));
//S.addStatement(insts.PutInstruction(5, 4, "__proto__"));
S.getNextProgramCounter();
S.addConstant(new Integer(8), new ConstantValue(value));
S.addStatement(insts.PutInstruction(S.getNumberOfStatements(), 5, 8, "$value"));
S.getNextProgramCounter();
S.addStatement(insts.ReturnInstruction(S.getNumberOfStatements(), 5, false));
S.getNextProgramCounter();
//S.addConstant(9, new ConstantValue("__proto__"));
return new JavaScriptConstructor(ref, S, cls, cls);
}
private IMethod makeUnaryValueConstructor(IClass cls) {
JSInstructionFactory insts = (JSInstructionFactory)cls.getClassLoader().getInstructionFactory();
MethodReference ref = JavaScriptMethods.makeCtorReference(cls.getReference());
JavaScriptSummary S = new JavaScriptSummary(ref, 2);
S.addStatement(insts.GetInstruction(S.getNumberOfStatements(), 5, 1, "prototype"));
S.getNextProgramCounter();
S.addStatement(insts.NewInstruction(S.getNumberOfStatements(), 6, NewSiteReference.make(S.getNextProgramCounter(), cls.getReference())));
S.addStatement(insts.SetPrototype(S.getNumberOfStatements(), 6, 5));
//S.addStatement(insts.PutInstruction(6, 5, "__proto__"));
S.getNextProgramCounter();
S.addStatement(insts.PutInstruction(S.getNumberOfStatements(), 6, 2, "$value"));
S.getNextProgramCounter();
S.addStatement(insts.ReturnInstruction(S.getNumberOfStatements(), 6, false));
S.getNextProgramCounter();
//S.addConstant(7, new ConstantValue("__proto__"));
return new JavaScriptConstructor(ref, S, cls, cls);
}
private IMethod makeValueConstructor(IClass cls, int nargs, Object value) {
if (nargs == 0 || nargs == 1) {
Object key = Pair.make(cls, new Integer(nargs));
if (constructors.containsKey(key))
return constructors.get(key);
else
return record(key, (nargs == 0) ? makeNullaryValueConstructor(cls, value) : makeUnaryValueConstructor(cls));
} else {
// not a legal call, likely due to dataflow imprecision
return null;
}
}
/**
* create a method for constructing an Object with no arguments passed
*/
private IMethod makeNullaryObjectConstructor(IClass cls) {
JSInstructionFactory insts = (JSInstructionFactory)cls.getClassLoader().getInstructionFactory();
MethodReference ref = JavaScriptMethods.makeCtorReference(JavaScriptTypes.Object);
JavaScriptSummary S = new JavaScriptSummary(ref, 1);
S.addStatement(insts.GetInstruction(S.getNumberOfStatements(), 4, 1, "prototype"));
S.getNextProgramCounter();
S.addStatement(insts.NewInstruction(S.getNumberOfStatements(), 5, NewSiteReference.make(S.getNextProgramCounter(), JavaScriptTypes.Object)));
S.addStatement(insts.SetPrototype(S.getNumberOfStatements(), 5, 4));
//S.addStatement(insts.PutInstruction(5, 4, "__proto__"));
S.getNextProgramCounter();
S.addStatement(insts.ReturnInstruction(S.getNumberOfStatements(), 5, false));
S.getNextProgramCounter();
//S.addConstant(6, new ConstantValue("__proto__"));
return new JavaScriptConstructor(ref, S, cls, cha.lookupClass(JavaScriptTypes.Object));
}
private IMethod makeUnaryObjectConstructor(IClass cls) {
JSInstructionFactory insts = (JSInstructionFactory)cls.getClassLoader().getInstructionFactory();
MethodReference ref = JavaScriptMethods.makeCtorReference(JavaScriptTypes.Object);
JavaScriptSummary S = new JavaScriptSummary(ref, 2);
S.addStatement(insts.ReturnInstruction(S.getNumberOfStatements(), 2, false));
S.getNextProgramCounter();
return new JavaScriptConstructor(ref, S, cls, cha.lookupClass(JavaScriptTypes.Object));
}
private IMethod makeObjectConstructor(IClass cls, int nargs) {
if (nargs == 0 || nargs == 1) {
Object key = Pair.make(cls, new Integer(nargs));
if (constructors.containsKey(key))
return constructors.get(key);
else
return record(key, (nargs == 0) ? makeNullaryObjectConstructor(cls) : makeUnaryObjectConstructor(cls));
} else {
// not a legal call, likely the result of analysis imprecision
return null;
}
}
private IMethod makeObjectCall(IClass cls, int nargs) {
assert nargs == 0;
Object key = Pair.make(cls, new Integer(nargs));
if (constructors.containsKey(key))
return constructors.get(key);
else
return record(key, makeNullaryObjectConstructor(cls));
}
private IMethod makeArrayLengthConstructor(IClass cls) {
JSInstructionFactory insts = (JSInstructionFactory)cls.getClassLoader().getInstructionFactory();
MethodReference ref = JavaScriptMethods.makeCtorReference(JavaScriptTypes.Array);
JavaScriptSummary S = new JavaScriptSummary(ref, 2);
S.addStatement(insts.GetInstruction(S.getNumberOfStatements(), 5, 1, "prototype"));
S.getNextProgramCounter();
S.addStatement(insts.NewInstruction(S.getNumberOfStatements(), 6, NewSiteReference.make(S.getNextProgramCounter(), JavaScriptTypes.Array)));
S.addStatement(insts.SetPrototype(S.getNumberOfStatements(), 6, 5));
//S.addStatement(insts.PutInstruction(6, 5, "__proto__"));
S.getNextProgramCounter();
S.addStatement(insts.PutInstruction(S.getNumberOfStatements(), 6, 2, "length"));
S.getNextProgramCounter();
S.addStatement(insts.ReturnInstruction(S.getNumberOfStatements(), 6, false));
S.getNextProgramCounter();
//S.addConstant(7, new ConstantValue("__proto__"));
return new JavaScriptConstructor(ref, S, cls, cha.lookupClass(JavaScriptTypes.Array));
}
private IMethod makeArrayContentsConstructor(IClass cls, int nargs) {
JSInstructionFactory insts = (JSInstructionFactory)cls.getClassLoader().getInstructionFactory();
MethodReference ref = JavaScriptMethods.makeCtorReference(JavaScriptTypes.Array);
JavaScriptSummary S = new JavaScriptSummary(ref, nargs + 1);
S.addConstant(new Integer(nargs + 3), new ConstantValue("prototype"));
S.addStatement(insts.PropertyRead(S.getNumberOfStatements(), nargs + 4, 1, nargs + 3));
S.getNextProgramCounter();
S.addStatement(
insts.NewInstruction(S.getNumberOfStatements(), nargs + 5, NewSiteReference.make(S.getNextProgramCounter(),
JavaScriptTypes.Array)));
S.addStatement(insts.SetPrototype(S.getNumberOfStatements(), nargs + 5, nargs + 4));
//S.addStatement(insts.PutInstruction(nargs + 5, nargs + 4, "__proto__"));
S.getNextProgramCounter();
S.addConstant(new Integer(nargs + 7), new ConstantValue(nargs));
S.addStatement(insts.PutInstruction(S.getNumberOfStatements(), nargs + 5, nargs + 7, "length"));
S.getNextProgramCounter();
int vn = nargs + 9;
for (int i = 0; i < nargs; i++, vn += 2) {
S.addConstant(new Integer(vn), new ConstantValue(i));
S.addStatement(insts.PropertyWrite(S.getNumberOfStatements(), nargs + 5, vn, i + 1));
S.getNextProgramCounter();
}
S.addStatement(insts.ReturnInstruction(S.getNumberOfStatements(), 5, false));
S.getNextProgramCounter();
//S.addConstant(vn, new ConstantValue("__proto__"));
return new JavaScriptConstructor(ref, S, cls, cha.lookupClass(JavaScriptTypes.Array));
}
private IMethod makeArrayConstructor(IClass cls, int nargs) {
Object key = Pair.make(cls, new Integer(nargs));
if (constructors.containsKey(key))
return constructors.get(key);
else
return record(key, (nargs == 1) ? makeArrayLengthConstructor(cls) : makeArrayContentsConstructor(cls, nargs));
}
private IMethod makeNullaryStringCall(IClass cls) {
JSInstructionFactory insts = (JSInstructionFactory)cls.getClassLoader().getInstructionFactory();
MethodReference ref = AstMethodReference.fnReference(JavaScriptTypes.String);
JavaScriptSummary S = new JavaScriptSummary(ref, 1);
S.addConstant(new Integer(2), new ConstantValue(""));
S.addStatement(insts.ReturnInstruction(S.getNumberOfStatements(), 2, false));
S.getNextProgramCounter();
return new JavaScriptConstructor(ref, S, cls, cha.lookupClass(JavaScriptTypes.String));
}
private IMethod makeUnaryStringCall(IClass cls) {
JSInstructionFactory insts = (JSInstructionFactory)cls.getClassLoader().getInstructionFactory();
MethodReference ref = AstMethodReference.fnReference(JavaScriptTypes.String);
JavaScriptSummary S = new JavaScriptSummary(ref, 2);
S.addStatement(insts.GetInstruction(S.getNumberOfStatements(), 4, 2, "toString"));
S.getNextProgramCounter();
CallSiteReference cs = new JSCallSiteReference(S.getNextProgramCounter());
S.addStatement(insts.Invoke(4, 5, new int[] { 2 }, 6, cs));
S.addStatement(insts.ReturnInstruction(S.getNumberOfStatements(), 5, false));
S.getNextProgramCounter();
return new JavaScriptConstructor(ref, S, cls, cha.lookupClass(JavaScriptTypes.String));
}
private IMethod makeStringCall(IClass cls, int nargs) {
assert nargs == 0 || nargs == 1;
Object key = Pair.make(cls, new Integer(nargs));
if (constructors.containsKey(key))
return constructors.get(key);
else
return record(key, (nargs == 0) ? makeNullaryStringCall(cls) : makeUnaryStringCall(cls));
}
private IMethod makeNullaryNumberCall(IClass cls) {
JSInstructionFactory insts = (JSInstructionFactory)cls.getClassLoader().getInstructionFactory();
MethodReference ref = AstMethodReference.fnReference(JavaScriptTypes.Number);
JavaScriptSummary S = new JavaScriptSummary(ref, 1);
S.addConstant(new Integer(2), new ConstantValue(0.0));
S.addStatement(insts.ReturnInstruction(S.getNumberOfStatements(), 2, false));
S.getNextProgramCounter();
return new JavaScriptConstructor(ref, S, cls, cha.lookupClass(JavaScriptTypes.Number));
}
private IMethod makeUnaryNumberCall(IClass cls) {
JSInstructionFactory insts = (JSInstructionFactory)cls.getClassLoader().getInstructionFactory();
MethodReference ref = AstMethodReference.fnReference(JavaScriptTypes.Number);
JavaScriptSummary S = new JavaScriptSummary(ref, 2);
S.addStatement(insts.GetInstruction(S.getNumberOfStatements(), 4, 2, "toNumber"));
S.getNextProgramCounter();
CallSiteReference cs = new JSCallSiteReference(S.getNextProgramCounter());
S.addStatement(insts.Invoke(4, 5, new int[] { 2 }, 6, cs));
S.addStatement(insts.ReturnInstruction(S.getNumberOfStatements(), 5, false));
S.getNextProgramCounter();
return new JavaScriptConstructor(ref, S, cls, cha.lookupClass(JavaScriptTypes.Number));
}
private IMethod makeNumberCall(IClass cls, int nargs) {
assert nargs == 0 || nargs == 1;
Object key = Pair.make(cls, new Integer(nargs));
if (constructors.containsKey(key))
return constructors.get(key);
else
return record(key, (nargs == 0) ? makeNullaryNumberCall(cls) : makeUnaryNumberCall(cls));
}
private IMethod makeFunctionConstructor(IClass receiver, IClass cls) {
JSInstructionFactory insts = (JSInstructionFactory)cls.getClassLoader().getInstructionFactory();
Pair<IClass, IClass> tableKey = Pair.make(receiver, cls);
if (constructors.containsKey(tableKey))
return constructors.get(tableKey);
MethodReference ref = JavaScriptMethods.makeCtorReference(receiver.getReference());
JavaScriptSummary S = new JavaScriptSummary(ref, 1);
S.addStatement(insts.GetInstruction(S.getNumberOfStatements(), 4, 1, "prototype"));
S.getNextProgramCounter();
S.addStatement(insts.NewInstruction(S.getNumberOfStatements(), 5, NewSiteReference.make(S.getNextProgramCounter(), cls.getReference())));
S.addStatement(insts.NewInstruction(S.getNumberOfStatements(), 7, NewSiteReference.make(S.getNextProgramCounter(), JavaScriptTypes.Object)));
S.addStatement(insts.SetPrototype(S.getNumberOfStatements(), 5, 4));
//S.addStatement(insts.PutInstruction(5, 4, "__proto__"));
S.getNextProgramCounter();
S.addStatement(insts.PutInstruction(S.getNumberOfStatements(), 5, 7, "prototype"));
S.getNextProgramCounter();
S.addStatement(insts.PutInstruction(S.getNumberOfStatements(), 7, 5, "constructor"));
S.getNextProgramCounter();
// TODO we need to set v7.__proto__ to Object.prototype
S.addStatement(insts.ReturnInstruction(S.getNumberOfStatements(), 5, false));
S.getNextProgramCounter();
//S.addConstant(8, new ConstantValue("__proto__"));
if (receiver != cls)
return record(tableKey, new JavaScriptConstructor(ref, S, receiver, cls, "(" + cls.getReference().getName() + ")"));
else
return record(tableKey, new JavaScriptConstructor(ref, S, receiver, cls));
}
private int ctorCount = 0;
private IMethod makeFunctionConstructor(IR callerIR, SSAAbstractInvokeInstruction callStmt, IClass cls, int nargs) {
SymbolTable ST = callerIR.getSymbolTable();
if (nargs == 0) {
return makeFunctionConstructor(cls, cls);
} else if (nargs == 1) {
if (ST.isStringConstant(callStmt.getUse(1))) {
TypeReference ref = TypeReference.findOrCreate(JavaScriptTypes.jsLoader, TypeName.string2TypeName(ST
.getStringValue(callStmt.getUse(1))));
IClass cls2 = cha.lookupClass(ref);
if (cls2 != null) {
return makeFunctionConstructor(cls, cls2);
}
}
return makeFunctionConstructor(cls, cls);
} else {
assert nargs > 1;
JavaScriptLoader cl = (JavaScriptLoader) cha.getLoader(JavaScriptTypes.jsLoader);
for (int i = 1; i < callStmt.getNumberOfUses(); i++)
if (!ST.isStringConstant(callStmt.getUse(i)))
return makeFunctionConstructor(cls, cls);
StringBuffer fun = new StringBuffer("function _fromctor (");
for (int j = 1; j < callStmt.getNumberOfUses() - 1; j++) {
if (j != 1)
fun.append(",");
fun.append(ST.getStringValue(callStmt.getUse(j)));
}
fun.append(") {");
fun.append(ST.getStringValue(callStmt.getUse(callStmt.getNumberOfUses() - 1)));
fun.append("}");
try {
String fileName = "ctor$" + ++ctorCount;
File f = new File(System.getProperty("java.io.tmpdir") + File.separator + fileName);
FileWriter FO = new FileWriter(f);
FO.write(fun.toString());
FO.close();
Set<String> fnNames = JSCallGraphUtil.loadAdditionalFile(cha, cl, fileName, f.toURI().toURL());
IClass fcls = null;
for(String nm : fnNames) {
if (nm.endsWith("_fromctor")) {
fcls = cl.lookupClass(nm, cha);
}
}
assert fcls != null : "cannot find class for " + fileName + " in " + f;
f.delete();
if (fcls != null)
return makeFunctionConstructor(cls, fcls);
} catch (IOException e) {
}
return makeFunctionConstructor(cls, cls);
}
}
private IMethod makeFunctionObjectConstructor(IClass cls, int nargs) {
JSInstructionFactory insts = (JSInstructionFactory)cls.getClassLoader().getInstructionFactory();
Object key = Pair.make(cls, new Integer(nargs));
if (constructors.containsKey(key))
return constructors.get(key);
MethodReference ref = JavaScriptMethods.makeCtorReference(cls.getReference());
JavaScriptSummary S = new JavaScriptSummary(ref, nargs + 1);
S.addStatement(insts.GetInstruction(S.getNumberOfStatements(), nargs + 4, 1, "prototype"));
S.getNextProgramCounter();
S.addStatement(
insts.NewInstruction(S.getNumberOfStatements(), nargs + 5,
NewSiteReference.make(S.getNextProgramCounter(),
JavaScriptTypes.Object)));
S.addStatement(insts.SetPrototype(S.getNumberOfStatements(), nargs + 5, nargs + 4));
S.getNextProgramCounter();
CallSiteReference cs = new JSCallSiteReference(S.getNextProgramCounter());
int[] args = new int[nargs + 1];
args[0] = nargs + 5;
for (int i = 0; i < nargs; i++)
args[i + 1] = i + 2;
S.addStatement(insts.Invoke(1, nargs + 7, args, nargs + 8, cs));
int pc = S.getNextProgramCounter();
S.addConstant(nargs + 9, null);
S.addStatement(insts.ConditionalBranchInstruction(S.getNumberOfStatements(), Operator.EQ, JavaScriptTypes.Root, nargs + 7, nargs + 9, pc+2));
S.getNextProgramCounter();
S.addStatement(insts.ReturnInstruction(S.getNumberOfStatements(), nargs + 7, false));
S.getNextProgramCounter();
S.addStatement(insts.ReturnInstruction(S.getNumberOfStatements(), nargs + 5, false));
S.getNextProgramCounter();
return record(key, new JavaScriptConstructor(ref, S, cls, cls));
}
public IMethod findOrCreateConstructorMethod(IR callerIR, SSAAbstractInvokeInstruction callStmt, IClass receiver, int nargs) {
if (receiver.getReference().equals(JavaScriptTypes.Object))
return makeObjectConstructor(receiver, nargs);
else if (receiver.getReference().equals(JavaScriptTypes.Array))
return makeArrayConstructor(receiver, nargs);
else if (receiver.getReference().equals(JavaScriptTypes.StringObject))
return makeValueConstructor(receiver, nargs, "");
else if (receiver.getReference().equals(JavaScriptTypes.BooleanObject)) {
assert nargs == 1;
return makeValueConstructor(receiver, nargs, null);
} else if (receiver.getReference().equals(JavaScriptTypes.NumberObject))
return makeValueConstructor(receiver, nargs, new Integer(0));
else if (receiver.getReference().equals(JavaScriptTypes.Function))
return makeFunctionConstructor(callerIR, callStmt, receiver, nargs);
else if (cha.isSubclassOf(receiver, cha.lookupClass(JavaScriptTypes.CodeBody)))
return makeFunctionObjectConstructor(receiver, nargs);
else {
return null;
}
}
public IMethod findOrCreateCallMethod(IR callerIR, SSAAbstractInvokeInstruction callStmt, IClass receiver, int nargs) {
if (receiver.getReference().equals(JavaScriptTypes.Object))
return makeObjectCall(receiver, nargs);
else if (receiver.getReference().equals(JavaScriptTypes.Array))
return makeArrayConstructor(receiver, nargs);
else if (receiver.getReference().equals(JavaScriptTypes.StringObject))
return makeStringCall(receiver, nargs);
else if (receiver.getReference().equals(JavaScriptTypes.NumberObject))
return makeNumberCall(receiver, nargs);
else if (receiver.getReference().equals(JavaScriptTypes.Function))
return makeFunctionConstructor(callerIR, callStmt, receiver, nargs);
else {
return null;
}
}
}

View File

@ -420,9 +420,9 @@ public class JavaScriptLoader extends CAstAbstractModuleLoader {
}
@Override
public SSAConditionalBranchInstruction ConditionalBranchInstruction(int iindex,
com.ibm.wala.shrikeBT.IConditionalBranchInstruction.IOperator operator, TypeReference type, int val1, int val2) {
return new SSAConditionalBranchInstruction(iindex, operator, type, val1, val2);
public SSAConditionalBranchInstruction ConditionalBranchInstruction(int iindex,
com.ibm.wala.shrikeBT.IConditionalBranchInstruction.IOperator operator, TypeReference type, int val1, int val2, int target) {
return new SSAConditionalBranchInstruction(iindex, operator, type, val1, val2, target);
}
@Override
@ -462,8 +462,8 @@ public class JavaScriptLoader extends CAstAbstractModuleLoader {
}
@Override
public SSAGotoInstruction GotoInstruction(int iindex) {
return new SSAGotoInstruction(iindex);
public SSAGotoInstruction GotoInstruction(int iindex, int target) {
return new SSAGotoInstruction(iindex, target);
}
@Override

View File

@ -10,7 +10,6 @@
*****************************************************************************/
package com.ibm.wala.cast.js.translator;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Map;
@ -36,7 +35,6 @@ import com.ibm.wala.cfg.AbstractCFG;
import com.ibm.wala.cfg.IBasicBlock;
import com.ibm.wala.classLoader.NewSiteReference;
import com.ibm.wala.ssa.SSAInstruction;
import com.ibm.wala.ssa.SSAInstructionFactory;
import com.ibm.wala.ssa.SymbolTable;
import com.ibm.wala.types.FieldReference;
import com.ibm.wala.types.MethodReference;
@ -261,17 +259,15 @@ public class JSAstTranslator extends AstTranslator {
context.cfg().addInstruction(((JSInstructionFactory) insts).PropertyRead(context.cfg().getCurrentInstruction(), result, x, context.getValue(elt)));
}
// generate code to handle read of non-existent property
if (context.getControlFlow().getMappedNodes().contains(readNode)) {
context.cfg().addPreNode(readNode, context.getUnwindState());
// generate code to handle read of property from null or undefined
context.cfg().addPreNode(readNode, context.getUnwindState());
context.cfg().newBlock(true);
context.cfg().newBlock(true);
if (context.getControlFlow().getTarget(readNode, JavaScriptTypes.TypeError) != null)
context.cfg().addPreEdge(readNode, context.getControlFlow().getTarget(readNode, JavaScriptTypes.TypeError), true);
else
context.cfg().addPreEdgeToExit(readNode, true);
}
if (context.getControlFlow().getTarget(readNode, JavaScriptTypes.TypeError) != null)
context.cfg().addPreEdge(readNode, context.getControlFlow().getTarget(readNode, JavaScriptTypes.TypeError), true);
else
context.cfg().addPreEdgeToExit(readNode, true);
}
@Override
@ -296,9 +292,18 @@ public class JSAstTranslator extends AstTranslator {
context.cfg().addInstruction(put);
}
} else {
*/
*/
context.cfg().addInstruction(((JSInstructionFactory) insts).PropertyWrite(context.cfg().getCurrentInstruction(), receiver, context.getValue(elt), rval));
// }
context.cfg().addPreNode(parent, context.getUnwindState());
// generate code to handle read of property from null or undefined
context.cfg().newBlock(true);
if (context.getControlFlow().getTarget(parent, JavaScriptTypes.TypeError) != null)
context.cfg().addPreEdge(parent, context.getControlFlow().getTarget(parent, JavaScriptTypes.TypeError), true);
else
context.cfg().addPreEdgeToExit(parent, true);
// }
}
private void doPrimitiveNew(WalkContext context, int resultVal, String typeName) {
@ -382,9 +387,10 @@ public class JSAstTranslator extends AstTranslator {
if (f.getKind() == CAstNode.CONSTANT && f.getValue() instanceof String) {
String field = (String) f.getValue();
FieldReference fieldRef = FieldReference.findOrCreate(JavaScriptTypes.Root, Atom.findOrCreateUnicodeAtom((String)field), JavaScriptTypes.Root);
context.cfg().addInstruction(((JSInstructionFactory)insts).IsDefinedInstruction(context.cfg().getCurrentInstruction(), result, ref, fieldRef));
FieldReference fieldRef = FieldReference.findOrCreate(JavaScriptTypes.Root, Atom.findOrCreateUnicodeAtom(field),
JavaScriptTypes.Root);
context.cfg().addInstruction(((JSInstructionFactory) insts).IsDefinedInstruction(context.cfg().getCurrentInstruction(), result, ref, fieldRef));
} else {
@ -394,7 +400,7 @@ public class JSAstTranslator extends AstTranslator {
@Override
protected boolean visitInstanceOf(CAstNode n, WalkContext c, CAstVisitor<WalkContext> visitor) {
WalkContext context = (WalkContext) c;
WalkContext context = c;
int result = context.currentScope().allocateTempValue();
context.setValue(n, result);
return false;
@ -402,7 +408,7 @@ public class JSAstTranslator extends AstTranslator {
@Override
protected void leaveInstanceOf(CAstNode n, WalkContext c, CAstVisitor<WalkContext> visitor) {
WalkContext context = (WalkContext) c;
WalkContext context = c;
int result = context.getValue(n);
visit(n.getChild(0), context, visitor);

View File

@ -22,11 +22,29 @@ import com.ibm.wala.core.tests.util.WalaTestCase;
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.SSACFG;
import com.ibm.wala.ssa.SSAInstruction;
import com.ibm.wala.util.collections.NonNullSingletonIterator;
public abstract class TestCallGraphShape extends WalaTestCase {
protected void verifyCFGAssertions(CallGraph CG, Object[][] assertionData) {
for(Object[] dat : assertionData) {
String function = (String) dat[0];
for(CGNode N : getNodes(CG, function)) {
int[][] edges = (int[][]) dat[1];
SSACFG cfg = N.getIR().getControlFlowGraph();
for (int i = 0; i < edges.length; i++) {
SSACFG.BasicBlock bb = cfg.getNode(i);
Assert.assertEquals("basic block " + i, edges[i].length, cfg.getSuccNodeCount(bb));
for (int j = 0; j < edges[i].length; j++) {
Assert.assertTrue(cfg.hasEdge(bb, cfg.getNode(edges[i][j])));
}
}
}
}
}
protected void verifySourceAssertions(CallGraph CG, Object[][] assertionData) {
for(Object[] dat : assertionData) {
String function = (String) dat[0];

View File

@ -0,0 +1,7 @@
package com.ibm.wala.cast.ipa.callgraph;
import com.ibm.wala.ipa.modref.ExtendedHeapModel;
public interface AstHeapModel extends ExtendedHeapModel, AstPointerKeyFactory {
}

View File

@ -44,20 +44,24 @@ import com.ibm.wala.ipa.callgraph.CGNode;
import com.ibm.wala.ipa.callgraph.CallGraph;
import com.ibm.wala.ipa.callgraph.impl.ExplicitCallGraph;
import com.ibm.wala.ipa.callgraph.propagation.AbstractFieldPointerKey;
import com.ibm.wala.ipa.callgraph.propagation.HeapModel;
import com.ibm.wala.ipa.callgraph.propagation.InstanceKey;
import com.ibm.wala.ipa.callgraph.propagation.InstanceKeyFactory;
import com.ibm.wala.ipa.callgraph.propagation.LocalPointerKey;
import com.ibm.wala.ipa.callgraph.propagation.PointerAnalysis;
import com.ibm.wala.ipa.callgraph.propagation.PointerAnalysisImpl;
import com.ibm.wala.ipa.callgraph.propagation.PointerKey;
import com.ibm.wala.ipa.callgraph.propagation.PointerKeyFactory;
import com.ibm.wala.ipa.callgraph.propagation.PointsToMap;
import com.ibm.wala.ipa.callgraph.propagation.PointsToSetVariable;
import com.ibm.wala.ipa.callgraph.propagation.PropagationCallGraphBuilder;
import com.ibm.wala.ipa.callgraph.propagation.PropagationSystem;
import com.ibm.wala.ipa.callgraph.propagation.SSAContextInterpreter;
import com.ibm.wala.ipa.callgraph.propagation.SSAPropagationCallGraphBuilder;
import com.ibm.wala.ipa.callgraph.propagation.cfa.DefaultSSAInterpreter;
import com.ibm.wala.ipa.callgraph.propagation.cfa.DelegatingSSAContextInterpreter;
import com.ibm.wala.ipa.cha.IClassHierarchy;
import com.ibm.wala.ipa.modref.ArrayLengthKey;
import com.ibm.wala.ssa.DefUse;
import com.ibm.wala.ssa.IR;
import com.ibm.wala.ssa.SSAPutInstruction;
@ -107,6 +111,7 @@ public abstract class AstSSAPropagationCallGraphBuilder extends SSAPropagationCa
//
// /////////////////////////////////////////////////////////////////////////
protected AstSSAPropagationCallGraphBuilder(IClassHierarchy cha, AnalysisOptions options, AnalysisCache cache,
PointerKeyFactory pointerKeyFactory) {
super(cha, options, cache, pointerKeyFactory);
@ -132,6 +137,16 @@ public abstract class AstSSAPropagationCallGraphBuilder extends SSAPropagationCa
//
// /////////////////////////////////////////////////////////////////////////
@Override
protected PropagationSystem makeSystem(AnalysisOptions options) {
return new PropagationSystem(callGraph, pointerKeyFactory, instanceKeyFactory) {
@Override
public PointerAnalysis makePointerAnalysis(PropagationCallGraphBuilder builder) {
return new AstPointerAnalysisImpl(builder, cg, pointsToMap, instanceKeys, pointerKeyFactory, instanceKeyFactory);
}
};
}
public static class AstPointerAnalysisImpl extends PointerAnalysisImpl {
public AstPointerAnalysisImpl(PropagationCallGraphBuilder builder, CallGraph cg, PointsToMap pointsToMap,
@ -139,6 +154,34 @@ public abstract class AstSSAPropagationCallGraphBuilder extends SSAPropagationCa
super(builder, cg, pointsToMap, instanceKeys, pointerKeys, iKeyFactory);
}
@Override
protected HeapModel makeHeapModel() {
class Model extends HModel implements AstHeapModel {
@Override
public PointerKey getPointerKeyForArrayLength(InstanceKey I) {
return new ArrayLengthKey(I);
}
@Override
public Iterator<PointerKey> getPointerKeysForReflectedFieldRead(InstanceKey I, InstanceKey F) {
return ((AstPointerKeyFactory)pointerKeys).getPointerKeysForReflectedFieldRead(I, F);
}
@Override
public Iterator<PointerKey> getPointerKeysForReflectedFieldWrite(InstanceKey I, InstanceKey F) {
return ((AstPointerKeyFactory)pointerKeys).getPointerKeysForReflectedFieldWrite(I, F);
}
@Override
public PointerKey getPointerKeyForObjectCatalog(InstanceKey I) {
return ((AstPointerKeyFactory)pointerKeys).getPointerKeyForObjectCatalog(I);
}
}
return new Model();
}
@Override
protected ImplicitPointsToSetVisitor makeImplicitPointsToVisitor(LocalPointerKey lpk) {
return new AstImplicitPointsToSetVisitor(this, lpk);

View File

@ -29,7 +29,6 @@ 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;
/**
* An {@link InstanceKeyFactory} that returns {@link ScopeMappingInstanceKey}s

View File

@ -12,6 +12,7 @@ package com.ibm.wala.cast.ipa.modref;
import java.util.Collection;
import com.ibm.wala.cast.ipa.callgraph.AstHeapModel;
import com.ibm.wala.cast.ir.ssa.AstAssertInstruction;
import com.ibm.wala.cast.ir.ssa.AstEchoInstruction;
import com.ibm.wala.cast.ir.ssa.AstGlobalRead;
@ -31,12 +32,14 @@ import com.ibm.wala.ipa.modref.ModRef;
public class AstModRef extends ModRef {
protected static class AstRefVisitor
extends RefVisitor
implements AstInstructionVisitor
{
@Override
public ExtendedHeapModel makeHeapModel(PointerAnalysis pa) {
return (AstHeapModel)pa.getHeapModel();
}
protected static class AstRefVisitor extends RefVisitor<AstHeapModel> implements AstInstructionVisitor {
protected AstRefVisitor(CGNode n, Collection<PointerKey> result, PointerAnalysis<InstanceKey> pa, ExtendedHeapModel h) {
protected AstRefVisitor(CGNode n, Collection<PointerKey> result, PointerAnalysis<InstanceKey> pa, AstHeapModel h) {
super(n, result, pa, h);
}
@ -88,15 +91,15 @@ public class AstModRef extends ModRef {
@Override
protected RefVisitor makeRefVisitor(CGNode n, Collection<PointerKey> result, PointerAnalysis<InstanceKey> pa, ExtendedHeapModel h) {
return new AstRefVisitor(n, result, pa, h);
return new AstRefVisitor(n, result, pa, (AstHeapModel)h);
}
protected static class AstModVisitor
extends ModVisitor
extends ModVisitor <AstHeapModel>
implements AstInstructionVisitor
{
protected AstModVisitor(CGNode n, Collection<PointerKey> result, ExtendedHeapModel h, PointerAnalysis<InstanceKey> pa) {
protected AstModVisitor(CGNode n, Collection<PointerKey> result, AstHeapModel h, PointerAnalysis<InstanceKey> pa) {
super(n, result, h, pa, true);
}
@ -148,7 +151,7 @@ public class AstModRef extends ModRef {
@Override
protected ModVisitor makeModVisitor(CGNode n, Collection<PointerKey> result, PointerAnalysis<InstanceKey> pa, ExtendedHeapModel h, boolean ignoreAllocHeapDefs) {
return new AstModVisitor(n, result, h, pa);
return new AstModVisitor(n, result, (AstHeapModel)h, pa);
}
}

View File

@ -45,8 +45,9 @@ public abstract class FixedParametersInvokeInstruction
/**
* Constructor InvokeInstruction. This case for void return values
* @param i
* @param params
* @param exception
* @param site
*/
public FixedParametersInvokeInstruction(int iindex, int[] params, int exception, CallSiteReference site) {
this(iindex, null, params, exception, site);

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;
@ -21,6 +22,7 @@ import com.ibm.wala.cast.ir.ssa.analysis.LiveAnalysis;
import com.ibm.wala.cast.loader.AstMethod;
import com.ibm.wala.cast.loader.AstMethod.DebuggingInformation;
import com.ibm.wala.cast.loader.AstMethod.LexicalInformation;
import com.ibm.wala.cast.tree.CAstType.Array;
import com.ibm.wala.ssa.IR.SSA2LocalMap;
import com.ibm.wala.ssa.SSACFG;
import com.ibm.wala.ssa.SSAInstruction;
@ -29,9 +31,11 @@ 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;
import com.ibm.wala.util.intset.IntSetUtil;
import com.ibm.wala.util.intset.MutableIntSet;
/**
@ -63,6 +67,8 @@ public class SSAConversion extends AbstractSSAConversion {
private SSA2LocalMap computedLocalMap;
private Map<Integer,Integer> assignments = HashMapFactory.make();
//
// Copy propagation history
//
@ -81,6 +87,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 +117,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 +137,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 +169,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;
}
@ -237,15 +266,30 @@ public class SSAConversion extends AbstractSSAConversion {
// SSA2LocalMap implementation for SSAConversion
//
private class SSAInformation implements com.ibm.wala.ssa.IR.SSA2LocalMap {
private final String[][] computedNames = new String[valueMap.length][];
@Override
public String[] getLocalNames(int pc, int vn) {
if (computedNames[vn] != null) {
return computedNames[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));
MutableIntSet vals = IntSetUtil.make();
while (assignments.containsKey(v) && !vals.contains(v)) {
vals.add(v);
v = assignments.get(v);
vNames = namesData[v];
x.addAll(Arrays.asList(vNames));
}
return computedNames[vn] = x.toArray(new String[x.size()]);
}
private void undoCopyPropagation(int instructionIndex, int useNumber) {
@ -269,6 +313,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 +437,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) {
@ -404,7 +459,7 @@ public class SSAConversion extends AbstractSSAConversion {
for (int j = 0; j < lexicalUses.length; j++) {
int lexicalUse = lexicalUses[j];
if (lexicalUse != -1 && !skip(lexicalUse)) {
if (S[lexicalUse].isEmpty()) {
if (S.length <= lexicalUse || S[lexicalUse].isEmpty()) {
lexicalUses[j] = -1;
} else {
int newUse = top(lexicalUse);
@ -510,22 +565,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++) {

View File

@ -68,6 +68,7 @@ import com.ibm.wala.shrikeBT.IConditionalBranchInstruction;
import com.ibm.wala.shrikeBT.IUnaryOpInstruction;
import com.ibm.wala.shrikeBT.ShiftInstruction;
import com.ibm.wala.ssa.SSAAbstractInvokeInstruction;
import com.ibm.wala.ssa.SSAConditionalBranchInstruction;
import com.ibm.wala.ssa.SSAGetCaughtExceptionInstruction;
import com.ibm.wala.ssa.SSAGotoInstruction;
import com.ibm.wala.ssa.SSAInstruction;
@ -698,6 +699,7 @@ public abstract class AstTranslator extends CAstVisitor<AstTranslator.WalkContex
* holds the control-flow graph as it is being constructed. When construction
* is complete, information is stored in an {@link AstCFG}
*/
@SuppressWarnings("javadoc")
public final class IncipientCFG extends SparseNumberedGraph<PreBasicBlock> {
protected class Unwind {
@ -751,7 +753,7 @@ public abstract class AstTranslator extends CAstVisitor<AstTranslator.WalkContex
int e = -1;
PreBasicBlock currentBlock = getCurrentBlock();
if (!isDeadBlock(currentBlock)) {
addInstruction(insts.GotoInstruction(currentInstruction));
addInstruction(insts.GotoInstruction(currentInstruction, -1));
newBlock(false);
}
PreBasicBlock startBlock = getCurrentBlock();
@ -795,7 +797,7 @@ public abstract class AstTranslator extends CAstVisitor<AstTranslator.WalkContex
addPreNode(dummy);
doThrow(astContext, e);
} else {
addInstruction(insts.GotoInstruction(currentInstruction));
addInstruction(insts.GotoInstruction(currentInstruction, -1));
}
newBlock(false);
@ -1277,8 +1279,34 @@ public abstract class AstTranslator extends CAstVisitor<AstTranslator.WalkContex
if (ci.getBasicBlockNumber() != blocks.get(i).getNumber()) {
inst = insts.GetCaughtExceptionInstruction(x, blocks.get(i).getNumber(), ci.getException());
}
} else if (inst instanceof SSAGotoInstruction) {
Iterator<PreBasicBlock> succs = this.getNormalSuccessors(blocks.get(i)).iterator();
if (succs.hasNext()) {
PreBasicBlock target = succs.next();
assert !succs.hasNext() : "unexpected successors for block " + blocks.get(i) + ": " + target + " and " + succs.next();
inst = insts.GotoInstruction(x, target.firstIndex);
} else {
// goto to the end of the method, so the instruction is unnecessary
inst = null;
}
} else if (inst instanceof SSAConditionalBranchInstruction) {
Iterator<PreBasicBlock> succs = this.getNormalSuccessors(blocks.get(i)).iterator();
assert succs.hasNext();
int target;
int t1 = succs.next().firstIndex;
if (succs.hasNext()) {
int t2 = succs.next().firstIndex;
if (t1 == x+1) {
target = t2;
} else {
target = t1;
}
} else {
target = t1;
}
SSAConditionalBranchInstruction branch = (SSAConditionalBranchInstruction) inst;
inst = insts.ConditionalBranchInstruction(x, branch.getOperator(), branch.getType(), branch.getUse(0), branch.getUse(1), target);
}
assert inst.iindex == x;
instructions[x++] = inst;
}
}
@ -1756,6 +1784,11 @@ public abstract class AstTranslator extends CAstVisitor<AstTranslator.WalkContex
private final SymbolTable functionSymtab = new SymbolTable(getArgumentCount(f));
@Override
public String toString() {
return "scope for " + f.getName();
}
// ctor for scope object
{
for (int i = 0; i < getArgumentCount(f); i++) {
@ -1969,6 +2002,12 @@ public abstract class AstTranslator extends CAstVisitor<AstTranslator.WalkContex
final Map<String, AbstractSymbol> globalSymbols = new LinkedHashMap<String, AbstractSymbol>();
final Map<String, String> caseInsensitiveNames = new LinkedHashMap<String, String>();
return new Scope() {
@Override
public String toString() {
return "global scope";
}
private final String mapName(String nm) {
String mappedName = caseInsensitiveNames.get(nm.toLowerCase());
return (mappedName == null) ? nm : mappedName;
@ -3273,6 +3312,73 @@ public abstract class AstTranslator extends CAstVisitor<AstTranslator.WalkContex
return new LocalContext(context, makeLocalScope(n, context.currentScope()));
}
@Override
protected WalkContext makeSpecialParentContext(final WalkContext context, CAstNode n) {
final String specialName = (String) n.getChild(0).getValue();
return new LocalContext(context, new AbstractScope(context.currentScope()) {
private Scope parent = null;
private Scope parent() {
if (parent == null) {
parent = ((AbstractScope)context.currentScope()).getEntityScope().getParent();
}
return parent;
}
@Override
public ScopeType type() {
return ScopeType.LOCAL;
}
private Scope scopeFor(String name) {
if (name.equals(specialName)) {
return parent();
} else {
return context.currentScope();
}
}
@Override
public boolean contains(String name) {
return scopeFor(name).contains(name);
}
@Override
public Symbol lookup(String name) {
return scopeFor(name).lookup(name);
}
@Override
protected SymbolTable getUnderlyingSymtab() {
return ((AbstractScope)context.currentScope()).getUnderlyingSymtab();
}
@Override
protected Symbol makeSymbol(String nm, CAstType type, boolean isFinal, boolean isInternalName, Object defaultInitValue,
int vn, Scope parent) {
return ((AbstractScope)context.currentScope()).makeSymbol(nm, type, isFinal, isInternalName, defaultInitValue, vn, parent);
}
@Override
protected AbstractScope getEntityScope() {
return ((AbstractScope)context.currentScope()).getEntityScope();
}
@Override
public boolean isLexicallyScoped(Symbol s) {
return context.currentScope().isLexicallyScoped(s);
}
@Override
public CAstEntity getEntity() {
return context.top();
}
});
}
@Override
protected WalkContext makeUnwindContext(WalkContext context, CAstNode n, CAstVisitor<WalkContext> visitor) {
// here, n represents the "finally" block of the unwind
@ -3328,11 +3434,21 @@ public abstract class AstTranslator extends CAstVisitor<AstTranslator.WalkContex
return false;
}
@Override
protected boolean visitSpecialParentScope(CAstNode n, WalkContext c, CAstVisitor<WalkContext> visitor) { /* empty */
return false;
}
@Override
protected void leaveLocalScope(CAstNode n, WalkContext c, CAstVisitor<WalkContext> visitor) {
c.setValue(n, c.getValue(n.getChild(0)));
}
@Override
protected void leaveSpecialParentScope(CAstNode n, WalkContext c, CAstVisitor<WalkContext> visitor) {
c.setValue(n, c.getValue(n.getChild(1)));
}
@Override
protected boolean visitBlockExpr(CAstNode n, WalkContext c, CAstVisitor<WalkContext> visitor) { /* empty */
return false;
@ -3364,14 +3480,14 @@ public abstract class AstTranslator extends CAstVisitor<AstTranslator.WalkContex
+ " of loop " + CAstPrinter.print(n, context.top().getSourceMap());
context.cfg().addInstruction(
insts.ConditionalBranchInstruction(context.cfg().currentInstruction, translateConditionOpcode(CAstOperator.OP_EQ), null, c.getValue(n.getChild(0)), context
.currentScope().getConstantValue(new Integer(0))));
.currentScope().getConstantValue(new Integer(0)), -1));
PreBasicBlock branchB = context.cfg().getCurrentBlock();
// loop body
context.cfg().newBlock(true);
visitor.visit(n.getChild(1), context, visitor);
if (!context.cfg().isDeadBlock(context.cfg().getCurrentBlock())) {
context.cfg().addInstruction(insts.GotoInstruction(context.cfg().currentInstruction));
context.cfg().addInstruction(insts.GotoInstruction(context.cfg().currentInstruction, -1));
PreBasicBlock bodyB = context.cfg().getCurrentBlock();
context.cfg().addEdge(bodyB, headerB);
@ -3640,11 +3756,11 @@ public abstract class AstTranslator extends CAstVisitor<AstTranslator.WalkContex
if (n.getChildCount() == 1) {
context.cfg().addInstruction(
insts.ConditionalBranchInstruction(context.cfg().currentInstruction, translateConditionOpcode(CAstOperator.OP_NE), null, c.getValue(n.getChild(0)), context
.currentScope().getConstantValue(new Integer(0))));
.currentScope().getConstantValue(new Integer(0)), -1));
} else if (n.getChildCount() == 3) {
context.cfg().addInstruction(
insts.ConditionalBranchInstruction(context.cfg().currentInstruction, translateConditionOpcode(n.getChild(0)), null, c.getValue(n.getChild(1)),
c.getValue(n.getChild(2))));
c.getValue(n.getChild(2)), -1));
} else {
Assertions.UNREACHABLE();
}
@ -3665,7 +3781,7 @@ public abstract class AstTranslator extends CAstVisitor<AstTranslator.WalkContex
if (!context.cfg().isDeadBlock(context.cfg().getCurrentBlock())) {
context.cfg().addPreNode(n, context.getUnwindState());
context.cfg().addPreEdge(n, context.getControlFlow().getTarget(n, null), false);
context.cfg().addInstruction(insts.GotoInstruction(context.cfg().currentInstruction));
context.cfg().addInstruction(insts.GotoInstruction(context.cfg().currentInstruction, -1));
if (context.getControlFlow().getTarget(n, null) == null) {
assert context.getControlFlow().getTarget(n, null) != null : context.getControlFlow() + " does not map " + n + " ("
+ context.getSourceMap().getPosition(n) + ")";
@ -3696,7 +3812,7 @@ public abstract class AstTranslator extends CAstVisitor<AstTranslator.WalkContex
visitor.visit(l, context, visitor);
context.cfg().addInstruction(
insts.ConditionalBranchInstruction(context.cfg().currentInstruction, translateConditionOpcode(CAstOperator.OP_EQ), null, c.getValue(l), context.currentScope()
.getConstantValue(new Integer(0))));
.getConstantValue(new Integer(0)), -1));
PreBasicBlock srcB = context.cfg().getCurrentBlock();
// true clause
context.cfg().newBlock(true);
@ -3706,7 +3822,7 @@ public abstract class AstTranslator extends CAstVisitor<AstTranslator.WalkContex
context.cfg().addInstruction(new AssignInstruction(context.cfg().currentInstruction, c.getValue(n), c.getValue(r)));
if (n.getChildCount() == 3) {
if (!context.cfg().isDeadBlock(context.cfg().getCurrentBlock())) {
context.cfg().addInstruction(insts.GotoInstruction(context.cfg().currentInstruction));
context.cfg().addInstruction(insts.GotoInstruction(context.cfg().currentInstruction, -1));
trueB = context.cfg().getCurrentBlock();
// false clause
@ -4097,7 +4213,7 @@ public abstract class AstTranslator extends CAstVisitor<AstTranslator.WalkContex
// PreBasicBlock switchB = context.cfg().getCurrentBlock();
context.cfg().newBlock(true);
context.cfg().addInstruction(insts.GotoInstruction(context.cfg().currentInstruction));
context.cfg().addInstruction(insts.GotoInstruction(context.cfg().currentInstruction, -1));
defaultHackBlock = context.cfg().getCurrentBlock();
context.cfg().newBlock(false);
@ -4141,14 +4257,14 @@ public abstract class AstTranslator extends CAstVisitor<AstTranslator.WalkContex
if (x != CAstControlFlowMap.SWITCH_DEFAULT) {
visitor.visit((CAstNode) x, context, visitor);
context.cfg().addInstruction(
insts.ConditionalBranchInstruction(context.cfg().currentInstruction, translateConditionOpcode(CAstOperator.OP_EQ), null, v, context.getValue((CAstNode) x)));
insts.ConditionalBranchInstruction(context.cfg().currentInstruction, translateConditionOpcode(CAstOperator.OP_EQ), null, v, context.getValue((CAstNode) x), -1));
labelToBlock.put(x, context.cfg().getCurrentBlock());
context.cfg().newBlock(true);
}
}
PreBasicBlock defaultGotoBlock = context.cfg().getCurrentBlock();
context.cfg().addInstruction(insts.GotoInstruction(context.cfg().currentInstruction));
context.cfg().addInstruction(insts.GotoInstruction(context.cfg().currentInstruction, -1));
context.cfg().newBlock(false);
CAstNode switchBody = n.getChild(1);
@ -4294,7 +4410,7 @@ public abstract class AstTranslator extends CAstVisitor<AstTranslator.WalkContex
if (!context.cfg().isDeadBlock(context.cfg().getCurrentBlock())) {
addSkipCatchGoto = true;
context.cfg().addInstruction(insts.GotoInstruction(context.cfg().currentInstruction));
context.cfg().addInstruction(insts.GotoInstruction(context.cfg().currentInstruction, -1));
context.cfg().newBlock(false);
}

View File

@ -10,7 +10,6 @@
*****************************************************************************/
package com.ibm.wala.cast.loader;
import java.io.InputStream;
import java.io.Reader;
import java.net.URL;
import java.util.Collection;

View File

@ -10,7 +10,6 @@
*****************************************************************************/
package com.ibm.wala.cast.loader;
import java.io.InputStream;
import java.io.Reader;
import java.net.URL;
import java.util.Collection;

View File

@ -27,7 +27,6 @@ import com.ibm.wala.cast.tree.CAst;
import com.ibm.wala.cast.tree.CAstEntity;
import com.ibm.wala.cast.tree.impl.CAstImpl;
import com.ibm.wala.cast.util.CAstPrinter;
import com.ibm.wala.classLoader.IClass;
import com.ibm.wala.classLoader.IClassLoader;
import com.ibm.wala.classLoader.Module;
import com.ibm.wala.classLoader.ModuleEntry;

View File

@ -163,6 +163,7 @@ public interface CAstNode {
// explicit lexical scopes
public static final int LOCAL_SCOPE = 200;
public static final int SPECIAL_PARENT_SCOPE = 201;
// literal expression kinds
public static final int CONSTANT = 300;

View File

@ -78,7 +78,7 @@ public class CAstImpl implements CAst {
@Override
public int hashCode() {
int code = getKind() * (getChildCount() + 13);
for (int i = 0; i < getChildCount(); i++) {
for (int i = 0; i < getChildCount() && i < 15; i++) {
code *= getChild(i).getKind();
}

View File

@ -416,7 +416,7 @@ public abstract class CAstVisitor<C extends CAstVisitor.Context> {
*/
public final void visit(final CAstNode n, C context, CAstVisitor<C> visitor) {
Position restore = currentPosition;
if (context.getSourceMap() != null) {
if (context != null && context.getSourceMap() != null) {
Position p = context.getSourceMap().getPosition(n);
if (p != null) {
currentPosition = p;
@ -451,6 +451,15 @@ public abstract class CAstVisitor<C extends CAstVisitor.Context> {
break;
}
case CAstNode.SPECIAL_PARENT_SCOPE: {
if (visitor.visitSpecialParentScope(n, context, visitor))
break;
C localContext = visitor.makeSpecialParentContext(context, n);
visitor.visit(n.getChild(1), localContext, visitor);
visitor.leaveSpecialParentScope(n, context, visitor);
break;
}
case CAstNode.BLOCK_EXPR: {
if (visitor.visitBlockExpr(n, context, visitor))
break;
@ -818,7 +827,7 @@ public abstract class CAstVisitor<C extends CAstVisitor.Context> {
visitor.leaveTypeLiteralExpr(n, context, visitor);
break;
}
case CAstNode.IS_DEFINED_EXPR: {
if (visitor.visitIsDefinedExpr(n, context, visitor)) {
break;
@ -875,6 +884,18 @@ public abstract class CAstVisitor<C extends CAstVisitor.Context> {
currentPosition = restore;
}
protected void leaveSpecialParentScope(CAstNode n, C context, CAstVisitor<C> visitor) {
visitor.leaveNode(n, context, visitor);
}
protected C makeSpecialParentContext(C context, CAstNode n) {
return context;
}
protected boolean visitSpecialParentScope(CAstNode n, C context, CAstVisitor<C> visitor) {
return visitor.visitNode(n, context, visitor);
}
/**
* Process the given array reference node. Factored out so that derived languages can reuse this
* code for specially-marked types of array references (as in X10, for which different instruction

View File

@ -1314,4 +1314,25 @@ public abstract class DelegatingCAstVisitor<C extends CAstVisitor.Context> exten
protected void leaveInstanceOf(CAstNode n, C c, CAstVisitor<C> visitor) {
delegate.leaveInstanceOf(n, c, visitor);
}
/**
* Visit a LocalScope node.
* @param n the node to process
* @param c a visitor-specific context
* @return true if no further processing is needed
*/
@Override
protected boolean visitSpecialParentScope(CAstNode n, C c, CAstVisitor<C> visitor) {
return delegate.visitSpecialParentScope(n, c, visitor);
}
/**
* Leave a LocalScope node.
* @param n the node to process
* @param c a visitor-specific context
*/
@Override
protected void leaveSpecialParentScope(CAstNode n, C c, CAstVisitor<C> visitor) {
delegate.leaveSpecialParentScope(n, c, visitor);
}
}

View File

@ -379,20 +379,7 @@ public class CAstPattern {
}
public static Collection<Segments> findAll(final CAstPattern p, final CAstEntity e) {
final Collection<Segments> result = HashSetFactory.make();
CAstVisitor<Context> v = new CAstVisitor<Context>() {
@Override
public void leaveNode(CAstNode n, Context c, CAstVisitor visitor) {
Segments s = match(p, n);
if (s != null) {
result.add(s);
}
}
};
v.visit(e.getAST(), new Context() {
return p.new Matcher().findAll(new Context() {
@Override
public CAstEntity top() {
return e;
@ -401,11 +388,26 @@ public class CAstPattern {
public CAstSourcePositionMap getSourceMap() {
return e.getSourceMap();
}
}, v);
return result;
}, e.getAST());
}
public class Matcher extends CAstVisitor<Context> {
private final Collection<Segments> result = HashSetFactory.make();
@Override
public void leaveNode(CAstNode n, Context c, CAstVisitor visitor) {
Segments s = match(CAstPattern.this, n);
if (s != null) {
result.add(s);
}
}
public Collection<Segments> findAll(final Context c, final CAstNode top) {
visit(top, c, this);
return result;
}
}
private static class Parser {
private final Map<String, CAstPattern> namedPatterns = HashMapFactory.make();

View File

@ -94,7 +94,8 @@ public class CAstPrinter {
// explicit lexical scopes
case CAstNode.LOCAL_SCOPE: return "SCOPE";
case CAstNode.SPECIAL_PARENT_SCOPE: return "SPECIAL PARENT SCOPE";
// literal expression kinds
case CAstNode.CONSTANT: return "CONSTANT";
case CAstNode.OPERATOR: return "OPERATOR";

View File

@ -12,7 +12,6 @@ package com.ibm.wala.cast.util;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.Reader;
import java.net.URL;
import java.util.ArrayList;

View File

@ -0,0 +1,93 @@
/*******************************************************************************
* Copyright (c) 2006 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 reflection;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
/**
* A test targeting the {@link com.ibm.wala.analysis.reflection.GetMethodContext}.
* @author Michael Heilmann
*/
public class GetMethodContext {
public static class A {
public void foo() {
}
public void bar() {
}
public void baz() {
}
};
public static class B extends A {
@Override
public void foo() {
}
@Override
public void bar() {
}
@Override
public void baz() {
}
};
public static class C extends B {
@Override
public void foo() {
}
@Override
public void bar() {
}
};
public static void main(String[] args) throws IllegalAccessException, NoSuchMethodException, IllegalArgumentException, InvocationTargetException {
Method m;
A a;
a = new B();
// As a points to an instance of GetMethodContext$B:
// Without GetMethodContext, Wala should return GetMethodContext$A#foo() and GetMethodContext$B#foo().
// With GetMethodContext, Wala should return only GetMethodContext$B#foo().
m = a.getClass().getMethod("foo");
m.invoke(a,new Object[]{});
a = new C();
// As a points to an instance of GetMethodContext$C:
// Without GetMethodContext, Wala should return GetMethodContext$C#bar(), GetMethodContext$B#bar() and GetMethodContext$A#bar().
// With GetMethodContext, Wala should return only GetMethodContext$C#bar().
m = a.getClass().getDeclaredMethod("bar");
m.invoke(a,new Object[]{});
// To summarize:
//
// Without GetMethodContext, the call graph must contain
// GetMethodContext$B#foo(),
// GetMethodContext$A#foo(),
// GetMethodContext$C#bar(),
// GetMethodContext$B#bar(), and
// GetMethodContext$A#bar().
//
// With GetMethodContext, the call graph must contain
// GetMethodContext$B#foo() and
// GetMethodContext$C#bar()
// and must not contain
// GetMethodContext$A#foo(),
// GetMethodContext$B#bar(), or
// GetMethodContext$A#bar().
//
// In either case it must not contain:
// GetMethodContext$C#baz(),
// GetMethodContext$C#baz(),
// GetMethodContext$B#baz(), or
// GetMethodContext$A#baz().
}
}

View File

@ -18,9 +18,9 @@
<property name="compilerArg" value="" />
<property name="javacSource" value="1.5" />
<property name="javacTarget" value="1.5" />
<condition property="dir_bootclasspath" value="${java.home}/../Classes">
<!-- <condition property="dir_bootclasspath" value="${java.home}/../Classes">
<os family="mac" />
</condition>
</condition> -->
<property name="dir_bootclasspath" value="${java.home}/lib" />
<path id="path_bootclasspath">
<fileset dir="${dir_bootclasspath}">

View File

@ -33,7 +33,7 @@ import com.ibm.wala.util.intset.MutableMapping;
import com.ibm.wala.util.intset.OrdinalSetMapping;
/**
* Simple Regression test for a graph-based dataflow problem
* Simple Regression test for a graph-based dataflow problem.
*/
public class GraphDataflowTest extends WalaTestCase {
@ -211,7 +211,7 @@ public class GraphDataflowTest extends WalaTestCase {
StringBuffer result = new StringBuffer("------\n");
for (int i = 0; i < nodes.length; i++) {
String n = nodes[i];
BitVectorVariable varI = (BitVectorVariable) solver.getOut(n);
BitVectorVariable varI = solver.getOut(n);
String s = varI.toString();
result.append("Node " + n + "(" + i + ") = " + s + "\n");
}

View File

@ -608,16 +608,16 @@ public class PrimitivesTest extends WalaTestCase {
M.put(I2, I2);
M.put(I3, I3);
Integer I = (Integer) M.get(new Integer(2));
Integer I = M.get(new Integer(2));
Assert.assertTrue(I != null);
Assert.assertTrue(I.equals(I2));
I = (Integer) M.get(new Integer(4));
I = M.get(new Integer(4));
Assert.assertTrue(I == null);
I = (Integer) M.put(new Integer(2), new Integer(3));
I = M.put(new Integer(2), new Integer(3));
Assert.assertTrue(I.equals(I2));
I = (Integer) M.get(I2);
I = M.get(I2);
Assert.assertTrue(I.equals(I3));
}

View File

@ -383,7 +383,7 @@ public class CallGraphTest extends WalaTestCase {
int count = 0;
for (Iterator<BasicBlockInContext<ISSABasicBlock>> it = icfg.iterator(); it.hasNext();) {
BasicBlockInContext<ISSABasicBlock> bb = it.next();
if (icfg.hasCall((BasicBlockInContext<ISSABasicBlock>) bb)) {
if (icfg.hasCall(bb)) {
count++;
}
}
@ -444,7 +444,7 @@ public class CallGraphTest extends WalaTestCase {
}
final Set<MethodReference> nodes = HashSetFactory.make();
for (Iterator<CGNode> nodesI = cg.iterator(); nodesI.hasNext();) {
nodes.add(((CGNode) nodesI.next()).getMethod().getReference());
nodes.add((nodesI.next()).getMethod().getReference());
}
return new Graph<MethodReference>() {

View File

@ -59,7 +59,7 @@ public class ClassConstantTest extends WalaTestCase {
MethodReference mainMethodRef = MethodReference.findOrCreate(mainClassRef, "main", "([Ljava/lang/String;)V");
Set<CGNode> mainMethodNodes = cg.getNodes(mainMethodRef);
Assert.assertFalse(mainMethodNodes.isEmpty());
CGNode mainMethodNode = (CGNode) mainMethodNodes.iterator().next();
CGNode mainMethodNode = mainMethodNodes.iterator().next();
// Trace.println("main IR:");
// Trace.println(mainMethodNode.getIR());

View File

@ -51,12 +51,12 @@ public class CloneTest extends WalaTestCase {
// Find node corresponding to java.text.MessageFormat.clone()
TypeReference t = TypeReference.findOrCreate(ClassLoaderReference.Primordial, "Ljava/text/MessageFormat");
MethodReference m = MethodReference.findOrCreate(t, "clone", "()Ljava/lang/Object;");
CGNode node = (CGNode) cg.getNodes(m).iterator().next();
CGNode node = cg.getNodes(m).iterator().next();
// Check there's exactly one target for each super call in
// MessageFormat.clone()
for (Iterator<CallSiteReference> i = node.iterateCallSites(); i.hasNext();) {
CallSiteReference site = (CallSiteReference) i.next();
CallSiteReference site = i.next();
if (site.isSpecial()) {
if (site.getDeclaredTarget().getDeclaringClass().equals(TypeReference.JavaLangObject)) {
Set<CGNode> targets = cg.getPossibleTargets(node, site);

View File

@ -38,6 +38,7 @@ import com.ibm.wala.ipa.cha.ClassHierarchyException;
import com.ibm.wala.ipa.cha.IClassHierarchy;
import com.ibm.wala.types.ClassLoaderReference;
import com.ibm.wala.types.MethodReference;
import com.ibm.wala.types.Selector;
import com.ibm.wala.types.TypeReference;
import com.ibm.wala.util.CancelException;
import com.ibm.wala.util.WalaException;
@ -94,7 +95,7 @@ public class ReflectionTest extends WalaTestCase {
Warnings.clear();
CallGraphTest.doCallGraphs(options, new AnalysisCache(), cha, scope);
for (Iterator<Warning> it = Warnings.iterator(); it.hasNext();) {
Warning w = (Warning) it.next();
Warning w = it.next();
if (w.toString().indexOf("com/ibm/jvm") > 0) {
continue;
}
@ -281,7 +282,7 @@ public class ReflectionTest extends WalaTestCase {
if (context instanceof ReceiverInstanceContext && node.getMethod().getReference().equals(newInstanceMr)) {
ReceiverInstanceContext r = (ReceiverInstanceContext) context;
ConstantKey<IMethod> c = (ConstantKey<IMethod>) r.getReceiver();
IMethod ctor = (IMethod) c.getValue();
IMethod ctor = c.getValue();
if (ctor.getSignature().equals(fpInitSig)) {
filePermConstrNewInstanceNode = node;
break;
@ -638,4 +639,62 @@ public class ReflectionTest extends WalaTestCase {
Set<CGNode> nodes = cg.getNodes(mr);
Assert.assertFalse(nodes.isEmpty());
}
/**
* Test that when analyzing GetMethodContext, the call graph must contain exactly one call to each of the following methods:
* <ul>
* <li>GetMethodContext$B#foo()</li>
* <li>GetMethodContext$C#bar()</li>
* </ul>
* and must not contain
* <ul>
* <li>GetMethodContext$A#bar()</li>
* <li>GetMethodContext$A#baz()</li>
* <li>GetMethodContext$A#foo()</li>
* <li>GetMethodContext$B#bar()</li>
* <li>GetMethodContext$B#baz()</li>
* <li>GetMethodContext$C#baz()</li>
* <li>GetMethodContext$C#foo()</li>
* </ul>
*/
@Test
public void testGetMethodContext() throws WalaException, IllegalArgumentException, CancelException, IOException {
TypeReference ta = TypeReference.findOrCreate(ClassLoaderReference.Application, "Lreflection/GetMethodContext$A");
TypeReference tb = TypeReference.findOrCreate(ClassLoaderReference.Application, "Lreflection/GetMethodContext$B");
TypeReference tc = TypeReference.findOrCreate(ClassLoaderReference.Application, "Lreflection/GetMethodContext$C");
Selector sfoo = Selector.make("foo()V"),
sbar = Selector.make("bar()V"),
sbaz = Selector.make("baz()V");
MethodReference mafoo = MethodReference.findOrCreate(ta,sfoo),
mbfoo = MethodReference.findOrCreate(tb,sfoo),
mcfoo = MethodReference.findOrCreate(tc,sfoo),
mabar = MethodReference.findOrCreate(ta,sbar),
mbbar = MethodReference.findOrCreate(tb,sbar),
mcbar = MethodReference.findOrCreate(tc,sbar),
mabaz = MethodReference.findOrCreate(ta,sbaz),
mbbaz = MethodReference.findOrCreate(tb,sbaz),
mcbaz = MethodReference.findOrCreate(tc,sbaz);
AnalysisScope scope = findOrCreateAnalysisScope();
IClassHierarchy cha = findOrCreateCHA(scope);
Iterable<Entrypoint> entrypoints = com.ibm.wala.ipa.callgraph.impl.Util.makeMainEntrypoints(scope, cha,
TestConstants.REFLECTGETMETHODCONTEXT_MAIN);
AnalysisOptions options = CallGraphTestUtil.makeAnalysisOptions(scope, entrypoints);
CallGraph cg = CallGraphTestUtil.buildZeroOneCFA(options, new AnalysisCache(), cha, scope, false);
Set<CGNode> cgn;
cgn = cg.getNodes(mabar); Assert.assertTrue(cgn.isEmpty());
cgn = cg.getNodes(mabaz); Assert.assertTrue(cgn.isEmpty());
cgn = cg.getNodes(mafoo); Assert.assertTrue(cgn.isEmpty());
cgn = cg.getNodes(mbbar); Assert.assertTrue(cgn.isEmpty());
cgn = cg.getNodes(mbbaz); Assert.assertTrue(cgn.isEmpty());
cgn = cg.getNodes(mcbaz); Assert.assertTrue(cgn.isEmpty());
cgn = cg.getNodes(mcfoo); Assert.assertTrue(cgn.isEmpty());
cgn = cg.getNodes(mbfoo); Assert.assertTrue(1 == cgn.size());
cgn = cg.getNodes(mcbar); Assert.assertTrue(1 == cgn.size());
}
}

View File

@ -58,11 +58,15 @@ public class DynamicCallGraphTest extends WalaTestCase {
private boolean instrumentedJarBuilt = false;
private static String instrumentedJarLocation = System.getProperty("java.io.tmpdir") + File.separator + "test.jar";
private static String cgLocation = System.getProperty("java.io.tmpdir") + File.separator + "cg.txt";
private void instrument() throws IOException, ClassNotFoundException, InvalidClassFileException, FailureException {
if (! instrumentedJarBuilt) {
System.err.println("core data jar to instrument: " + testJarLocation);
DynamicCallGraph.main(new String[]{testJarLocation, "-o", "/tmp/test.jar"});
Assert.assertTrue("expected to create /tmp/test.jar", new File("/tmp/test.jar").exists());
DynamicCallGraph.main(new String[]{testJarLocation, "-o", instrumentedJarLocation});
Assert.assertTrue("expected to create /tmp/test.jar", new File(instrumentedJarLocation).exists());
instrumentedJarBuilt = true;
}
}
@ -70,14 +74,14 @@ public class DynamicCallGraphTest extends WalaTestCase {
private void run(String exclusionsFile) throws IOException, ClassNotFoundException, SecurityException, NoSuchMethodException, IllegalArgumentException, IllegalAccessException, InvocationTargetException {
String shrikeBin = getClasspathEntry("com.ibm.wala.shrike");
String utilBin = getClasspathEntry("com.ibm.wala.util");
URLClassLoader jcl = new URLClassLoader(new URL[]{ new URL("file:///tmp/test.jar"), new URL("file://" + shrikeBin), new URL("file://" + utilBin) }, DynamicCallGraphTest.class.getClassLoader().getParent());
URLClassLoader jcl = new URLClassLoader(new URL[]{ new URL("file://" + instrumentedJarLocation), new URL("file://" + shrikeBin), new URL("file://" + utilBin) }, DynamicCallGraphTest.class.getClassLoader().getParent());
Class<?> testClass = jcl.loadClass("dynamicCG.MainClass");
Assert.assertNotNull(testClass);
Method testMain = testClass.getDeclaredMethod("main", String[].class);
Assert.assertNotNull(testMain);
System.setProperty("dynamicCGFile", "/tmp/cg.txt");
System.setProperty("dynamicCGFile", cgLocation);
if (exclusionsFile != null) {
File tmpFile = TemporaryFile.urlToFile("exclusions.txt", getClass().getClassLoader().getResource(exclusionsFile));
System.setProperty("dynamicCGFilter", tmpFile.getCanonicalPath());

View File

@ -88,6 +88,8 @@ public interface TestConstants {
public final static String REFLECT23_MAIN = "Lreflection/Reflect23";
public final static String REFLECTGETMETHODCONTEXT_MAIN = "Lreflection/GetMethodContext";
public final static String SLICE1_MAIN = "Lslice/Slice1";
public final static String SLICE2_MAIN = "Lslice/Slice2";

View File

@ -218,7 +218,7 @@ public class SimpleThreadEscapeAnalysis extends AbstractAnalysisEngine {
for (IClass cls : cha) {
Collection<IField> staticFields = cls.getDeclaredStaticFields();
for (Iterator<IField> sfs = staticFields.iterator(); sfs.hasNext();) {
IField sf = (IField) sfs.next();
IField sf = sfs.next();
if (sf.getFieldTypeReference().isReferenceType()) {
escapeAnalysisRoots.add(heapModel.getPointerKeyForStaticField(sf));
}
@ -232,13 +232,13 @@ public class SimpleThreadEscapeAnalysis extends AbstractAnalysisEngine {
// Thread objects must be constructed somewhere)
Collection<IClass> threads = cha.computeSubClasses(TypeReference.JavaLangThread);
for (Iterator<IClass> clss = threads.iterator(); clss.hasNext();) {
IClass cls = (IClass) clss.next();
IClass cls = clss.next();
for (Iterator<IMethod> ms = cls.getDeclaredMethods().iterator(); ms.hasNext();) {
IMethod m = (IMethod) ms.next();
IMethod m = ms.next();
if (m.isInit()) {
Set<CGNode> nodes = cg.getNodes(m.getReference());
for (Iterator<CGNode> ns = nodes.iterator(); ns.hasNext();) {
CGNode n = (CGNode) ns.next();
CGNode n = ns.next();
escapeAnalysisRoots.add(heapModel.getPointerKeyForLocal(n, 1));
}
}
@ -258,7 +258,7 @@ public class SimpleThreadEscapeAnalysis extends AbstractAnalysisEngine {
PointerKey root = rts.next();
OrdinalSet<InstanceKey> objects = pa.getPointsToSet(root);
for (Iterator<InstanceKey> objs = objects.iterator(); objs.hasNext();) {
InstanceKey obj = (InstanceKey) objs.next();
InstanceKey obj = objs.next();
escapingInstanceKeys.add(obj);
}
}
@ -278,7 +278,7 @@ public class SimpleThreadEscapeAnalysis extends AbstractAnalysisEngine {
PointerKey fk = heapModel.getPointerKeyForArrayContents(key);
OrdinalSet<InstanceKey> fobjects = pa.getPointsToSet(fk);
for (Iterator<InstanceKey> fobjs = fobjects.iterator(); fobjs.hasNext();) {
InstanceKey fobj = (InstanceKey) fobjs.next();
InstanceKey fobj = fobjs.next();
if (!escapingInstanceKeys.contains(fobj)) {
newKeys.add(fobj);
}
@ -287,12 +287,12 @@ public class SimpleThreadEscapeAnalysis extends AbstractAnalysisEngine {
} else {
Collection<IField> fields = type.getAllInstanceFields();
for (Iterator<IField> fs = fields.iterator(); fs.hasNext();) {
IField f = (IField) fs.next();
IField f = fs.next();
if (f.getFieldTypeReference().isReferenceType()) {
PointerKey fk = heapModel.getPointerKeyForInstanceField(key, f);
OrdinalSet<InstanceKey> fobjects = pa.getPointsToSet(fk);
for (Iterator<InstanceKey> fobjs = fobjects.iterator(); fobjs.hasNext();) {
InstanceKey fobj = (InstanceKey) fobjs.next();
InstanceKey fobj = fobjs.next();
if (!escapingInstanceKeys.contains(fobj)) {
newKeys.add(fobj);
}
@ -339,7 +339,7 @@ public class SimpleThreadEscapeAnalysis extends AbstractAnalysisEngine {
IClass cls = types.next();
if (!cls.isArrayClass()) {
for (Iterator<IField> fs = cls.getAllFields().iterator(); fs.hasNext();) {
IField f = (IField) fs.next();
IField f = fs.next();
if (!f.isVolatile() && !f.isFinal()) {
System.err.println(f.getReference());
}

View File

@ -124,7 +124,7 @@ public class PDFControlDependenceGraph {
String dotExe = wp.getProperty(WalaExamplesProperties.DOT_EXE);
String gvExe = wp.getProperty(WalaExamplesProperties.PDFVIEW_EXE);
DotUtil.dotify(cdg, PDFViewUtil.makeIRDecorator(ir), dotFile, psFile, dotExe);
DotUtil.<ISSABasicBlock>dotify(cdg, PDFViewUtil.makeIRDecorator(ir), dotFile, psFile, dotExe);
return PDFViewUtil.launchPDFView(psFile, gvExe);

View File

@ -163,8 +163,7 @@ public class PDFSDG {
private static Graph<Statement> pruneSDG(final SDG sdg) {
Filter<Statement> f = new Filter<Statement>() {
@Override
public boolean accepts(Statement o) {
Statement s = (Statement) o;
public boolean accepts(Statement s) {
if (s.getNode().equals(sdg.getCallGraph().getFakeRootNode())) {
return false;
} else if (s instanceof MethodExitStatement || s instanceof MethodEntryStatement) {
@ -177,11 +176,10 @@ public class PDFSDG {
return GraphSlicer.prune(sdg, f);
}
private static NodeDecorator makeNodeDecorator() {
return new NodeDecorator() {
private static NodeDecorator<Statement> makeNodeDecorator() {
return new NodeDecorator<Statement>() {
@Override
public String getLabel(Object o) throws WalaException {
Statement s = (Statement) o;
public String getLabel(Statement s) throws WalaException {
switch (s.getKind()) {
case HEAP_PARAM_CALLEE:
case HEAP_PARAM_CALLER:

View File

@ -256,11 +256,10 @@ public class PDFSlice {
/**
* @return a NodeDecorator that decorates statements in a slice for a dot-ted representation
*/
public static NodeDecorator makeNodeDecorator() {
return new NodeDecorator() {
public static NodeDecorator<Statement> makeNodeDecorator() {
return new NodeDecorator<Statement>() {
@Override
public String getLabel(Object o) throws WalaException {
Statement s = (Statement) o;
public String getLabel(Statement s) throws WalaException {
switch (s.getKind()) {
case HEAP_PARAM_CALLEE:
case HEAP_PARAM_CALLER:

View File

@ -0,0 +1,142 @@
/*******************************************************************************
* Copyright (c) 2013 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.analysis.reflection;
import com.ibm.wala.analysis.typeInference.PointType;
import com.ibm.wala.analysis.typeInference.TypeAbstraction;
import com.ibm.wala.classLoader.IClass;
import com.ibm.wala.ipa.callgraph.Context;
import com.ibm.wala.ipa.callgraph.ContextItem;
import com.ibm.wala.ipa.callgraph.ContextKey;
import com.ibm.wala.ipa.callgraph.propagation.ConstantKey;
import com.ibm.wala.ipa.callgraph.propagation.FilteredPointerKey;
/**
* A context which may be used if
* <ul>
* <li>the method to be interpreted is either
* {@link java.lang.Class#getMethod(String, Class...)} or
* {@link java.lang.Class#getDeclaredMethod(String, Class...)},</li>
* <li>the type of the "this" argument is known and</li>
* <li>the value of the first argument (the method name) is a constant.</li>
* </ul>
*
* In the special case described above,
* {@link GetMethodContextInterpreter}
* and
* {@link GetMethodContextSelector}
* should be preferred over
* {@link JavaLangClassContextInterpreter}
* and
* {@link JavaLangClassContextSelector},
* as
* {@link GetMethodContextInterpreter}
* and
* {@link GetMethodContextSelector}
* drastically reduce the number of methods returned increasing the precision of the analysis.
* Thus,
* {@link GetMethodContextInterpreter}
* and
* {@link GetMethodContextSelector}
* should be placed in be placed in front of
* {@link JavaLangClassContextInterpreter}
* and
* {@link JavaLangClassContextSelector}
* .
* @author Michael Heilmann
* @see com.ibm.wala.analysis.reflection.GetMethodContextInterpreter
* @see com.ibm.wala.analysis.reflection.GetMethodContextSelector
* TODO Do the same for {@link Class#getField(String)} and {@link Class#getDeclaredField(String)}.
*/
public class GetMethodContext implements Context {
/**
* The type abstraction.
*/
private final TypeAbstraction type;
/**
* The method name.
*/
private final ConstantKey name;
/**
* Construct this GetMethodContext.
* @param type the type
* @param name the name of the method
*/
public GetMethodContext(TypeAbstraction type,ConstantKey name) {
if (type == null) {
throw new IllegalArgumentException("null == type");
}
this.type = type;
if (name == null) {
throw new IllegalArgumentException("null == name");
}
this.name = name;
}
@Override
public ContextItem get(ContextKey name) {
if (name == ContextKey.RECEIVER) {
return type;
} else if (name == ContextKey.PARAMETERS[0]) {
if (type instanceof PointType) {
IClass cls = ((PointType) type).getIClass();
return new FilteredPointerKey.SingleClassFilter(cls);
} else {
return null;
}
} else if (name == ContextKey.PARAMETERS[1]) {
return new FilteredPointerKey.SingleClassFilter(this.name.getConcreteType());
} else {
return null;
}
}
@Override
public String toString() {
return "GetMethodContext<" + type + ", " + name + ">";
}
@Override
public int hashCode() {
return 6367 * type.hashCode() * name.hashCode();
}
@Override
public boolean equals(Object obj) {
if (obj == null) {
return false;
}
if (getClass().equals(obj.getClass())) {
GetMethodContext other = (GetMethodContext) obj;
return type.equals(other.type) && name.equals(other.name);
} else {
return false;
}
}
/**
* Get the type.
* @return the type
*/
public TypeAbstraction getType() {
return type;
}
/**
* Get the name.
* @return the name
*/
public String getName() {
return (String)name.getValue();
}
}

View File

@ -0,0 +1,264 @@
/*******************************************************************************
* Copyright (c) 2013 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.analysis.reflection;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.Map;
import com.ibm.wala.cfg.ControlFlowGraph;
import com.ibm.wala.cfg.InducedCFG;
import com.ibm.wala.classLoader.CallSiteReference;
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.propagation.SSAContextInterpreter;
import com.ibm.wala.ipa.summaries.SyntheticIR;
import com.ibm.wala.ssa.ConstantValue;
import com.ibm.wala.ssa.DefUse;
import com.ibm.wala.ssa.IR;
import com.ibm.wala.ssa.ISSABasicBlock;
import com.ibm.wala.ssa.SSAInstruction;
import com.ibm.wala.ssa.SSAInstructionFactory;
import com.ibm.wala.ssa.SSAOptions;
import com.ibm.wala.ssa.SSAReturnInstruction;
import com.ibm.wala.types.FieldReference;
import com.ibm.wala.types.MethodReference;
import com.ibm.wala.types.TypeReference;
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.NonNullSingletonIterator;
import com.ibm.wala.util.debug.Assertions;
import com.ibm.wala.util.strings.Atom;
/**
* Understands {@link com.ibm.wala.analysis.reflection.GetMethodContext}.
* @author Michael Heilmann
* @see com.ibm.wala.analysis.reflection.GetMethodContext
* @see com.ibm.wala.analysis.reflection.GetMethodContextSelector
*/
public class GetMethodContextInterpreter implements SSAContextInterpreter {
/**
* TODO
* MH: Maybe hard-code those in {@link com.ibm.wala.types.MethodReference}?
*/
public final static MethodReference GET_METHOD = MethodReference.findOrCreate(TypeReference.JavaLangClass, "getMethod",
"(Ljava/lang/String;[Ljava/lang/Class;)Ljava/lang/reflect/Method;");
/**
* TODO
* MH: Maybe hard-code those in {@link com.ibm.wala.types.MethodReference}?
*/
public final static MethodReference GET_DECLARED_METHOD = MethodReference.findOrCreate(TypeReference.JavaLangClass,
"getDeclaredMethod", "(Ljava/lang/String;[Ljava/lang/Class;)Ljava/lang/reflect/Method;");
private static final boolean DEBUG = false;
/**
* @see com.ibm.wala.ipa.callgraph.propagation.SSAContextInterpreter#getIR(com.ibm.wala.ipa.callgraph.CGNode)
*/
@Override
public IR getIR(CGNode node) {
if (node == null) {
throw new IllegalArgumentException("node is null");
}
assert understands(node);
if (DEBUG) {
System.err.println("generating IR for " + node);
}
IMethod method = node.getMethod();
GetMethodContext context = (GetMethodContext) node.getContext();
Map<Integer,ConstantValue> constants = HashMapFactory.make();
if (method.getReference().equals(GET_METHOD)) {
Atom name = Atom.findOrCreateAsciiAtom(context.getName());
SSAInstruction instrs[] = makeGetMethodStatements(context,constants,name);
return new SyntheticIR(method, context, new InducedCFG(instrs, method, context), instrs, SSAOptions.defaultOptions(), constants);
}
if (method.getReference().equals(GET_DECLARED_METHOD)) {
Atom name = Atom.findOrCreateAsciiAtom(context.getName());
SSAInstruction instrs[] = makeGetDeclaredMethodStatements(context,constants,name);
return new SyntheticIR(method, context, new InducedCFG(instrs, method, context), instrs, SSAOptions.defaultOptions(), constants);
}
Assertions.UNREACHABLE("Unexpected method " + node);
return null;
}
/**
* @see com.ibm.wala.ipa.callgraph.propagation.SSAContextInterpreter#getNumberOfStatements(com.ibm.wala.ipa.callgraph.CGNode)
*/
@Override
public int getNumberOfStatements(CGNode node) {
assert understands(node);
return getIR(node).getInstructions().length;
}
/**
* @see com.ibm.wala.ipa.callgraph.propagation.rta.RTAContextInterpreter#understands(com.ibm.wala.ipa.callgraph.CGNode)
*/
@Override
public boolean understands(CGNode node) {
if (node == null) {
throw new IllegalArgumentException("node is null");
}
if (!(node.getContext() instanceof GetMethodContext)) {
return false;
}
MethodReference mRef = node.getMethod().getReference();
return mRef.equals(GET_METHOD) || mRef.equals(GET_DECLARED_METHOD);
}
@Override
public Iterator<NewSiteReference> iterateNewSites(CGNode node) {
if (node == null) {
throw new IllegalArgumentException("node is null");
}
assert understands(node);
GetMethodContext context = (GetMethodContext) node.getContext();
TypeReference tr = context.getType().getTypeReference();
if (tr != null) {
return new NonNullSingletonIterator<NewSiteReference>(NewSiteReference.make(0, tr));
}
return EmptyIterator.instance();
}
@Override
public Iterator<CallSiteReference> iterateCallSites(CGNode node) {
assert understands(node);
return EmptyIterator.instance();
}
/**
* Get all non-constructor, non-class-initializer methods declared by a class
* if their name is equal to the specified name.
* @param cls the class
* @param name the name
*/
private Collection<IMethod> getDeclaredNormalMethods(IClass cls,Atom name) {
Collection<IMethod> result = HashSetFactory.make();
for (IMethod m : cls.getDeclaredMethods()) {
if (!m.isInit() && !m.isClinit() && m.getSelector().getName().equals(name)) {
result.add(m);
}
}
return result;
}
/**
* Get all non-constructor, non-class-initializer methods declared by a class
* and all its superclasses if their name is equal to the specified name.
* @param cls the class
* @param name the name
*/
private Collection<IMethod> getAllNormalPublicMethods(IClass cls,Atom name) {
Collection<IMethod> result = HashSetFactory.make();
Collection<IMethod> allMethods = null;
allMethods = cls.getAllMethods();
for (IMethod m : allMethods) {
if (!m.isInit() && !m.isClinit() && m.isPublic() && m.getSelector().getName().equals(name)) {
result.add(m);
}
}
return result;
}
/**
* Create statements for methods like getMethod() and getDeclaredMethod(),
* which return a single method. This creates a return statement for each
* possible return value, each of which is a {@link ConstantValue} for an
* {@link IMethod}.
* @param returnValues the possible return values for this method
* @return the statements
*/
private SSAInstruction[] getParticularMethodStatements
(
MethodReference ref,
Collection<IMethod> returnValues,
GetMethodContext context,
Map<Integer, ConstantValue> constants
) {
ArrayList<SSAInstruction> statements = new ArrayList<SSAInstruction>();
int nextLocal = ref.getNumberOfParameters() + 2;
IClass cls = context.getType().getType();
SSAInstructionFactory insts = context.getType().getType().getClassLoader().getInstructionFactory();
if (cls != null) {
for (IMethod m : returnValues) {
int c = nextLocal++;
constants.put(c, new ConstantValue(m));
SSAReturnInstruction R = insts.ReturnInstruction(statements.size(), c, false);
statements.add(R);
}
} else {
// SJF: This is incorrect. TODO: fix and enable.
// SSAThrowInstruction t = insts.ThrowInstruction(retValue);
// statements.add(t);
}
SSAInstruction[] result = new SSAInstruction[statements.size()];
Iterator<SSAInstruction> it = statements.iterator();
for (int i = 0; i < result.length; i++) {
result[i] = it.next();
}
return result;
}
private SSAInstruction[] makeGetMethodStatements
(
GetMethodContext context,
Map<Integer,ConstantValue> constants,
Atom name
) {
IClass cls = context.getType().getType();
if (cls == null) {
return getParticularMethodStatements(GET_METHOD, null, context, constants);
} else {
return getParticularMethodStatements(GET_METHOD, getAllNormalPublicMethods(cls,name), context, constants);
}
}
/**
* Create statements for {@link Class#getDeclaredMethod(String, Class...)}.
*/
private SSAInstruction[] makeGetDeclaredMethodStatements(GetMethodContext context, Map<Integer, ConstantValue> constants,Atom name) {
IClass cls = context.getType().getType();
if (cls == null) {
return getParticularMethodStatements(GET_DECLARED_METHOD, null, context, constants);
} else {
return getParticularMethodStatements(GET_DECLARED_METHOD, getDeclaredNormalMethods(cls,name), context, constants);
}
}
@Override
public boolean recordFactoryType(CGNode node, IClass klass) {
return false;
}
@Override
public Iterator<FieldReference> iterateFieldsRead(CGNode node) {
return EmptyIterator.instance();
}
@Override
public Iterator<FieldReference> iterateFieldsWritten(CGNode node) {
return EmptyIterator.instance();
}
@Override
public ControlFlowGraph<SSAInstruction,ISSABasicBlock> getCFG(CGNode N) {
return getIR(N).getControlFlowGraph();
}
@Override
public DefUse getDU(CGNode node) {
return new DefUse(getIR(node));
}
}

View File

@ -0,0 +1,154 @@
/*******************************************************************************
* Copyright (c) 2013 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.analysis.reflection;
import java.util.Collection;
import com.ibm.wala.analysis.typeInference.PointType;
import com.ibm.wala.classLoader.CallSiteReference;
import com.ibm.wala.classLoader.IClass;
import com.ibm.wala.classLoader.IMethod;
import com.ibm.wala.ipa.callgraph.CGNode;
import com.ibm.wala.ipa.callgraph.Context;
import com.ibm.wala.ipa.callgraph.ContextSelector;
import com.ibm.wala.ipa.callgraph.propagation.ConstantKey;
import com.ibm.wala.ipa.callgraph.propagation.InstanceKey;
import com.ibm.wala.ipa.cha.IClassHierarchy;
import com.ibm.wala.ssa.IR;
import com.ibm.wala.ssa.SSAAbstractInvokeInstruction;
import com.ibm.wala.ssa.SymbolTable;
import com.ibm.wala.types.MethodReference;
import com.ibm.wala.types.TypeReference;
import com.ibm.wala.util.collections.HashSetFactory;
import com.ibm.wala.util.intset.EmptyIntSet;
import com.ibm.wala.util.intset.IntSet;
import com.ibm.wala.util.intset.IntSetUtil;
/**
* Produces {@link com.ibm.wala.analysis.reflection.GetMethodContext} if appropriate.
* @author Michael Heilmann
* @see com.ibm.wala.analysis.reflection.GetMethodContext
* @see com.ibm.wala.analysis.reflection.GetMethodContextInterpreter
*/
public class GetMethodContextSelector implements ContextSelector {
/**
* If <tt>true</tt>, debug information is emitted.
*/
protected static final boolean DEBUG = false;
/**
* If
* <ul>
* <li>the {@link CallSiteReference} invokes either {@link java.lang.Class#getMethod} or {@link java.lang.Class#getDeclaredMethod},</li>
* <li>and the receiver is a type constant and</li>
* <li>the first argument is a constant,</li>
* </ul>
* then return a {@link GetMethodContextSelector}.
*/
@Override
public Context getCalleeTarget(CGNode caller,CallSiteReference site,IMethod callee,InstanceKey[] receiver) {
if (receiver != null && receiver.length > 0 && mayUnderstand(caller, site, callee, receiver[0])) {
if (DEBUG) {
System.out.print("site := " + site + ", receiver := " + receiver[0]);
}
// If the first argument is a constant ...
IR ir = caller.getIR();
SymbolTable symbolTable = ir.getSymbolTable();
SSAAbstractInvokeInstruction[] invokeInstructions = caller.getIR().getCalls(site);
if (invokeInstructions.length != 1) {
return null;
}
int use = invokeInstructions[0].getUse(1);
if (symbolTable.isStringConstant(invokeInstructions[0].getUse(1))) {
String sym = symbolTable.getStringValue(use);
if (DEBUG) {
System.out.println(invokeInstructions);
System.out.println(", with constant := `" + sym + "`");
for (InstanceKey instanceKey:receiver) {
System.out.println(" " + instanceKey);
}
}
// ... return an GetMethodContext.
ConstantKey ck = makeConstantKey(caller.getClassHierarchy(),sym);
if (DEBUG) {
System.out.println(ck);
}
return new GetMethodContext(new PointType(getTypeConstant(receiver[0])),ck);
}
if (DEBUG) {
System.out.println(", with constant := no");
}
// Otherwise, return null.
// TODO Remove this, just fall-through.
return null;
}
return null;
}
/**
* If <tt>instance</tt> is a {@link ConstantKey} and its value is an instance of {@link IClass},
* return that value. Otherwise, return <tt>null</tt>.
*/
private IClass getTypeConstant(InstanceKey instance) {
if (instance instanceof ConstantKey) {
ConstantKey c = (ConstantKey) instance;
if (c.getValue() instanceof IClass) {
return (IClass) c.getValue();
}
}
return null;
}
/**
* Create a constant key for a string.
* @param cha the class hierarchy
* @param str the string
* @return the constant key
*/
protected static ConstantKey<String> makeConstantKey(IClassHierarchy cha,String str) {
IClass cls = cha.lookupClass(TypeReference.JavaLangString);
ConstantKey<String> ck = new ConstantKey<String>(str,cls);
return ck;
}
private static final Collection<MethodReference> UNDERSTOOD_METHOD_REFS = HashSetFactory.make();
static {
UNDERSTOOD_METHOD_REFS.add(GetMethodContextInterpreter.GET_METHOD);
UNDERSTOOD_METHOD_REFS.add(GetMethodContextInterpreter.GET_DECLARED_METHOD);
}
/**
* This object understands a dispatch to {@link java.lang.Class#getMethod(String, Class...)}
* or {@link java.lang.Class#getDeclaredMethod} when the receiver is a type constant.
*/
private boolean mayUnderstand(CGNode caller,CallSiteReference site,IMethod targetMethod,InstanceKey instance) {
return UNDERSTOOD_METHOD_REFS.contains(targetMethod.getReference())
&& getTypeConstant(instance) != null;
}
/**
* TODO
* MH: Shouldn't be the first TWO parameters be relevant?
* Documentation is not too helpful about the implications.
*/
private static final IntSet thisParameter = IntSetUtil.make(new int[]{0});
@Override
public IntSet getRelevantParameters(CGNode caller, CallSiteReference site) {
if (site.isDispatch() || site.getDeclaredTarget().getNumberOfParameters() > 0) {
return thisParameter;
} else {
return EmptyIntSet.instance;
}
}
}

View File

@ -19,7 +19,12 @@ import com.ibm.wala.ipa.callgraph.ContextKey;
import com.ibm.wala.ipa.callgraph.propagation.FilteredPointerKey;
/**
* Implement a Context which corresponds to a given type abstraction. Thus, this maps the name "TYPE" to a JavaTypeAbstraction.
* @brief
* Implements a Context which corresponds to a given type abstraction.
* Thus, this maps the name "TYPE" to a JavaTypeAbstraction.
* TODO
* This context maps
* {@link com.ibm.wala.ipa.callgraph.ContextKey#RECEIVER} to a {@link TypeAbstraction}.
*/
public class JavaTypeContext implements Context {

View File

@ -115,6 +115,10 @@ public class ReflectionContextInterpreter {
result = new DelegatingSSAContextInterpreter(new ReflectiveInvocationInterpreter(), new DelegatingSSAContextInterpreter(
new JavaLangClassContextInterpreter(), result));
}
// if NEITHER string constants NOR method invocations are ignored
if (!options.getReflectionOptions().isIgnoreStringConstants() && !options.getReflectionOptions().isIgnoreMethodInvoke()) {
result = new DelegatingSSAContextInterpreter(new GetMethodContextInterpreter(),result);
}
return result;
}

View File

@ -54,6 +54,10 @@ public class ReflectionContextSelector {
result = new DelegatingContextSelector(new ReflectiveInvocationSelector(), new DelegatingContextSelector(
new JavaLangClassContextSelector(), result));
}
// if NEITHER string constants NOR method invocations are ignored
if (!options.getReflectionOptions().isIgnoreStringConstants() && !options.getReflectionOptions().isIgnoreMethodInvoke()) {
result = new DelegatingContextSelector(new GetMethodContextSelector(),result);
}
return result;
}
}

View File

@ -49,6 +49,10 @@ public class PointType extends TypeAbstraction {
}
} else if (rhs instanceof ConeType) {
ConeType other = (ConeType) rhs;
if (type.equals(other.getType())) {
// "this" and the cone type have the same underlying type, return the cone type
return other;
}
TypeReference T = other.getType().getReference();
if (type.isArrayClass() || T.isArrayType()) {
// give up on arrays. We don't care anyway.

View File

@ -258,18 +258,16 @@ public class InducedCFG extends AbstractCFG<SSAInstruction, InducedCFG.BasicBloc
@Override
public void visitConditionalBranch(SSAConditionalBranchInstruction instruction) {
Assertions.UNREACHABLE("haven't implemented logic for cbranch yet.");
breakBasicBlock(index);
}
@Override
public void visitSwitch(SSASwitchInstruction instruction) {
Assertions.UNREACHABLE("haven't implemented logic for switch yet.");
// breakBasicBlock();
// int[] targets = instruction.getTargets();
// for (int i = 0; i < targets.length; i++) {
// r[targets[i]] = true;
// }
breakBasicBlock(index);
int[] targets = instruction.getCasesAndLabels();
for (int i = 1; i < targets.length; i+=2) {
r[targets[i]] = true;
}
}
@Override
@ -503,21 +501,30 @@ public class InducedCFG extends AbstractCFG<SSAInstruction, InducedCFG.BasicBloc
}
/** END Custom change: Add GoTo Instruction */
// this CFG is odd in that we assume fallthru might always
// happen .. this is because I'm too lazy to code control
// flow in all method summaries yet.
int normalSuccNodeNumber = getGraphNodeId() + 1;
if (true) {
// if (last.isFallThrough()) {
if (last.isFallThrough()) {
if (DEBUG) {
//System.err.println(("Add fallthru to " + getNode(getGraphNodeId() + 1)));
logger.trace(("Add fallthru to " + getNode(getGraphNodeId() + 1)));
}
addNormalEdgeTo(getNode(normalSuccNodeNumber));
}
if (last instanceof SSAGotoInstruction) {
addNormalEdgeTo(getBlockForInstruction(((SSAGotoInstruction)last).getTarget()));
} else if (last instanceof SSAConditionalBranchInstruction) {
addNormalEdgeTo(getBlockForInstruction(((SSAConditionalBranchInstruction)last).getTarget()));
} else if (last instanceof SSASwitchInstruction) {
int[] targets = ((SSASwitchInstruction) last).getCasesAndLabels();
for (int i = 1; i < targets.length; i+=2) {
addNormalEdgeTo(getBlockForInstruction(targets[i]));
}
}
if (pis != null) {
updatePiInstrs(normalSuccNodeNumber);
}
if (last instanceof SSAReturnInstruction) {
// link each return instrution to the exit block.
BasicBlock exit = exit();

View File

@ -14,7 +14,6 @@ import static com.ibm.wala.types.TypeName.ArrayMask;
import static com.ibm.wala.types.TypeName.ElementBits;
import static com.ibm.wala.types.TypeName.PrimitiveMask;
import java.io.InputStream;
import java.io.Reader;
import java.util.Collection;
import java.util.Collections;

Some files were not shown because too many files have changed in this diff Show More