Merge branch 'master' of https://github.com/wala/WALA into development

This commit is contained in:
Michael Heilmann 2014-06-26 17:52:47 +02:00
commit ea40719069
50 changed files with 1349 additions and 721 deletions

View File

@ -44,6 +44,7 @@ public abstract class AbstractFieldBasedTest extends TestJSCallGraphShape {
ProgressMaster monitor = ProgressMaster.make(new NullProgressMonitor(), 30000, true);
try {
cg = util.buildCG(url, builderType, monitor);
System.err.println(cg);
verifyGraphAssertions(cg, assertions);
} catch(AssertionFailedError afe) {
throw new AssertionFailedError(builderType + ": " + afe.getMessage());

View File

@ -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);
}

View File

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

View File

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

View File

@ -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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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" } }

View File

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

View File

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

View File

@ -4,7 +4,8 @@ Bundle-Name: JavaScript Plug-in
Bundle-SymbolicName: com.ibm.wala.cast.js;singleton:=true
Bundle-Version: 1.3.4.qualifier
Bundle-ClassPath: .,
lib/jericho-html-3.2.jar
lib/jericho-html-3.2.jar,
lib/commons-io-2.4.jar
Bundle-Activator: com.ibm.wala.cast.js.JavaScriptPlugin
Bundle-Vendor: IBM
Export-Package: .,

View File

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

View File

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

View File

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

View File

@ -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) {

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -57,7 +57,7 @@ public class WebPageLoaderFactory extends JavaScriptLoaderFactory {
@Override
protected int doGlobalRead(CAstNode n, WalkContext context, String name, TypeReference type) {
int result = context.currentScope().allocateTempValue();
if (isNestedWithinScriptBody(context) && ! "$$undefined".equals(name) && ! "window".equals(name)) {
if (isNestedWithinScriptBody(context) && ! "$$undefined".equals(name) && !"window".equals(name) && !name.startsWith("$$destructure")) {
// check if field is defined on 'window'
int windowVal = isScriptBody(context)? super.doLocalRead(context, "this", JavaScriptTypes.Root): super.doGlobalRead(n, context, "window", type);
@ -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));

View File

@ -10,564 +10,45 @@
*****************************************************************************/
package com.ibm.wala.cast.js.ipa.callgraph;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.util.Map;
import java.util.Set;
import com.ibm.wala.cast.js.ipa.summaries.JavaScriptSummarizedFunction;
import com.ibm.wala.cast.js.ipa.summaries.JavaScriptSummary;
import com.ibm.wala.cast.js.loader.JSCallSiteReference;
import com.ibm.wala.cast.js.loader.JavaScriptLoader;
import com.ibm.wala.cast.js.ssa.JSInstructionFactory;
import com.ibm.wala.cast.js.ipa.summaries.JavaScriptConstructorFunctions;
import com.ibm.wala.cast.js.types.JavaScriptMethods;
import com.ibm.wala.cast.js.types.JavaScriptTypes;
import com.ibm.wala.cast.types.AstMethodReference;
import com.ibm.wala.classLoader.CallSiteReference;
import com.ibm.wala.classLoader.IClass;
import com.ibm.wala.classLoader.IMethod;
import com.ibm.wala.classLoader.NewSiteReference;
import com.ibm.wala.ipa.callgraph.CGNode;
import com.ibm.wala.ipa.callgraph.MethodTargetSelector;
import com.ibm.wala.ipa.cha.IClassHierarchy;
import com.ibm.wala.ipa.summaries.MethodSummary;
import com.ibm.wala.ssa.ConstantValue;
import com.ibm.wala.ssa.IR;
import com.ibm.wala.ssa.SSAAbstractInvokeInstruction;
import com.ibm.wala.ssa.SymbolTable;
import com.ibm.wala.types.MethodReference;
import com.ibm.wala.types.TypeName;
import com.ibm.wala.types.TypeReference;
import com.ibm.wala.util.collections.HashMapFactory;
import com.ibm.wala.util.collections.Pair;
/**
* generates instructions to simulate the semantics of JS constructor invocations
*
*/
public class JavaScriptConstructTargetSelector implements MethodTargetSelector {
private static final boolean DEBUG = false;
private final IClassHierarchy cha;
private final MethodTargetSelector base;
private final Map<Object, IMethod> constructors = HashMapFactory.make();
public static class JavaScriptConstructor extends JavaScriptSummarizedFunction {
private final String toStringExtra;
private final IClass constructorForType;
private JavaScriptConstructor(MethodReference ref, MethodSummary summary, IClass declaringClass, IClass constructorForType, String toStringExtra) {
super(ref, summary, declaringClass);
this.toStringExtra = toStringExtra;
this.constructorForType = constructorForType;
}
private JavaScriptConstructor(MethodReference ref, MethodSummary summary, IClass declaringClass, IClass constructorForType) {
this(ref, summary, declaringClass, constructorForType, "");
}
@Override
public String toString() {
return "<ctor for " + getReference().getDeclaringClass() + toStringExtra + ">";
}
public IClass constructedType() {
return constructorForType;
}
}
private final JavaScriptConstructorFunctions constructors;
public JavaScriptConstructTargetSelector(IClassHierarchy cha, MethodTargetSelector base) {
this.cha = cha;
this.constructors = new JavaScriptConstructorFunctions(cha);
this.base = base;
}
private IMethod record(Object key, IMethod m) {
constructors.put(key, m);
return m;
}
private IMethod makeNullaryValueConstructor(IClass cls, Object value) {
JSInstructionFactory insts = (JSInstructionFactory)cls.getClassLoader().getInstructionFactory();
MethodReference ref = JavaScriptMethods.makeCtorReference(cls.getReference());
JavaScriptSummary S = new JavaScriptSummary(ref, 1);
S.addStatement(insts.GetInstruction(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);
}

View File

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

View File

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

View File

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

View File

@ -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);
}

View File

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

View File

@ -0,0 +1,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;
}
}
}

View File

@ -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);

View File

@ -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;

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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) {

View File

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

View File

@ -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();

View File

@ -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;
}

View File

@ -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) {

View File

@ -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);
}

View File

@ -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();
}
};

View File

@ -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;