Merge branch 'master' of https://github.com/wala/WALA into development
This commit is contained in:
commit
ea40719069
|
@ -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());
|
||||
|
|
|
@ -14,52 +14,53 @@ 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));
|
||||
runTest(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));
|
||||
runTest(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));
|
||||
runTest(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));
|
||||
runTest(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));
|
||||
runTest(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));
|
||||
runTest(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));
|
||||
runTest(new URL("http://worldofsolitaire.com/"), new Object[][]{}, BuilderType.OPTIMISTIC_WORKLIST);
|
||||
}
|
||||
|
||||
@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));
|
||||
runTest(new URL("http://www.inmensia.com/files/minesweeper1.0.html"), new Object[][]{}, BuilderType.OPTIMISTIC_WORKLIST);
|
||||
}
|
||||
|
||||
@Test
|
||||
// seems to not work on the Travis CI boxes, so comment out for now
|
||||
//@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));
|
||||
runTest(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));
|
||||
runTest(new URL("http://www.sinkmyship.com/battleship/single.html"), new Object[][]{}, BuilderType.OPTIMISTIC_WORKLIST);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
|
@ -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));
|
||||
|
|
|
@ -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;
|
||||
|
@ -955,6 +961,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 +984,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();
|
||||
}
|
||||
|
@ -1368,14 +1391,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
|
||||
|
|
|
@ -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>
|
|
@ -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>
|
|
@ -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>
|
|
@ -7,3 +7,5 @@ function h() {
|
|||
}
|
||||
|
||||
function k() {}
|
||||
|
||||
h();
|
||||
|
|
|
@ -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);
|
|
@ -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;" +
|
||||
" }" +
|
||||
" }" +
|
||||
" }" +
|
||||
" }" +
|
||||
"}");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -641,6 +641,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" } }
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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: .,
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
bin.includes = .,\
|
||||
META-INF/,\
|
||||
lib/,\
|
||||
lib/commons-io-2.4.jar,\
|
||||
lib/jericho-html-3.2.jar
|
||||
source.. = source/,\
|
||||
dat/
|
||||
|
|
|
@ -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">
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -402,7 +402,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 +535,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) {
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
|
|
|
@ -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)))
|
||||
|
|
|
@ -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()));
|
||||
|
|
|
@ -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()));
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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()));
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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);
|
||||
|
@ -99,7 +99,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(windowVal, rval, nm));
|
||||
|
|
|
@ -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(4, 1, "prototype"));
|
||||
S.getNextProgramCounter();
|
||||
|
||||
S.addStatement(insts.NewInstruction(5, NewSiteReference.make(S.getNextProgramCounter(), cls.getReference())));
|
||||
|
||||
S.addStatement(insts.SetPrototype(5, 4));
|
||||
//S.addStatement(insts.PutInstruction(5, 4, "__proto__"));
|
||||
S.getNextProgramCounter();
|
||||
|
||||
S.addConstant(new Integer(8), new ConstantValue(value));
|
||||
S.addStatement(insts.PutInstruction(5, 8, "$value"));
|
||||
S.getNextProgramCounter();
|
||||
|
||||
S.addStatement(insts.ReturnInstruction(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(5, 1, "prototype"));
|
||||
S.getNextProgramCounter();
|
||||
|
||||
S.addStatement(insts.NewInstruction(6, NewSiteReference.make(S.getNextProgramCounter(), cls.getReference())));
|
||||
|
||||
S.addStatement(insts.SetPrototype(6, 5));
|
||||
//S.addStatement(insts.PutInstruction(6, 5, "__proto__"));
|
||||
S.getNextProgramCounter();
|
||||
|
||||
S.addStatement(insts.PutInstruction(6, 2, "$value"));
|
||||
S.getNextProgramCounter();
|
||||
|
||||
S.addStatement(insts.ReturnInstruction(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(4, 1, "prototype"));
|
||||
S.getNextProgramCounter();
|
||||
|
||||
S.addStatement(insts.NewInstruction(5, NewSiteReference.make(S.getNextProgramCounter(), JavaScriptTypes.Object)));
|
||||
|
||||
S.addStatement(insts.SetPrototype(5, 4));
|
||||
//S.addStatement(insts.PutInstruction(5, 4, "__proto__"));
|
||||
S.getNextProgramCounter();
|
||||
|
||||
S.addStatement(insts.ReturnInstruction(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(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(5, 1, "prototype"));
|
||||
S.getNextProgramCounter();
|
||||
|
||||
S.addStatement(insts.NewInstruction(6, NewSiteReference.make(S.getNextProgramCounter(), JavaScriptTypes.Array)));
|
||||
|
||||
S.addStatement(insts.SetPrototype(6, 5));
|
||||
//S.addStatement(insts.PutInstruction(6, 5, "__proto__"));
|
||||
S.getNextProgramCounter();
|
||||
|
||||
S.addStatement(insts.PutInstruction(6, 2, "length"));
|
||||
S.getNextProgramCounter();
|
||||
|
||||
S.addStatement(insts.ReturnInstruction(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(nargs + 4, 1, nargs + 3));
|
||||
S.getNextProgramCounter();
|
||||
|
||||
S.addStatement(
|
||||
insts.NewInstruction(nargs + 5, NewSiteReference.make(S.getNextProgramCounter(),
|
||||
JavaScriptTypes.Array)));
|
||||
|
||||
S.addStatement(insts.SetPrototype(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(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(nargs + 5, vn, i + 1));
|
||||
S.getNextProgramCounter();
|
||||
}
|
||||
|
||||
S.addStatement(insts.ReturnInstruction(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(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(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(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(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(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(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(4, 1, "prototype"));
|
||||
S.getNextProgramCounter();
|
||||
|
||||
S.addStatement(insts.NewInstruction(5, NewSiteReference.make(S.getNextProgramCounter(), cls.getReference())));
|
||||
|
||||
S.addStatement(insts.NewInstruction(7, NewSiteReference.make(S.getNextProgramCounter(), JavaScriptTypes.Object)));
|
||||
|
||||
S.addStatement(insts.SetPrototype(5, 4));
|
||||
//S.addStatement(insts.PutInstruction(5, 4, "__proto__"));
|
||||
S.getNextProgramCounter();
|
||||
|
||||
S.addStatement(insts.PutInstruction(5, 7, "prototype"));
|
||||
S.getNextProgramCounter();
|
||||
|
||||
S.addStatement(insts.PutInstruction(7, 5, "constructor"));
|
||||
S.getNextProgramCounter();
|
||||
|
||||
// TODO we need to set v7.__proto__ to Object.prototype
|
||||
S.addStatement(insts.ReturnInstruction(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(nargs + 4, 1, "prototype"));
|
||||
S.getNextProgramCounter();
|
||||
|
||||
S.addStatement(
|
||||
insts.NewInstruction(nargs + 5,
|
||||
NewSiteReference.make(S.getNextProgramCounter(),
|
||||
JavaScriptTypes.Object)));
|
||||
|
||||
S.addStatement(insts.SetPrototype(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(nargs + 7, false));
|
||||
S.getNextProgramCounter();
|
||||
|
||||
S.addStatement(insts.ReturnInstruction(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);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -0,0 +1,535 @@
|
|||
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.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(4, 1, "prototype"));
|
||||
S.getNextProgramCounter();
|
||||
|
||||
S.addStatement(insts.NewInstruction(5, NewSiteReference.make(S.getNextProgramCounter(), cls.getReference())));
|
||||
|
||||
S.addStatement(insts.SetPrototype(5, 4));
|
||||
//S.addStatement(insts.PutInstruction(5, 4, "__proto__"));
|
||||
S.getNextProgramCounter();
|
||||
|
||||
S.addConstant(new Integer(8), new ConstantValue(value));
|
||||
S.addStatement(insts.PutInstruction(5, 8, "$value"));
|
||||
S.getNextProgramCounter();
|
||||
|
||||
S.addStatement(insts.ReturnInstruction(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(5, 1, "prototype"));
|
||||
S.getNextProgramCounter();
|
||||
|
||||
S.addStatement(insts.NewInstruction(6, NewSiteReference.make(S.getNextProgramCounter(), cls.getReference())));
|
||||
|
||||
S.addStatement(insts.SetPrototype(6, 5));
|
||||
//S.addStatement(insts.PutInstruction(6, 5, "__proto__"));
|
||||
S.getNextProgramCounter();
|
||||
|
||||
S.addStatement(insts.PutInstruction(6, 2, "$value"));
|
||||
S.getNextProgramCounter();
|
||||
|
||||
S.addStatement(insts.ReturnInstruction(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(4, 1, "prototype"));
|
||||
S.getNextProgramCounter();
|
||||
|
||||
S.addStatement(insts.NewInstruction(5, NewSiteReference.make(S.getNextProgramCounter(), JavaScriptTypes.Object)));
|
||||
|
||||
S.addStatement(insts.SetPrototype(5, 4));
|
||||
//S.addStatement(insts.PutInstruction(5, 4, "__proto__"));
|
||||
S.getNextProgramCounter();
|
||||
|
||||
S.addStatement(insts.ReturnInstruction(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(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(5, 1, "prototype"));
|
||||
S.getNextProgramCounter();
|
||||
|
||||
S.addStatement(insts.NewInstruction(6, NewSiteReference.make(S.getNextProgramCounter(), JavaScriptTypes.Array)));
|
||||
|
||||
S.addStatement(insts.SetPrototype(6, 5));
|
||||
//S.addStatement(insts.PutInstruction(6, 5, "__proto__"));
|
||||
S.getNextProgramCounter();
|
||||
|
||||
S.addStatement(insts.PutInstruction(6, 2, "length"));
|
||||
S.getNextProgramCounter();
|
||||
|
||||
S.addStatement(insts.ReturnInstruction(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(nargs + 4, 1, nargs + 3));
|
||||
S.getNextProgramCounter();
|
||||
|
||||
S.addStatement(
|
||||
insts.NewInstruction(nargs + 5, NewSiteReference.make(S.getNextProgramCounter(),
|
||||
JavaScriptTypes.Array)));
|
||||
|
||||
S.addStatement(insts.SetPrototype(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(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(nargs + 5, vn, i + 1));
|
||||
S.getNextProgramCounter();
|
||||
}
|
||||
|
||||
S.addStatement(insts.ReturnInstruction(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(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(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(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(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(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(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(4, 1, "prototype"));
|
||||
S.getNextProgramCounter();
|
||||
|
||||
S.addStatement(insts.NewInstruction(5, NewSiteReference.make(S.getNextProgramCounter(), cls.getReference())));
|
||||
|
||||
S.addStatement(insts.NewInstruction(7, NewSiteReference.make(S.getNextProgramCounter(), JavaScriptTypes.Object)));
|
||||
|
||||
S.addStatement(insts.SetPrototype(5, 4));
|
||||
//S.addStatement(insts.PutInstruction(5, 4, "__proto__"));
|
||||
S.getNextProgramCounter();
|
||||
|
||||
S.addStatement(insts.PutInstruction(5, 7, "prototype"));
|
||||
S.getNextProgramCounter();
|
||||
|
||||
S.addStatement(insts.PutInstruction(7, 5, "constructor"));
|
||||
S.getNextProgramCounter();
|
||||
|
||||
// TODO we need to set v7.__proto__ to Object.prototype
|
||||
S.addStatement(insts.ReturnInstruction(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);
|
||||
|
||||
System.err.println(cls);
|
||||
|
||||
MethodReference ref = JavaScriptMethods.makeCtorReference(cls.getReference());
|
||||
JavaScriptSummary S = new JavaScriptSummary(ref, nargs + 1);
|
||||
S.addStatement(insts.GetInstruction(nargs + 4, 1, "prototype"));
|
||||
S.getNextProgramCounter();
|
||||
|
||||
S.addStatement(
|
||||
insts.NewInstruction(nargs + 5,
|
||||
NewSiteReference.make(S.getNextProgramCounter(),
|
||||
JavaScriptTypes.Object)));
|
||||
|
||||
S.addStatement(insts.SetPrototype(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(nargs + 7, false));
|
||||
S.getNextProgramCounter();
|
||||
|
||||
S.addStatement(insts.ReturnInstruction(nargs + 5, false));
|
||||
S.getNextProgramCounter();
|
||||
|
||||
//S.addConstant(nargs + 9, new ConstantValue("__proto__"));
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -404,7 +404,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);
|
||||
|
|
|
@ -1755,6 +1755,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++) {
|
||||
|
@ -1968,6 +1973,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;
|
||||
|
@ -3272,6 +3283,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
|
||||
|
@ -3327,11 +3405,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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
|
||||
|
|
|
@ -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";
|
||||
|
|
|
@ -913,7 +913,7 @@ public abstract class AbstractIntStackMachine implements FixedPointConstants {
|
|||
protected class BasicStackMachineVisitor extends IInstruction.Visitor {
|
||||
|
||||
/**
|
||||
* @see com.ibm.wala.shrikeBT.Instruction.Visitor#visitArrayLength(ArrayLengthInstruction)
|
||||
* @see com.ibm.wala.shrikeBT.IInstruction.Visitor#visitArrayLength(ArrayLengthInstruction)
|
||||
*/
|
||||
@Override
|
||||
public void visitArrayLength(ArrayLengthInstruction instruction) {
|
||||
|
@ -923,7 +923,7 @@ public abstract class AbstractIntStackMachine implements FixedPointConstants {
|
|||
}
|
||||
|
||||
/**
|
||||
* @see com.ibm.wala.shrikeBT.Instruction.Visitor#visitArrayLoad(IArrayLoadInstruction)
|
||||
* @see com.ibm.wala.shrikeBT.IInstruction.Visitor#visitArrayLoad(IArrayLoadInstruction)
|
||||
*/
|
||||
@Override
|
||||
public void visitArrayLoad(IArrayLoadInstruction instruction) {
|
||||
|
@ -933,7 +933,7 @@ public abstract class AbstractIntStackMachine implements FixedPointConstants {
|
|||
}
|
||||
|
||||
/**
|
||||
* @see com.ibm.wala.shrikeBT.Instruction.Visitor#visitArrayStore(IArrayStoreInstruction)
|
||||
* @see com.ibm.wala.shrikeBT.IInstruction.Visitor#visitArrayStore(IArrayStoreInstruction)
|
||||
*/
|
||||
@Override
|
||||
public void visitArrayStore(IArrayStoreInstruction instruction) {
|
||||
|
@ -943,7 +943,7 @@ public abstract class AbstractIntStackMachine implements FixedPointConstants {
|
|||
}
|
||||
|
||||
/**
|
||||
* @see com.ibm.wala.shrikeBT.Instruction.Visitor#visitBinaryOp(IBinaryOpInstruction)
|
||||
* @see com.ibm.wala.shrikeBT.IInstruction.Visitor#visitBinaryOp(IBinaryOpInstruction)
|
||||
*/
|
||||
@Override
|
||||
public void visitBinaryOp(IBinaryOpInstruction instruction) {
|
||||
|
@ -951,7 +951,7 @@ public abstract class AbstractIntStackMachine implements FixedPointConstants {
|
|||
}
|
||||
|
||||
/**
|
||||
* @see com.ibm.wala.shrikeBT.Instruction.Visitor#visitComparison(IComparisonInstruction)
|
||||
* @see com.ibm.wala.shrikeBT.IInstruction.Visitor#visitComparison(IComparisonInstruction)
|
||||
*/
|
||||
@Override
|
||||
public void visitComparison(IComparisonInstruction instruction) {
|
||||
|
@ -961,7 +961,7 @@ public abstract class AbstractIntStackMachine implements FixedPointConstants {
|
|||
}
|
||||
|
||||
/**
|
||||
* @see com.ibm.wala.shrikeBT.Instruction.Visitor#visitConditionalBranch(IConditionalBranchInstruction)
|
||||
* @see com.ibm.wala.shrikeBT.IInstruction.Visitor#visitConditionalBranch(IConditionalBranchInstruction)
|
||||
*/
|
||||
@Override
|
||||
public void visitConditionalBranch(IConditionalBranchInstruction instruction) {
|
||||
|
@ -970,7 +970,7 @@ public abstract class AbstractIntStackMachine implements FixedPointConstants {
|
|||
}
|
||||
|
||||
/**
|
||||
* @see com.ibm.wala.shrikeBT.Instruction.Visitor#visitConstant(ConstantInstruction)
|
||||
* @see com.ibm.wala.shrikeBT.IInstruction.Visitor#visitConstant(ConstantInstruction)
|
||||
*/
|
||||
@Override
|
||||
public void visitConstant(ConstantInstruction instruction) {
|
||||
|
@ -978,7 +978,7 @@ public abstract class AbstractIntStackMachine implements FixedPointConstants {
|
|||
}
|
||||
|
||||
/**
|
||||
* @see com.ibm.wala.shrikeBT.Instruction.Visitor#visitConversion(IConversionInstruction)
|
||||
* @see com.ibm.wala.shrikeBT.IInstruction.Visitor#visitConversion(IConversionInstruction)
|
||||
*/
|
||||
@Override
|
||||
public void visitConversion(IConversionInstruction instruction) {
|
||||
|
@ -987,7 +987,7 @@ public abstract class AbstractIntStackMachine implements FixedPointConstants {
|
|||
}
|
||||
|
||||
/**
|
||||
* @see com.ibm.wala.shrikeBT.Instruction.Visitor#visitDup(DupInstruction)
|
||||
* @see com.ibm.wala.shrikeBT.IInstruction.Visitor#visitDup(DupInstruction)
|
||||
*/
|
||||
@Override
|
||||
public void visitDup(DupInstruction instruction) {
|
||||
|
@ -1020,7 +1020,7 @@ public abstract class AbstractIntStackMachine implements FixedPointConstants {
|
|||
}
|
||||
|
||||
/**
|
||||
* @see com.ibm.wala.shrikeBT.Instruction.Visitor#visitGet(IGetInstruction)
|
||||
* @see com.ibm.wala.shrikeBT.IInstruction.Visitor#visitGet(IGetInstruction)
|
||||
*/
|
||||
@Override
|
||||
public void visitGet(IGetInstruction instruction) {
|
||||
|
@ -1035,7 +1035,7 @@ public abstract class AbstractIntStackMachine implements FixedPointConstants {
|
|||
}
|
||||
|
||||
/**
|
||||
* @see com.ibm.wala.shrikeBT.Instruction.Visitor#visitInstanceof(IInstanceofInstruction)
|
||||
* @see com.ibm.wala.shrikeBT.IInstruction.Visitor#visitInstanceof(IInstanceofInstruction)
|
||||
*/
|
||||
@Override
|
||||
public void visitInstanceof(IInstanceofInstruction instruction) {
|
||||
|
@ -1044,7 +1044,7 @@ public abstract class AbstractIntStackMachine implements FixedPointConstants {
|
|||
}
|
||||
|
||||
/**
|
||||
* @see com.ibm.wala.shrikeBT.Instruction.Visitor#visitInvoke(IInvokeInstruction)
|
||||
* @see com.ibm.wala.shrikeBT.IInstruction.Visitor#visitInvoke(IInvokeInstruction)
|
||||
*/
|
||||
@Override
|
||||
public void visitInvoke(IInvokeInstruction instruction) {
|
||||
|
@ -1057,7 +1057,7 @@ public abstract class AbstractIntStackMachine implements FixedPointConstants {
|
|||
}
|
||||
|
||||
/**
|
||||
* @see com.ibm.wala.shrikeBT.Instruction.Visitor#visitMonitor(MonitorInstruction)
|
||||
* @see com.ibm.wala.shrikeBT.IInstruction.Visitor#visitMonitor(MonitorInstruction)
|
||||
*/
|
||||
@Override
|
||||
public void visitMonitor(MonitorInstruction instruction) {
|
||||
|
@ -1065,7 +1065,7 @@ public abstract class AbstractIntStackMachine implements FixedPointConstants {
|
|||
}
|
||||
|
||||
/**
|
||||
* @see com.ibm.wala.shrikeBT.Instruction.Visitor#visitLocalLoad(ILoadInstruction)
|
||||
* @see com.ibm.wala.shrikeBT.IInstruction.Visitor#visitLocalLoad(ILoadInstruction)
|
||||
*/
|
||||
@Override
|
||||
public void visitLocalLoad(ILoadInstruction instruction) {
|
||||
|
@ -1074,7 +1074,7 @@ public abstract class AbstractIntStackMachine implements FixedPointConstants {
|
|||
}
|
||||
|
||||
/**
|
||||
* @see com.ibm.wala.shrikeBT.Instruction.Visitor#visitLocalStore(IStoreInstruction)
|
||||
* @see com.ibm.wala.shrikeBT.IInstruction.Visitor#visitLocalStore(IStoreInstruction)
|
||||
*/
|
||||
@Override
|
||||
public void visitLocalStore(IStoreInstruction instruction) {
|
||||
|
@ -1083,7 +1083,7 @@ public abstract class AbstractIntStackMachine implements FixedPointConstants {
|
|||
}
|
||||
|
||||
/**
|
||||
* @see com.ibm.wala.shrikeBT.Instruction.Visitor#visitNew(NewInstruction)
|
||||
* @see com.ibm.wala.shrikeBT.IInstruction.Visitor#visitNew(NewInstruction)
|
||||
*/
|
||||
@Override
|
||||
public void visitNew(NewInstruction instruction) {
|
||||
|
@ -1092,7 +1092,7 @@ public abstract class AbstractIntStackMachine implements FixedPointConstants {
|
|||
}
|
||||
|
||||
/**
|
||||
* @see com.ibm.wala.shrikeBT.Instruction.Visitor#visitPop(PopInstruction)
|
||||
* @see com.ibm.wala.shrikeBT.IInstruction.Visitor#visitPop(PopInstruction)
|
||||
*/
|
||||
@Override
|
||||
public void visitPop(PopInstruction instruction) {
|
||||
|
@ -1102,7 +1102,7 @@ public abstract class AbstractIntStackMachine implements FixedPointConstants {
|
|||
}
|
||||
|
||||
/**
|
||||
* @see com.ibm.wala.shrikeBT.Instruction.Visitor#visitPut(IPutInstruction)
|
||||
* @see com.ibm.wala.shrikeBT.IInstruction.Visitor#visitPut(IPutInstruction)
|
||||
*/
|
||||
@Override
|
||||
public void visitPut(IPutInstruction instruction) {
|
||||
|
@ -1110,7 +1110,7 @@ public abstract class AbstractIntStackMachine implements FixedPointConstants {
|
|||
}
|
||||
|
||||
/**
|
||||
* @see com.ibm.wala.shrikeBT.Instruction.Visitor#visitShift(IShiftInstruction)
|
||||
* @see com.ibm.wala.shrikeBT.IInstruction.Visitor#visitShift(IShiftInstruction)
|
||||
*/
|
||||
@Override
|
||||
public void visitShift(IShiftInstruction instruction) {
|
||||
|
@ -1118,7 +1118,7 @@ public abstract class AbstractIntStackMachine implements FixedPointConstants {
|
|||
}
|
||||
|
||||
/**
|
||||
* @see com.ibm.wala.shrikeBT.Instruction.Visitor#visitSwap(SwapInstruction)
|
||||
* @see com.ibm.wala.shrikeBT.IInstruction.Visitor#visitSwap(SwapInstruction)
|
||||
*/
|
||||
@Override
|
||||
public void visitSwap(SwapInstruction instruction) {
|
||||
|
@ -1126,7 +1126,7 @@ public abstract class AbstractIntStackMachine implements FixedPointConstants {
|
|||
}
|
||||
|
||||
/**
|
||||
* @see com.ibm.wala.shrikeBT.Instruction.Visitor#visitSwitch(SwitchInstruction)
|
||||
* @see com.ibm.wala.shrikeBT.IInstruction.Visitor#visitSwitch(SwitchInstruction)
|
||||
*/
|
||||
@Override
|
||||
public void visitSwitch(SwitchInstruction instruction) {
|
||||
|
@ -1134,7 +1134,7 @@ public abstract class AbstractIntStackMachine implements FixedPointConstants {
|
|||
}
|
||||
|
||||
/**
|
||||
* @see com.ibm.wala.shrikeBT.Instruction.Visitor#visitThrow(ThrowInstruction)
|
||||
* @see com.ibm.wala.shrikeBT.IInstruction.Visitor#visitThrow(ThrowInstruction)
|
||||
*/
|
||||
@Override
|
||||
public void visitThrow(ThrowInstruction instruction) {
|
||||
|
@ -1144,7 +1144,7 @@ public abstract class AbstractIntStackMachine implements FixedPointConstants {
|
|||
}
|
||||
|
||||
/**
|
||||
* @see com.ibm.wala.shrikeBT.Instruction.Visitor#visitUnaryOp(IUnaryOpInstruction)
|
||||
* @see com.ibm.wala.shrikeBT.IInstruction.Visitor#visitUnaryOp(IUnaryOpInstruction)
|
||||
*/
|
||||
@Override
|
||||
public void visitUnaryOp(IUnaryOpInstruction instruction) {
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -766,7 +766,7 @@ public class ClassHierarchy implements IClassHierarchy {
|
|||
}
|
||||
IClass aa = a;
|
||||
while (aa != null) {
|
||||
if (superB.contains(aa)) {
|
||||
if (b.equals(aa) || superB.contains(aa)) {
|
||||
return aa;
|
||||
}
|
||||
aa = aa.getSuperclass();
|
||||
|
|
|
@ -125,7 +125,11 @@ public class BypassMethodTargetSelector implements MethodTargetSelector {
|
|||
// we want to generate a NoOpSummary for this method.
|
||||
return findOrCreateSyntheticMethod(site.getDeclaredTarget(), site.isStatic());
|
||||
}
|
||||
if (parent instanceof ClassHierarchyMethodTargetSelector) {
|
||||
|
||||
// not using if (instanceof ClassHierarchyMethodTargetSelector) because
|
||||
// we want to make sure that getCalleeTarget() is still called if
|
||||
// parent is a subclass of ClassHierarchyMethodTargetSelector
|
||||
if (parent.getClass() == ClassHierarchyMethodTargetSelector.class) {
|
||||
// already checked this case and decided not to bypass
|
||||
return chaTarget;
|
||||
}
|
||||
|
|
|
@ -384,7 +384,7 @@ public class SSABuilder extends AbstractIntStackMachine {
|
|||
class NodeVisitor extends BasicStackMachineVisitor {
|
||||
|
||||
/**
|
||||
* @see com.ibm.wala.shrikeBT.Instruction.Visitor#visitArrayLength(ArrayLengthInstruction)
|
||||
* @see com.ibm.wala.shrikeBT.IInstruction.Visitor#visitArrayLength(ArrayLengthInstruction)
|
||||
*/
|
||||
@Override
|
||||
public void visitArrayLength(com.ibm.wala.shrikeBT.ArrayLengthInstruction instruction) {
|
||||
|
@ -397,7 +397,7 @@ public class SSABuilder extends AbstractIntStackMachine {
|
|||
}
|
||||
|
||||
/**
|
||||
* @see com.ibm.wala.shrikeBT.Instruction.Visitor#visitArrayLoad(IArrayLoadInstruction)
|
||||
* @see com.ibm.wala.shrikeBT.IInstruction.Visitor#visitArrayLoad(IArrayLoadInstruction)
|
||||
*/
|
||||
@Override
|
||||
public void visitArrayLoad(IArrayLoadInstruction instruction) {
|
||||
|
@ -414,7 +414,7 @@ public class SSABuilder extends AbstractIntStackMachine {
|
|||
}
|
||||
|
||||
/**
|
||||
* @see com.ibm.wala.shrikeBT.Instruction.Visitor#visitArrayStore(IArrayStoreInstruction)
|
||||
* @see com.ibm.wala.shrikeBT.IInstruction.Visitor#visitArrayStore(IArrayStoreInstruction)
|
||||
*/
|
||||
@Override
|
||||
public void visitArrayStore(IArrayStoreInstruction instruction) {
|
||||
|
@ -427,7 +427,7 @@ public class SSABuilder extends AbstractIntStackMachine {
|
|||
}
|
||||
|
||||
/**
|
||||
* @see com.ibm.wala.shrikeBT.Instruction.Visitor#visitBinaryOp(IBinaryOpInstruction)
|
||||
* @see com.ibm.wala.shrikeBT.IInstruction.Visitor#visitBinaryOp(IBinaryOpInstruction)
|
||||
*/
|
||||
@Override
|
||||
public void visitBinaryOp(IBinaryOpInstruction instruction) {
|
||||
|
@ -441,7 +441,7 @@ public class SSABuilder extends AbstractIntStackMachine {
|
|||
}
|
||||
|
||||
/**
|
||||
* @see com.ibm.wala.shrikeBT.Instruction.Visitor#visitCheckCast(ITypeTestInstruction)
|
||||
* @see com.ibm.wala.shrikeBT.IInstruction.Visitor#visitCheckCast(ITypeTestInstruction)
|
||||
*/
|
||||
@Override
|
||||
public void visitCheckCast(ITypeTestInstruction instruction) {
|
||||
|
@ -459,7 +459,7 @@ public class SSABuilder extends AbstractIntStackMachine {
|
|||
}
|
||||
|
||||
/**
|
||||
* @see com.ibm.wala.shrikeBT.Instruction.Visitor#visitComparison(IComparisonInstruction)
|
||||
* @see com.ibm.wala.shrikeBT.IInstruction.Visitor#visitComparison(IComparisonInstruction)
|
||||
*/
|
||||
@Override
|
||||
public void visitComparison(IComparisonInstruction instruction) {
|
||||
|
@ -472,7 +472,7 @@ public class SSABuilder extends AbstractIntStackMachine {
|
|||
}
|
||||
|
||||
/**
|
||||
* @see com.ibm.wala.shrikeBT.Instruction.Visitor#visitConditionalBranch(IConditionalBranchInstruction)
|
||||
* @see com.ibm.wala.shrikeBT.IInstruction.Visitor#visitConditionalBranch(IConditionalBranchInstruction)
|
||||
*/
|
||||
@Override
|
||||
public void visitConditionalBranch(IConditionalBranchInstruction instruction) {
|
||||
|
@ -484,11 +484,12 @@ public class SSABuilder extends AbstractIntStackMachine {
|
|||
}
|
||||
|
||||
/**
|
||||
* @see com.ibm.wala.shrikeBT.Instruction.Visitor#visitConstant(ConstantInstruction)
|
||||
* @see com.ibm.wala.shrikeBT.IInstruction.Visitor#visitConstant(ConstantInstruction)
|
||||
*/
|
||||
@Override
|
||||
public void visitConstant(com.ibm.wala.shrikeBT.ConstantInstruction instruction) {
|
||||
Language l = cfg.getMethod().getDeclaringClass().getClassLoader().getLanguage();
|
||||
|
||||
TypeReference type = l.getConstantType(instruction.getValue());
|
||||
int symbol = 0;
|
||||
if (l.isNullType(type)) {
|
||||
|
@ -519,7 +520,7 @@ public class SSABuilder extends AbstractIntStackMachine {
|
|||
}
|
||||
|
||||
/**
|
||||
* @see com.ibm.wala.shrikeBT.Instruction.Visitor#visitConversion(IConversionInstruction)
|
||||
* @see com.ibm.wala.shrikeBT.IInstruction.Visitor#visitConversion(IConversionInstruction)
|
||||
*/
|
||||
@Override
|
||||
public void visitConversion(IConversionInstruction instruction) {
|
||||
|
@ -535,7 +536,7 @@ public class SSABuilder extends AbstractIntStackMachine {
|
|||
}
|
||||
|
||||
/**
|
||||
* @see com.ibm.wala.shrikeBT.Instruction.Visitor#visitGet(IGetInstruction)
|
||||
* @see com.ibm.wala.shrikeBT.IInstruction.Visitor#visitGet(IGetInstruction)
|
||||
*/
|
||||
@Override
|
||||
public void visitGet(IGetInstruction instruction) {
|
||||
|
@ -555,7 +556,7 @@ public class SSABuilder extends AbstractIntStackMachine {
|
|||
}
|
||||
|
||||
/**
|
||||
* @see com.ibm.wala.shrikeBT.Instruction.Visitor#visitGoto(GotoInstruction)
|
||||
* @see com.ibm.wala.shrikeBT.IInstruction.Visitor#visitGoto(GotoInstruction)
|
||||
*/
|
||||
@Override
|
||||
public void visitGoto(com.ibm.wala.shrikeBT.GotoInstruction instruction) {
|
||||
|
@ -563,7 +564,7 @@ public class SSABuilder extends AbstractIntStackMachine {
|
|||
}
|
||||
|
||||
/**
|
||||
* @see com.ibm.wala.shrikeBT.Instruction.Visitor#visitInstanceof(IInstanceofInstruction)
|
||||
* @see com.ibm.wala.shrikeBT.IInstruction.Visitor#visitInstanceof(IInstanceofInstruction)
|
||||
*/
|
||||
@Override
|
||||
public void visitInstanceof(IInstanceofInstruction instruction) {
|
||||
|
@ -576,7 +577,7 @@ public class SSABuilder extends AbstractIntStackMachine {
|
|||
}
|
||||
|
||||
/**
|
||||
* @see com.ibm.wala.shrikeBT.Instruction.Visitor#visitInvoke(IInvokeInstruction)
|
||||
* @see com.ibm.wala.shrikeBT.IInstruction.Visitor#visitInvoke(IInvokeInstruction)
|
||||
*/
|
||||
@Override
|
||||
public void visitInvoke(IInvokeInstruction instruction) {
|
||||
|
@ -621,8 +622,8 @@ public class SSABuilder extends AbstractIntStackMachine {
|
|||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* @see com.ibm.wala.shrikeBT.Instruction.Visitor#visitLocalStore(com.ibm.wala.shrikeBT.StoreInstruction)
|
||||
/**
|
||||
* @see com.ibm.wala.shrikeBT.IInstruction.Visitor#visitLocalStore(IStoreInstruction)
|
||||
*/
|
||||
@Override
|
||||
public void visitLocalStore(IStoreInstruction instruction) {
|
||||
|
@ -633,7 +634,7 @@ public class SSABuilder extends AbstractIntStackMachine {
|
|||
}
|
||||
|
||||
/**
|
||||
* @see com.ibm.wala.shrikeBT.Instruction.Visitor#visitMonitor(MonitorInstruction)
|
||||
* @see com.ibm.wala.shrikeBT.IInstruction.Visitor#visitMonitor(MonitorInstruction)
|
||||
*/
|
||||
@Override
|
||||
public void visitMonitor(com.ibm.wala.shrikeBT.MonitorInstruction instruction) {
|
||||
|
@ -643,7 +644,7 @@ public class SSABuilder extends AbstractIntStackMachine {
|
|||
}
|
||||
|
||||
/**
|
||||
* @see com.ibm.wala.shrikeBT.Instruction.Visitor#visitNew(NewInstruction)
|
||||
* @see com.ibm.wala.shrikeBT.IInstruction.Visitor#visitNew(NewInstruction)
|
||||
*/
|
||||
@Override
|
||||
public void visitNew(com.ibm.wala.shrikeBT.NewInstruction instruction) {
|
||||
|
@ -664,7 +665,7 @@ public class SSABuilder extends AbstractIntStackMachine {
|
|||
}
|
||||
|
||||
/**
|
||||
* @see com.ibm.wala.shrikeBT.Instruction.Visitor#visitGet(IGetInstruction)
|
||||
* @see com.ibm.wala.shrikeBT.IInstruction.Visitor#visitGet(IGetInstruction)
|
||||
*/
|
||||
@Override
|
||||
public void visitPut(IPutInstruction instruction) {
|
||||
|
@ -682,7 +683,7 @@ public class SSABuilder extends AbstractIntStackMachine {
|
|||
}
|
||||
|
||||
/**
|
||||
* @see com.ibm.wala.shrikeBT.Instruction.Visitor#visitReturn(ReturnInstruction)
|
||||
* @see com.ibm.wala.shrikeBT.IInstruction.Visitor#visitReturn(ReturnInstruction)
|
||||
*/
|
||||
@Override
|
||||
public void visitReturn(com.ibm.wala.shrikeBT.ReturnInstruction instruction) {
|
||||
|
@ -696,7 +697,7 @@ public class SSABuilder extends AbstractIntStackMachine {
|
|||
}
|
||||
|
||||
/**
|
||||
* @see com.ibm.wala.shrikeBT.Instruction.Visitor#visitShift(IShiftInstruction)
|
||||
* @see com.ibm.wala.shrikeBT.IInstruction.Visitor#visitShift(IShiftInstruction)
|
||||
*/
|
||||
@Override
|
||||
public void visitShift(IShiftInstruction instruction) {
|
||||
|
@ -709,7 +710,7 @@ public class SSABuilder extends AbstractIntStackMachine {
|
|||
}
|
||||
|
||||
/**
|
||||
* @see com.ibm.wala.shrikeBT.Instruction.Visitor#visitSwitch(SwitchInstruction)
|
||||
* @see com.ibm.wala.shrikeBT.IInstruction.Visitor#visitSwitch(SwitchInstruction)
|
||||
*/
|
||||
@Override
|
||||
public void visitSwitch(com.ibm.wala.shrikeBT.SwitchInstruction instruction) {
|
||||
|
@ -750,7 +751,7 @@ public class SSABuilder extends AbstractIntStackMachine {
|
|||
}
|
||||
|
||||
/**
|
||||
* @see com.ibm.wala.shrikeBT.Instruction.Visitor#visitThrow(ThrowInstruction)
|
||||
* @see com.ibm.wala.shrikeBT.IInstruction.Visitor#visitThrow(ThrowInstruction)
|
||||
*/
|
||||
@Override
|
||||
public void visitThrow(com.ibm.wala.shrikeBT.ThrowInstruction instruction) {
|
||||
|
@ -766,7 +767,7 @@ public class SSABuilder extends AbstractIntStackMachine {
|
|||
}
|
||||
|
||||
/**
|
||||
* @see com.ibm.wala.shrikeBT.Instruction.Visitor#visitUnaryOp(IUnaryOpInstruction)
|
||||
* @see com.ibm.wala.shrikeBT.IInstruction.Visitor#visitUnaryOp(IUnaryOpInstruction)
|
||||
*/
|
||||
@Override
|
||||
public void visitUnaryOp(IUnaryOpInstruction instruction) {
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
package com.ibm.wala.cast.js.callgraph.fieldbased.flowgraph;
|
||||
|
||||
import com.ibm.wala.cast.js.ipa.summaries.JavaScriptConstructorFunctions;
|
||||
import com.ibm.wala.classLoader.IMethod;
|
||||
import com.ibm.wala.ipa.callgraph.AnalysisCache;
|
||||
import com.ibm.wala.ipa.callgraph.MethodTargetSelector;
|
||||
import com.ibm.wala.ipa.cha.IClassHierarchy;
|
||||
import com.ibm.wala.util.functions.Function;
|
||||
|
||||
|
@ -9,13 +11,13 @@ public class FilteredFlowGraphBuilder extends FlowGraphBuilder {
|
|||
|
||||
private final Function<IMethod, Boolean> filter;
|
||||
|
||||
public FilteredFlowGraphBuilder(IClassHierarchy cha, AnalysisCache cache, Function<IMethod, Boolean> filter) {
|
||||
super(cha, cache);
|
||||
public FilteredFlowGraphBuilder(IClassHierarchy cha, AnalysisCache cache, JavaScriptConstructorFunctions selector, Function<IMethod, Boolean> filter) {
|
||||
super(cha, cache, selector);
|
||||
this.filter = filter;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void visitFunction(FlowGraph flowgraph, IMethod method) {
|
||||
public void visitFunction(FlowGraph flowgraph, IMethod method) {
|
||||
if (filter.apply(method)) {
|
||||
super.visitFunction(flowgraph, method);
|
||||
}
|
||||
|
|
|
@ -31,6 +31,7 @@ import com.ibm.wala.cast.js.html.IncludedPosition;
|
|||
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.JSCallGraphUtil;
|
||||
import com.ibm.wala.cast.js.ipa.summaries.JavaScriptConstructorFunctions;
|
||||
import com.ibm.wala.cast.js.loader.JavaScriptLoader;
|
||||
import com.ibm.wala.cast.js.loader.JavaScriptLoaderFactory;
|
||||
import com.ibm.wala.cast.js.translator.CAstRhinoTranslatorFactory;
|
||||
|
@ -46,6 +47,7 @@ import com.ibm.wala.ipa.callgraph.AnalysisOptions;
|
|||
import com.ibm.wala.ipa.callgraph.AnalysisScope;
|
||||
import com.ibm.wala.ipa.callgraph.CallGraphBuilder;
|
||||
import com.ibm.wala.ipa.callgraph.Entrypoint;
|
||||
import com.ibm.wala.ipa.callgraph.MethodTargetSelector;
|
||||
import com.ibm.wala.ipa.callgraph.propagation.PointerAnalysis;
|
||||
import com.ibm.wala.ipa.cha.IClassHierarchy;
|
||||
import com.ibm.wala.types.ClassLoaderReference;
|
||||
|
@ -165,8 +167,8 @@ public class EclipseJavaScriptAnalysisEngine extends EclipseProjectSourceAnalysi
|
|||
builderType.equals(BuilderType.PESSIMISTIC)?
|
||||
new PessimisticCallGraphBuilder(getClassHierarchy(), options, makeDefaultCache()) {
|
||||
@Override
|
||||
protected FlowGraph flowGraphFactory() {
|
||||
FlowGraphBuilder b = new FilteredFlowGraphBuilder(cha, cache, filter);
|
||||
protected FlowGraph flowGraphFactory(JavaScriptConstructorFunctions selector) {
|
||||
FlowGraphBuilder b = new FilteredFlowGraphBuilder(cha, cache, selector, filter);
|
||||
return b.buildFlowGraph();
|
||||
}
|
||||
@Override
|
||||
|
@ -176,8 +178,8 @@ public class EclipseJavaScriptAnalysisEngine extends EclipseProjectSourceAnalysi
|
|||
}
|
||||
: new OptimisticCallgraphBuilder(getClassHierarchy(), options, makeDefaultCache()) {
|
||||
@Override
|
||||
protected FlowGraph flowGraphFactory() {
|
||||
FlowGraphBuilder b = new FilteredFlowGraphBuilder(cha, cache, filter);
|
||||
protected FlowGraph flowGraphFactory(JavaScriptConstructorFunctions selector) {
|
||||
FlowGraphBuilder b = new FilteredFlowGraphBuilder(cha, cache, selector, filter);
|
||||
return b.buildFlowGraph();
|
||||
}
|
||||
};
|
||||
|
|
|
@ -208,7 +208,7 @@ public abstract class Launcher {
|
|||
/**
|
||||
* A thread that runs in a loop, performing the drain() action until a process terminates
|
||||
*/
|
||||
abstract class Drainer extends Thread {
|
||||
protected abstract class Drainer extends Thread {
|
||||
|
||||
// how many ms to sleep before waking up to check the streams?
|
||||
private static final int SLEEP_MS = 5;
|
||||
|
|
Loading…
Reference in New Issue