upgrades to lexical soping implements to address some performance issues
fixes to HTML model to capture use of local vars as window state in scripts git-svn-id: https://wala.svn.sourceforge.net/svnroot/wala/trunk@4176 f5eafffb-2e1d-0410-98e4-8ec43c5233c4
This commit is contained in:
parent
10849fcf78
commit
3e573a992d
|
@ -83,5 +83,9 @@ public class AnonymousGenerics {
|
||||||
|
|
||||||
Ops hack = ops;
|
Ops hack = ops;
|
||||||
hack.unary("whatever");
|
hack.unary("whatever");
|
||||||
|
hack.nullary();
|
||||||
|
hack = strQuadrupler;
|
||||||
|
hack.unary("whatever");
|
||||||
|
hack.nullary();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,6 +9,7 @@ import com.ibm.wala.cast.js.html.DomLessSourceExtractor;
|
||||||
import com.ibm.wala.cast.js.html.IdentityUrlResolver;
|
import com.ibm.wala.cast.js.html.IdentityUrlResolver;
|
||||||
import com.ibm.wala.cast.js.html.JSSourceExtractor;
|
import com.ibm.wala.cast.js.html.JSSourceExtractor;
|
||||||
import com.ibm.wala.cast.js.html.MappedSourceModule;
|
import com.ibm.wala.cast.js.html.MappedSourceModule;
|
||||||
|
import com.ibm.wala.cast.js.html.WebPageLoaderFactory;
|
||||||
import com.ibm.wala.cast.js.html.WebUtil;
|
import com.ibm.wala.cast.js.html.WebUtil;
|
||||||
import com.ibm.wala.cast.js.html.jericho.JerichoHtmlParser;
|
import com.ibm.wala.cast.js.html.jericho.JerichoHtmlParser;
|
||||||
import com.ibm.wala.cast.js.ipa.callgraph.JSCFABuilder;
|
import com.ibm.wala.cast.js.ipa.callgraph.JSCFABuilder;
|
||||||
|
@ -22,7 +23,7 @@ import com.ibm.wala.ipa.callgraph.propagation.PointerAnalysis;
|
||||||
import com.ibm.wala.ipa.cha.ClassHierarchyException;
|
import com.ibm.wala.ipa.cha.ClassHierarchyException;
|
||||||
import com.ibm.wala.util.CancelException;
|
import com.ibm.wala.util.CancelException;
|
||||||
|
|
||||||
public class JsViewerDriver {
|
public class JsViewerDriver extends Util {
|
||||||
public static void main(String args[]) throws ClassHierarchyException, IllegalArgumentException, IOException, CancelException {
|
public static void main(String args[]) throws ClassHierarchyException, IllegalArgumentException, IOException, CancelException {
|
||||||
|
|
||||||
if (args.length != 1){
|
if (args.length != 1){
|
||||||
|
@ -39,7 +40,7 @@ public class JsViewerDriver {
|
||||||
|
|
||||||
SourceModule[] sources = getSources(domless, url);
|
SourceModule[] sources = getSources(domless, url);
|
||||||
|
|
||||||
JSCFABuilder builder = Util.makeCGBuilder(sources, false);
|
JSCFABuilder builder = makeCGBuilder(new WebPageLoaderFactory(translatorFactory), sources, false);
|
||||||
builder.setBaseURL(url);
|
builder.setBaseURL(url);
|
||||||
|
|
||||||
CallGraph cg = builder.makeCallGraph(builder.getOptions());
|
CallGraph cg = builder.makeCallGraph(builder.getOptions());
|
||||||
|
|
|
@ -0,0 +1,17 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<launchConfiguration type="org.eclipse.jdt.junit.launchconfig">
|
||||||
|
<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_PATHS">
|
||||||
|
<listEntry value="/com.ibm.wala.cast.js.rhino.test/harness-src/com/ibm/wala/cast/js/test/TestForInLoopHackRhino.java"/>
|
||||||
|
</listAttribute>
|
||||||
|
<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_TYPES">
|
||||||
|
<listEntry value="1"/>
|
||||||
|
</listAttribute>
|
||||||
|
<stringAttribute key="org.eclipse.debug.ui.ATTR_CAPTURE_IN_FILE" value="/tmp/forinhack.out"/>
|
||||||
|
<stringAttribute key="org.eclipse.jdt.junit.CONTAINER" value=""/>
|
||||||
|
<booleanAttribute key="org.eclipse.jdt.junit.KEEPRUNNING_ATTR" value="false"/>
|
||||||
|
<stringAttribute key="org.eclipse.jdt.junit.TESTNAME" value=""/>
|
||||||
|
<stringAttribute key="org.eclipse.jdt.junit.TEST_KIND" value="org.eclipse.jdt.junit.loader.junit4"/>
|
||||||
|
<stringAttribute key="org.eclipse.jdt.launching.JRE_CONTAINER" value="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.launching.macosx.MacOSXType/JVM 1.6"/>
|
||||||
|
<stringAttribute key="org.eclipse.jdt.launching.MAIN_TYPE" value="com.ibm.wala.cast.js.test.TestForInLoopHackRhino"/>
|
||||||
|
<stringAttribute key="org.eclipse.jdt.launching.PROJECT_ATTR" value="com.ibm.wala.cast.js.rhino.test"/>
|
||||||
|
</launchConfiguration>
|
|
@ -0,0 +1,21 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<launchConfiguration type="org.eclipse.jdt.junit.launchconfig">
|
||||||
|
<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_PATHS">
|
||||||
|
<listEntry value="/com.ibm.wala.cast.js.rhino.test/harness-src/com/ibm/wala/cast/js/test/TestMozillaBugPagesRhino.java"/>
|
||||||
|
</listAttribute>
|
||||||
|
<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_TYPES">
|
||||||
|
<listEntry value="1"/>
|
||||||
|
</listAttribute>
|
||||||
|
<stringAttribute key="org.eclipse.debug.ui.ATTR_CAPTURE_IN_FILE" value="/tmp/rhinojs.out"/>
|
||||||
|
<listAttribute key="org.eclipse.debug.ui.favoriteGroups">
|
||||||
|
<listEntry value="org.eclipse.debug.ui.launchGroup.run"/>
|
||||||
|
</listAttribute>
|
||||||
|
<stringAttribute key="org.eclipse.jdt.junit.CONTAINER" value=""/>
|
||||||
|
<booleanAttribute key="org.eclipse.jdt.junit.KEEPRUNNING_ATTR" value="false"/>
|
||||||
|
<stringAttribute key="org.eclipse.jdt.junit.TESTNAME" value=""/>
|
||||||
|
<stringAttribute key="org.eclipse.jdt.junit.TEST_KIND" value="org.eclipse.jdt.junit.loader.junit4"/>
|
||||||
|
<stringAttribute key="org.eclipse.jdt.launching.JRE_CONTAINER" value="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.launching.macosx.MacOSXType/JVM 1.6"/>
|
||||||
|
<stringAttribute key="org.eclipse.jdt.launching.MAIN_TYPE" value="com.ibm.wala.cast.js.test.TestMozillaBugPagesRhino"/>
|
||||||
|
<stringAttribute key="org.eclipse.jdt.launching.PROJECT_ATTR" value="com.ibm.wala.cast.js.rhino.test"/>
|
||||||
|
<stringAttribute key="org.eclipse.jdt.launching.VM_ARGUMENTS" value="-ea"/>
|
||||||
|
</launchConfiguration>
|
|
@ -0,0 +1,263 @@
|
||||||
|
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
|
||||||
|
<title>Untitled Document</title>
|
||||||
|
</head>
|
||||||
|
<script>
|
||||||
|
(function top () {
|
||||||
|
var c = n.jQuery = n.$ = function dollar (a, d) {
|
||||||
|
return new c.fn.init(a, d)
|
||||||
|
}
|
||||||
|
c.fn = c.prototype = {
|
||||||
|
init: function init (a, d) {
|
||||||
|
a = a || document;
|
||||||
|
if (a.nodeType) {
|
||||||
|
this[0] = a;
|
||||||
|
this.length = 1;
|
||||||
|
this.context = a;
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
if (typeof a === "string") {
|
||||||
|
var f = r.exec(a);
|
||||||
|
if (f && (f[1] || !d)) if (f[1]) a = c.clean([f[1]], d);
|
||||||
|
else {
|
||||||
|
if ((d = document.getElementById(f[3])) && d.id != f[3]) return c().find(a);
|
||||||
|
f = c(d || []);
|
||||||
|
f.context = document;
|
||||||
|
f.selector = a;
|
||||||
|
return f
|
||||||
|
} else return c(d).find(a)
|
||||||
|
} else if (c.isFunction(a)) return c(document).ready(a);
|
||||||
|
if (a.selector && a.context) {
|
||||||
|
this.selector =
|
||||||
|
a.selector;
|
||||||
|
this.context = a.context
|
||||||
|
}
|
||||||
|
return this.setArray(c.isArray(a) ? a : c.makeArray(a))
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
c.extend = c.fn.extend = function extend () {
|
||||||
|
var a =
|
||||||
|
arguments[0] || {},
|
||||||
|
d = 1,
|
||||||
|
f = arguments.length,
|
||||||
|
j = false,
|
||||||
|
q;
|
||||||
|
if (typeof a === "boolean") {
|
||||||
|
j = a;
|
||||||
|
a = arguments[1] || {};
|
||||||
|
d = 2
|
||||||
|
}
|
||||||
|
if (typeof a !== "object" && !c.isFunction(a)) a = {};
|
||||||
|
if (f == d) {
|
||||||
|
a = this;
|
||||||
|
--d
|
||||||
|
}
|
||||||
|
for (; d < f; d++) if ((q = arguments[d]) != null) for (var t in q) {
|
||||||
|
var y = a[t],
|
||||||
|
A = q[t];
|
||||||
|
if (a !== A) if (j && A && typeof A === "object" && !A.nodeType) a[t] = c.extend(j, y || (A.length != null ? [] : {}), A);
|
||||||
|
else if (A !== void 0) a[t] = A
|
||||||
|
}
|
||||||
|
return a
|
||||||
|
};
|
||||||
|
c.extend({
|
||||||
|
noConflict: function noConflict (a) {
|
||||||
|
n.$ =
|
||||||
|
B;
|
||||||
|
if (a) n.jQuery = w;
|
||||||
|
return c
|
||||||
|
},
|
||||||
|
isFunction: 2,
|
||||||
|
each: function each (a, d, f) {
|
||||||
|
var j, q = 0,
|
||||||
|
t = a.length;
|
||||||
|
if (f) if (t === void 0) for (j in a) {
|
||||||
|
if (d.apply(a[j], f) === false) break
|
||||||
|
} else for (; q < t;) {
|
||||||
|
if (d.apply(a[q++], f) === false) break
|
||||||
|
} else if (t === void 0) for (j in a) {
|
||||||
|
if (d.call(a[j], j, a[j]) === false) break
|
||||||
|
} else for (f = a[0]; q < t && d.call(f, q, f) !== false; f = a[++q]);
|
||||||
|
return a
|
||||||
|
},
|
||||||
|
className: {
|
||||||
|
add: function add (a, d) {
|
||||||
|
c.each((d || "").split(/\s+/), function (f, j) {
|
||||||
|
if (a.nodeType == 1 && !c.className.has(a.className, j)) a.className += (a.className ? " " : "") + j
|
||||||
|
})
|
||||||
|
},
|
||||||
|
remove: function remove (a, d) {
|
||||||
|
if (a.nodeType == 1) a.className = d !== void 0 ? c.grep(a.className.split(/\s+/), function (f) {
|
||||||
|
return !c.className.has(d, f)
|
||||||
|
}).join(" ") : ""
|
||||||
|
},
|
||||||
|
has: function has (a, d) {
|
||||||
|
return a && c.inArray(d, (a.className || a).toString().split(/\s+/)) > -1
|
||||||
|
}
|
||||||
|
},
|
||||||
|
swap: function swap (a, d, f) {
|
||||||
|
var j = {};
|
||||||
|
for (var q in d) {
|
||||||
|
j[q] = a.style[q];
|
||||||
|
a.style[q] = d[q]
|
||||||
|
}
|
||||||
|
f.call(a);
|
||||||
|
for (q in d) a.style[q] = j[q]
|
||||||
|
},
|
||||||
|
css: function css (a, d, f, j) {
|
||||||
|
if (d == "width" || d == "height") {
|
||||||
|
var q;
|
||||||
|
f = {
|
||||||
|
position: "absolute",
|
||||||
|
visibility: "hidden",
|
||||||
|
display: "block"
|
||||||
|
};
|
||||||
|
var t = d == "width" ? ["Left", "Right"] : ["Top", "Bottom"],
|
||||||
|
y = function () {
|
||||||
|
q = d == "width" ? a.offsetWidth : a.offsetHeight;
|
||||||
|
j !== "border" && c.each(t, function () {
|
||||||
|
j || (q -= parseFloat(c.curCSS(a, "padding" + this, true)) || 0);
|
||||||
|
if (j === "margin") q += parseFloat(c.curCSS(a, "margin" + this, true)) || 0;
|
||||||
|
else q -= parseFloat(c.curCSS(a, "border" + this + "Width", true)) || 0
|
||||||
|
})
|
||||||
|
};
|
||||||
|
a.offsetWidth !== 0 ? y() : c.swap(a, f, y);
|
||||||
|
return Math.max(0, Math.round(q))
|
||||||
|
}
|
||||||
|
return c.curCSS(a, d, f)
|
||||||
|
},
|
||||||
|
curCSS: function curCSS (a, d, f) {
|
||||||
|
var j, q = a.style;
|
||||||
|
if (d == "opacity" && !c.support.opacity) {
|
||||||
|
j = c.attr(q, "opacity");
|
||||||
|
return j == "" ? "1" : j
|
||||||
|
}
|
||||||
|
if (d.match(/float/i)) d = W;
|
||||||
|
if (!f && q && q[d]) j = q[d];
|
||||||
|
else if (F.getComputedStyle) {
|
||||||
|
if (d.match(/float/i)) d = "float";
|
||||||
|
d = d.replace(/([A-Z])/g, "-$1").toLowerCase();
|
||||||
|
if (a = F.getComputedStyle(a, null)) j = a.getPropertyValue(d);
|
||||||
|
if (d == "opacity" && j == "") j = "1"
|
||||||
|
} else if (a.currentStyle) {
|
||||||
|
j = d.replace(/\-(\w)/g, function (t, y) {
|
||||||
|
return y.toUpperCase()
|
||||||
|
});
|
||||||
|
j = a.currentStyle[d] || a.currentStyle[j];
|
||||||
|
if (!/^\d+(px)?$/i.test(j) && /^\d/.test(j)) {
|
||||||
|
d = q.left;
|
||||||
|
f = a.runtimeStyle.left;
|
||||||
|
a.runtimeStyle.left = a.currentStyle.left;
|
||||||
|
q.left = j || 0;
|
||||||
|
j = q.pixelLeft + "px";
|
||||||
|
q.left = d;
|
||||||
|
a.runtimeStyle.left = f
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return j
|
||||||
|
},
|
||||||
|
clean: function clean (a, d, f) {
|
||||||
|
d = d || document;
|
||||||
|
if (typeof d.createElement === "undefined") d = d.ownerDocument || d[0] && d[0].ownerDocument || document;
|
||||||
|
if (!f && a.length === 1 && typeof a[0] === "string") {
|
||||||
|
var j = /^<(\w+)\s*\/?>$/.exec(a[0]);
|
||||||
|
if (j) return [d.createElement(j[1])]
|
||||||
|
}
|
||||||
|
c.each(a, function (y, A) {
|
||||||
|
if (typeof A === "number") A += "";
|
||||||
|
if (A) {
|
||||||
|
if (typeof A === "string") {
|
||||||
|
A = A.replace(/(<(\w+)[^>]*?)\/>/g, function (M, Q, S) {
|
||||||
|
return S.match(/^(abbr|br|col|img|input|link|meta|param|hr|area|embed)$/i) ? M : Q + "></" + S + ">"
|
||||||
|
});
|
||||||
|
y = A.replace(/^\s+/, "").substring(0, 10).toLowerCase();
|
||||||
|
var L = !y.indexOf("<opt") && [1, "<select multiple='multiple'>", "</select>"] || !y.indexOf("<leg") && [1, "<fieldset>", "</fieldset>"] || y.match(/^<(thead|tbody|tfoot|colg|cap)/) && [1, "<table>", "</table>"] || !y.indexOf("<tr") && [2, "<table><tbody>", "</tbody></table>"] || (!y.indexOf("<td") || !y.indexOf("<th")) && [3, "<table><tbody><tr>", "</tr></tbody></table>"] || !y.indexOf("<col") && [2, "<table><tbody></tbody><colgroup>", "</colgroup></table>"] || !c.support.htmlSerialize && [1, "div<div>", "</div>"] || [0, "", ""];
|
||||||
|
for (t.innerHTML = L[1] + A + L[2]; L[0]--;) t = t.lastChild;
|
||||||
|
if (!c.support.tbody) {
|
||||||
|
var N = /<tbody/i.test(A);
|
||||||
|
y = !y.indexOf("<table") && !N ? t.firstChild && t.firstChild.childNodes : L[1] == "<table>" && !N ? t.childNodes : [];
|
||||||
|
for (L = y.length - 1; L >= 0; --L) c.nodeName(y[L], "tbody") && !y[L].childNodes.length && y[L].parentNode.removeChild(y[L])
|
||||||
|
}!c.support.leadingWhitespace && /^\s/.test(A) && t.insertBefore(d.createTextNode(A.match(/^\s*/)[0]), t.firstChild);
|
||||||
|
A = c.makeArray(t.childNodes)
|
||||||
|
}
|
||||||
|
if (A.nodeType) q.push(A);
|
||||||
|
else q = c.merge(q, A)
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if (f) {
|
||||||
|
for (a = 0; q[a]; a++) if (c.nodeName(q[a], "script") && (!q[a].type || q[a].type.toLowerCase() === "text/javascript")) j.push(q[a].parentNode ? q[a].parentNode.removeChild(q[a]) : q[a]);
|
||||||
|
else {
|
||||||
|
q[a].nodeType === 1 && q.splice.apply(q, [a + 1, 0].concat(c.makeArray(q[a].getElementsByTagName("script"))));
|
||||||
|
f.appendChild(q[a])
|
||||||
|
}
|
||||||
|
return j
|
||||||
|
}
|
||||||
|
return q
|
||||||
|
},
|
||||||
|
attr: function attr (a, d, f) {
|
||||||
|
if (!(!a || a.nodeType == 3 || a.nodeType == 8)) {
|
||||||
|
var j = !c.isXMLDoc(a),
|
||||||
|
q = f !== void 0;
|
||||||
|
d = j && c.props[d] || d;
|
||||||
|
if (a.tagName) {
|
||||||
|
var t = /href|src|style/.test(d);
|
||||||
|
if (d in a && j && !t) {
|
||||||
|
if (q) {
|
||||||
|
if (d == "type" && c.nodeName(a, "input") && a.parentNode) throw "type property can't be changed";
|
||||||
|
a[d] = f
|
||||||
|
}
|
||||||
|
if (c.nodeName(a, "form") && a.getAttributeNode(d)) return a.getAttributeNode(d).nodeValue;
|
||||||
|
if (d == "tabIndex") return (d = a.getAttributeNode("tabIndex")) && d.specified ? d.value : a.nodeName.match(/(button|input|object|select|textarea)/i) ? 0 : a.nodeName.match(/^(a|area)$/i) && a.href ? 0 : void 0;
|
||||||
|
return a[d]
|
||||||
|
}
|
||||||
|
if (!c.support.style && j && d == "style") return c.attr(a.style, "cssText", f);
|
||||||
|
q && a.setAttribute(d, "" + f);
|
||||||
|
a = !c.support.hrefNormalized && j && t ? a.getAttribute(d, 2) : a.getAttribute(d);
|
||||||
|
return a === null ? void 0 : a
|
||||||
|
}
|
||||||
|
if (!c.support.opacity && d == "opacity") {
|
||||||
|
if (q) {
|
||||||
|
a.zoom = 1;
|
||||||
|
a.filter = (a.filter || "").replace(/alpha\([^)]*\)/, "") + (parseInt(f) + "" == "NaN" ? "" : "alpha(opacity=" + f * 100 + ")")
|
||||||
|
}
|
||||||
|
return a.filter && a.filter.indexOf("opacity=") >= 0 ? parseFloat(a.filter.match(/opacity=([^)]*)/)[1]) / 100 + "" : ""
|
||||||
|
}
|
||||||
|
d = d.replace(/-([a-z])/ig, function (y, A) {
|
||||||
|
return A.toUpperCase()
|
||||||
|
});
|
||||||
|
if (q) a[d] = f;
|
||||||
|
return a[d]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
makeArray: function makeArray (a) {
|
||||||
|
var d = [];
|
||||||
|
if (a != null) {
|
||||||
|
var f = a.length;
|
||||||
|
if (f == null || typeof a === "string" || c.isFunction(a) || a.setInterval) d[0] = a;
|
||||||
|
else for (; f;) d[--f] = a[f]
|
||||||
|
}
|
||||||
|
return d
|
||||||
|
},
|
||||||
|
inArray: function inArray (a, d) {
|
||||||
|
for (var f = 0, j = d.length; f < j; f++) if (d[f] === a) return f;
|
||||||
|
return -1
|
||||||
|
},
|
||||||
|
merge: function merge (a, d) {
|
||||||
|
var f = 0,
|
||||||
|
j, q = a.length;
|
||||||
|
if (c.support.getAll) for (;
|
||||||
|
(j = d[f++]) != null;) a[q++] = j;
|
||||||
|
else for (;
|
||||||
|
(j =
|
||||||
|
d[f++]) != null;) if (j.nodeType != 8) a[q++] = j;
|
||||||
|
return a
|
||||||
|
},
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
})();
|
||||||
|
|
||||||
|
</script>
|
|
@ -0,0 +1,288 @@
|
||||||
|
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
|
||||||
|
<title>Untitled Document</title>
|
||||||
|
</head>
|
||||||
|
<script>
|
||||||
|
(function top () {
|
||||||
|
var c = n.jQuery = n.$ = function dollar (a, d) {
|
||||||
|
return new c.fn.init(a, d)
|
||||||
|
}
|
||||||
|
c.fn = c.prototype = {
|
||||||
|
init: function init (a, d) {
|
||||||
|
a = a || document;
|
||||||
|
if (a.nodeType) {
|
||||||
|
this[0] = a;
|
||||||
|
this.length = 1;
|
||||||
|
this.context = a;
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
if (typeof a === "string") {
|
||||||
|
var f = r.exec(a);
|
||||||
|
if (f && (f[1] || !d)) if (f[1]) a = c.clean([f[1]], d);
|
||||||
|
else {
|
||||||
|
if ((d = document.getElementById(f[3])) && d.id != f[3]) return c().find(a);
|
||||||
|
f = c(d || []);
|
||||||
|
f.context = document;
|
||||||
|
f.selector = a;
|
||||||
|
return f
|
||||||
|
} else return c(d).find(a)
|
||||||
|
} else if (c.isFunction(a)) return c(document).ready(a);
|
||||||
|
if (a.selector && a.context) {
|
||||||
|
this.selector =
|
||||||
|
a.selector;
|
||||||
|
this.context = a.context
|
||||||
|
}
|
||||||
|
return this.setArray(c.isArray(a) ? a : c.makeArray(a))
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
c.extend = c.fn.extend = function extend () {
|
||||||
|
var a =
|
||||||
|
arguments[0] || {},
|
||||||
|
d = 1,
|
||||||
|
f = arguments.length,
|
||||||
|
j = false,
|
||||||
|
q;
|
||||||
|
if (typeof a === "boolean") {
|
||||||
|
j = a;
|
||||||
|
a = arguments[1] || {};
|
||||||
|
d = 2
|
||||||
|
}
|
||||||
|
if (typeof a !== "object" && !c.isFunction(a)) a = {};
|
||||||
|
if (f == d) {
|
||||||
|
a = this;
|
||||||
|
--d
|
||||||
|
}
|
||||||
|
for (; d < f; d++)
|
||||||
|
if ((q = arguments[d]) != null) {
|
||||||
|
for (var t in q) {
|
||||||
|
(function _forin_body_1(t) {
|
||||||
|
var y = a[t],
|
||||||
|
A = q[t];
|
||||||
|
if (a !== A)
|
||||||
|
if (j && A && typeof A === "object" && !A.nodeType) a[t] = c.extend(j, y || (A.length != null ? [] : {}), A);
|
||||||
|
else if (A !== void 0) a[t] = A
|
||||||
|
})(t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return a
|
||||||
|
};
|
||||||
|
c.extend({
|
||||||
|
noConflict: function noConflict (a) {
|
||||||
|
n.$ =
|
||||||
|
B;
|
||||||
|
if (a) n.jQuery = w;
|
||||||
|
return c
|
||||||
|
},
|
||||||
|
isFunction: 2,
|
||||||
|
each: function each (a, d, f) {
|
||||||
|
var j, q = 0,
|
||||||
|
t = a.length;
|
||||||
|
if (f) if (t === void 0) { for (j in a) {
|
||||||
|
if ((function _forin_body_2(j) {
|
||||||
|
if (d.apply(a[j], f) === false) return true;
|
||||||
|
else return false;
|
||||||
|
})(j)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} } else for (; q < t;) {
|
||||||
|
if (d.apply(a[q++], f) === false) break
|
||||||
|
} else if (t === void 0) { for (j in a) {
|
||||||
|
if ((function _forin_body_3(j) {
|
||||||
|
if (d.call(a[j], j, a[j]) === false)
|
||||||
|
return true;
|
||||||
|
else
|
||||||
|
return false;
|
||||||
|
})(j)) {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else for (f = a[0]; q < t && d.call(f, q, f) !== false; f = a[++q]);
|
||||||
|
return a
|
||||||
|
},
|
||||||
|
className: {
|
||||||
|
add: function add (a, d) {
|
||||||
|
c.each((d || "").split(/\s+/), function (f, j) {
|
||||||
|
if (a.nodeType == 1 && !c.className.has(a.className, j)) a.className += (a.className ? " " : "") + j
|
||||||
|
})
|
||||||
|
},
|
||||||
|
remove: function remove (a, d) {
|
||||||
|
if (a.nodeType == 1) a.className = d !== void 0 ? c.grep(a.className.split(/\s+/), function (f) {
|
||||||
|
return !c.className.has(d, f)
|
||||||
|
}).join(" ") : ""
|
||||||
|
},
|
||||||
|
has: function has (a, d) {
|
||||||
|
return a && c.inArray(d, (a.className || a).toString().split(/\s+/)) > -1
|
||||||
|
}
|
||||||
|
},
|
||||||
|
swap: function swap (a, d, f) {
|
||||||
|
var j = {};
|
||||||
|
for (var q in d) {
|
||||||
|
(function _forin_body_4(q) {
|
||||||
|
j[q] = a.style[q];
|
||||||
|
a.style[q] = d[q]
|
||||||
|
})(q);
|
||||||
|
}
|
||||||
|
f.call(a);
|
||||||
|
for (q in d) {
|
||||||
|
(function _forin_body_5(q) {
|
||||||
|
a.style[q] = j[q]
|
||||||
|
})(q);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
css: function css (a, d, f, j) {
|
||||||
|
if (d == "width" || d == "height") {
|
||||||
|
var q;
|
||||||
|
f = {
|
||||||
|
position: "absolute",
|
||||||
|
visibility: "hidden",
|
||||||
|
display: "block"
|
||||||
|
};
|
||||||
|
var t = d == "width" ? ["Left", "Right"] : ["Top", "Bottom"],
|
||||||
|
y = function () {
|
||||||
|
q = d == "width" ? a.offsetWidth : a.offsetHeight;
|
||||||
|
j !== "border" && c.each(t, function () {
|
||||||
|
j || (q -= parseFloat(c.curCSS(a, "padding" + this, true)) || 0);
|
||||||
|
if (j === "margin") q += parseFloat(c.curCSS(a, "margin" + this, true)) || 0;
|
||||||
|
else q -= parseFloat(c.curCSS(a, "border" + this + "Width", true)) || 0
|
||||||
|
})
|
||||||
|
};
|
||||||
|
a.offsetWidth !== 0 ? y() : c.swap(a, f, y);
|
||||||
|
return Math.max(0, Math.round(q))
|
||||||
|
}
|
||||||
|
return c.curCSS(a, d, f)
|
||||||
|
},
|
||||||
|
curCSS: function curCSS (a, d, f) {
|
||||||
|
var j, q = a.style;
|
||||||
|
if (d == "opacity" && !c.support.opacity) {
|
||||||
|
j = c.attr(q, "opacity");
|
||||||
|
return j == "" ? "1" : j
|
||||||
|
}
|
||||||
|
if (d.match(/float/i)) d = W;
|
||||||
|
if (!f && q && q[d]) j = q[d];
|
||||||
|
else if (F.getComputedStyle) {
|
||||||
|
if (d.match(/float/i)) d = "float";
|
||||||
|
d = d.replace(/([A-Z])/g, "-$1").toLowerCase();
|
||||||
|
if (a = F.getComputedStyle(a, null)) j = a.getPropertyValue(d);
|
||||||
|
if (d == "opacity" && j == "") j = "1"
|
||||||
|
} else if (a.currentStyle) {
|
||||||
|
j = d.replace(/\-(\w)/g, function (t, y) {
|
||||||
|
return y.toUpperCase()
|
||||||
|
});
|
||||||
|
j = a.currentStyle[d] || a.currentStyle[j];
|
||||||
|
if (!/^\d+(px)?$/i.test(j) && /^\d/.test(j)) {
|
||||||
|
d = q.left;
|
||||||
|
f = a.runtimeStyle.left;
|
||||||
|
a.runtimeStyle.left = a.currentStyle.left;
|
||||||
|
q.left = j || 0;
|
||||||
|
j = q.pixelLeft + "px";
|
||||||
|
q.left = d;
|
||||||
|
a.runtimeStyle.left = f
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return j
|
||||||
|
},
|
||||||
|
clean: function clean (a, d, f) {
|
||||||
|
d = d || document;
|
||||||
|
if (typeof d.createElement === "undefined") d = d.ownerDocument || d[0] && d[0].ownerDocument || document;
|
||||||
|
if (!f && a.length === 1 && typeof a[0] === "string") {
|
||||||
|
var j = /^<(\w+)\s*\/?>$/.exec(a[0]);
|
||||||
|
if (j) return [d.createElement(j[1])]
|
||||||
|
}
|
||||||
|
c.each(a, function (y, A) {
|
||||||
|
if (typeof A === "number") A += "";
|
||||||
|
if (A) {
|
||||||
|
if (typeof A === "string") {
|
||||||
|
A = A.replace(/(<(\w+)[^>]*?)\/>/g, function (M, Q, S) {
|
||||||
|
return S.match(/^(abbr|br|col|img|input|link|meta|param|hr|area|embed)$/i) ? M : Q + "></" + S + ">"
|
||||||
|
});
|
||||||
|
y = A.replace(/^\s+/, "").substring(0, 10).toLowerCase();
|
||||||
|
var L = !y.indexOf("<opt") && [1, "<select multiple='multiple'>", "</select>"] || !y.indexOf("<leg") && [1, "<fieldset>", "</fieldset>"] || y.match(/^<(thead|tbody|tfoot|colg|cap)/) && [1, "<table>", "</table>"] || !y.indexOf("<tr") && [2, "<table><tbody>", "</tbody></table>"] || (!y.indexOf("<td") || !y.indexOf("<th")) && [3, "<table><tbody><tr>", "</tr></tbody></table>"] || !y.indexOf("<col") && [2, "<table><tbody></tbody><colgroup>", "</colgroup></table>"] || !c.support.htmlSerialize && [1, "div<div>", "</div>"] || [0, "", ""];
|
||||||
|
for (t.innerHTML = L[1] + A + L[2]; L[0]--;) t = t.lastChild;
|
||||||
|
if (!c.support.tbody) {
|
||||||
|
var N = /<tbody/i.test(A);
|
||||||
|
y = !y.indexOf("<table") && !N ? t.firstChild && t.firstChild.childNodes : L[1] == "<table>" && !N ? t.childNodes : [];
|
||||||
|
for (L = y.length - 1; L >= 0; --L) c.nodeName(y[L], "tbody") && !y[L].childNodes.length && y[L].parentNode.removeChild(y[L])
|
||||||
|
}!c.support.leadingWhitespace && /^\s/.test(A) && t.insertBefore(d.createTextNode(A.match(/^\s*/)[0]), t.firstChild);
|
||||||
|
A = c.makeArray(t.childNodes)
|
||||||
|
}
|
||||||
|
if (A.nodeType) q.push(A);
|
||||||
|
else q = c.merge(q, A)
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if (f) {
|
||||||
|
for (a = 0; q[a]; a++) if (c.nodeName(q[a], "script") && (!q[a].type || q[a].type.toLowerCase() === "text/javascript")) j.push(q[a].parentNode ? q[a].parentNode.removeChild(q[a]) : q[a]);
|
||||||
|
else {
|
||||||
|
q[a].nodeType === 1 && q.splice.apply(q, [a + 1, 0].concat(c.makeArray(q[a].getElementsByTagName("script"))));
|
||||||
|
f.appendChild(q[a])
|
||||||
|
}
|
||||||
|
return j
|
||||||
|
}
|
||||||
|
return q
|
||||||
|
},
|
||||||
|
attr: function attr (a, d, f) {
|
||||||
|
if (!(!a || a.nodeType == 3 || a.nodeType == 8)) {
|
||||||
|
var j = !c.isXMLDoc(a),
|
||||||
|
q = f !== void 0;
|
||||||
|
d = j && c.props[d] || d;
|
||||||
|
if (a.tagName) {
|
||||||
|
var t = /href|src|style/.test(d);
|
||||||
|
if (d in a && j && !t) {
|
||||||
|
if (q) {
|
||||||
|
if (d == "type" && c.nodeName(a, "input") && a.parentNode) throw "type property can't be changed";
|
||||||
|
a[d] = f
|
||||||
|
}
|
||||||
|
if (c.nodeName(a, "form") && a.getAttributeNode(d)) return a.getAttributeNode(d).nodeValue;
|
||||||
|
if (d == "tabIndex") return (d = a.getAttributeNode("tabIndex")) && d.specified ? d.value : a.nodeName.match(/(button|input|object|select|textarea)/i) ? 0 : a.nodeName.match(/^(a|area)$/i) && a.href ? 0 : void 0;
|
||||||
|
return a[d]
|
||||||
|
}
|
||||||
|
if (!c.support.style && j && d == "style") return c.attr(a.style, "cssText", f);
|
||||||
|
q && a.setAttribute(d, "" + f);
|
||||||
|
a = !c.support.hrefNormalized && j && t ? a.getAttribute(d, 2) : a.getAttribute(d);
|
||||||
|
return a === null ? void 0 : a
|
||||||
|
}
|
||||||
|
if (!c.support.opacity && d == "opacity") {
|
||||||
|
if (q) {
|
||||||
|
a.zoom = 1;
|
||||||
|
a.filter = (a.filter || "").replace(/alpha\([^)]*\)/, "") + (parseInt(f) + "" == "NaN" ? "" : "alpha(opacity=" + f * 100 + ")")
|
||||||
|
}
|
||||||
|
return a.filter && a.filter.indexOf("opacity=") >= 0 ? parseFloat(a.filter.match(/opacity=([^)]*)/)[1]) / 100 + "" : ""
|
||||||
|
}
|
||||||
|
d = d.replace(/-([a-z])/ig, function (y, A) {
|
||||||
|
return A.toUpperCase()
|
||||||
|
});
|
||||||
|
if (q) a[d] = f;
|
||||||
|
return a[d]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
makeArray: function makeArray (a) {
|
||||||
|
var d = [];
|
||||||
|
if (a != null) {
|
||||||
|
var f = a.length;
|
||||||
|
if (f == null || typeof a === "string" || c.isFunction(a) || a.setInterval) d[0] = a;
|
||||||
|
else for (; f;) d[--f] = a[f]
|
||||||
|
}
|
||||||
|
return d
|
||||||
|
},
|
||||||
|
inArray: function inArray (a, d) {
|
||||||
|
for (var f = 0, j = d.length; f < j; f++) if (d[f] === a) return f;
|
||||||
|
return -1
|
||||||
|
},
|
||||||
|
merge: function merge (a, d) {
|
||||||
|
var f = 0,
|
||||||
|
j, q = a.length;
|
||||||
|
if (c.support.getAll) for (;
|
||||||
|
(j = d[f++]) != null;) a[q++] = j;
|
||||||
|
else for (;
|
||||||
|
(j =
|
||||||
|
d[f++]) != null;) if (j.nodeType != 8) a[q++] = j;
|
||||||
|
return a
|
||||||
|
},
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
})();
|
||||||
|
|
||||||
|
</script>
|
|
@ -0,0 +1,33 @@
|
||||||
|
<HTML>
|
||||||
|
|
||||||
|
<TITLE>Welcome!</TITLE>
|
||||||
|
|
||||||
|
Hi
|
||||||
|
|
||||||
|
<SCRIPT>
|
||||||
|
|
||||||
|
var x = function _f1() {
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
function _f2(x) {
|
||||||
|
x();
|
||||||
|
}
|
||||||
|
|
||||||
|
_f2(window.x);
|
||||||
|
|
||||||
|
window.z = function _f3() {
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
function _f4(x) {
|
||||||
|
x();
|
||||||
|
}
|
||||||
|
|
||||||
|
_f4(z);
|
||||||
|
</SCRIPT>
|
||||||
|
|
||||||
|
<BR>
|
||||||
|
Welcome to our system
|
||||||
|
|
||||||
|
</HTML>
|
|
@ -69,4 +69,46 @@ function outer( x ) {
|
||||||
return x+z;
|
return x+z;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function c2() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
function c3() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
function fa2(x) {
|
||||||
|
x();
|
||||||
|
}
|
||||||
|
|
||||||
|
function fa3(x) {
|
||||||
|
x();
|
||||||
|
}
|
||||||
|
|
||||||
|
function aa() {
|
||||||
|
var c1 = function _c1() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
var fa = function _fa1(x) {
|
||||||
|
x();
|
||||||
|
}
|
||||||
|
|
||||||
|
function bb(x) {
|
||||||
|
fa = x;
|
||||||
|
}
|
||||||
|
|
||||||
|
fa(c1);
|
||||||
|
|
||||||
|
bb(fa2);
|
||||||
|
|
||||||
|
fa(c2);
|
||||||
|
|
||||||
|
bb(fa3);
|
||||||
|
|
||||||
|
fa(c3);
|
||||||
|
}
|
||||||
|
|
||||||
var result = outer( 5 );
|
var result = outer( 5 );
|
||||||
|
|
||||||
|
aa();
|
||||||
|
|
|
@ -45,6 +45,24 @@ public class TestForInLoopHack extends TestJSCallGraphShape {
|
||||||
Util.dumpCG(builder.getPointerAnalysis(), CG);
|
Util.dumpCG(builder.getPointerAnalysis(), CG);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test public void testJQueryWithHack() throws IOException, IllegalArgumentException, CancelException {
|
||||||
|
URL url = getClass().getClassLoader().getResource("pages/jquery_hacked.html");
|
||||||
|
JSCFABuilder builder = Util.makeHTMLCGBuilder(url);
|
||||||
|
addHackedForInLoopSensitivity(builder);
|
||||||
|
CallGraph CG = builder.makeCallGraph(builder.getOptions());
|
||||||
|
Util.dumpCG(builder.getPointerAnalysis(), CG);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
@Test public void testJQueryEx1WithHack() throws IOException, IllegalArgumentException, CancelException {
|
||||||
|
URL url = getClass().getClassLoader().getResource("pages/jquery/ex1.html");
|
||||||
|
JSCFABuilder builder = Util.makeHTMLCGBuilder(url);
|
||||||
|
addHackedForInLoopSensitivity(builder);
|
||||||
|
CallGraph CG = builder.makeCallGraph(builder.getOptions());
|
||||||
|
Util.dumpCG(builder.getPointerAnalysis(), CG);
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
private static final Object[][] assertionsForBadForin = new Object[][] {
|
private static final Object[][] assertionsForBadForin = new Object[][] {
|
||||||
new Object[] { ROOT,
|
new Object[] { ROOT,
|
||||||
new String[] { "tests/badforin.js" } },
|
new String[] { "tests/badforin.js" } },
|
||||||
|
|
|
@ -32,6 +32,7 @@ public abstract class TestMediawikiCallGraphShape extends TestJSCallGraphShape {
|
||||||
URL url = new URL("http://en.wikipedia.org/wiki/2009_swine_flu_outbreak");
|
URL url = new URL("http://en.wikipedia.org/wiki/2009_swine_flu_outbreak");
|
||||||
CallGraph CG = Util.makeHTMLCG(url);
|
CallGraph CG = Util.makeHTMLCG(url);
|
||||||
verifyGraphAssertions(CG, assertionsForSwineFlu);
|
verifyGraphAssertions(CG, assertionsForSwineFlu);
|
||||||
|
System.err.println(CG);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -281,12 +281,31 @@ public abstract class TestSimplePageCallGraphShape extends TestJSCallGraphShape
|
||||||
Util.makeHTMLCG(url);
|
Util.makeHTMLCG(url);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static final Object[][] assertionsForWindowx = new Object[][] {
|
||||||
|
new Object[] { ROOT, new String[] { "windowx.html" } },
|
||||||
|
new Object[] { "windowx.html", new String[] { "windowx.html/__WINDOW_MAIN__" } },
|
||||||
|
new Object[] { "windowx.html/__WINDOW_MAIN__", new String[] { "windowx.html/__WINDOW_MAIN__/_f2", "windowx.html/__WINDOW_MAIN__/_f4" } },
|
||||||
|
new Object[] { "windowx.html/__WINDOW_MAIN__/_f2", new String[] { "windowx.html/__WINDOW_MAIN__/_f1" } },
|
||||||
|
new Object[] { "windowx.html/__WINDOW_MAIN__/_f4", new String[] { "windowx.html/__WINDOW_MAIN__/_f3" } }
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
@Test public void testWindowx() throws IOException, IllegalArgumentException, CancelException {
|
||||||
|
URL url = getClass().getClassLoader().getResource("pages/windowx.html");
|
||||||
|
JSCFABuilder builder = Util.makeHTMLCGBuilder(url);
|
||||||
|
CallGraph CG = builder.makeCallGraph(builder.getOptions());
|
||||||
|
Util.dumpCG(builder.getPointerAnalysis(), CG);
|
||||||
|
verifyGraphAssertions(CG, assertionsForWindowx);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@Test public void testJQuery() throws IOException, IllegalArgumentException, CancelException {
|
@Test public void testJQuery() throws IOException, IllegalArgumentException, CancelException {
|
||||||
URL url = getClass().getClassLoader().getResource("pages/jquery.html");
|
URL url = getClass().getClassLoader().getResource("pages/jquery.html");
|
||||||
CallGraph CG = Util.makeHTMLCG(url);
|
CallGraph CG = Util.makeHTMLCG(url);
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
@Test public void testDojoTest() throws IllegalArgumentException, IOException, CancelException {
|
@Test public void testDojoTest() throws IllegalArgumentException, IOException, CancelException {
|
||||||
URL url = getClass().getClassLoader().getResource("pages/dojo/test.html");
|
URL url = getClass().getClassLoader().getResource("pages/dojo/test.html");
|
||||||
CallGraph CG = Util.makeHTMLCG(url);
|
CallGraph CG = Util.makeHTMLCG(url);
|
||||||
|
|
|
@ -19,6 +19,7 @@ import java.util.Set;
|
||||||
import junit.framework.Assert;
|
import junit.framework.Assert;
|
||||||
|
|
||||||
import com.ibm.wala.cast.js.html.MappedSourceModule;
|
import com.ibm.wala.cast.js.html.MappedSourceModule;
|
||||||
|
import com.ibm.wala.cast.js.html.WebPageLoaderFactory;
|
||||||
import com.ibm.wala.cast.js.html.WebUtil;
|
import com.ibm.wala.cast.js.html.WebUtil;
|
||||||
import com.ibm.wala.cast.js.ipa.callgraph.JSCFABuilder;
|
import com.ibm.wala.cast.js.ipa.callgraph.JSCFABuilder;
|
||||||
import com.ibm.wala.cast.js.ipa.callgraph.JSZeroOrOneXCFABuilder;
|
import com.ibm.wala.cast.js.ipa.callgraph.JSZeroOrOneXCFABuilder;
|
||||||
|
@ -77,7 +78,7 @@ public class Util extends com.ibm.wala.cast.js.ipa.callgraph.Util {
|
||||||
|
|
||||||
public static CallGraph makeScriptCG(SourceModule[] scripts, boolean useOneCFA) throws IOException, IllegalArgumentException,
|
public static CallGraph makeScriptCG(SourceModule[] scripts, boolean useOneCFA) throws IOException, IllegalArgumentException,
|
||||||
CancelException {
|
CancelException {
|
||||||
PropagationCallGraphBuilder b = makeCGBuilder(scripts, useOneCFA);
|
PropagationCallGraphBuilder b = makeCGBuilder(makeLoaders(), scripts, useOneCFA);
|
||||||
CallGraph CG = b.makeCallGraph(b.getOptions());
|
CallGraph CG = b.makeCallGraph(b.getOptions());
|
||||||
dumpCG(b.getPointerAnalysis(), CG);
|
dumpCG(b.getPointerAnalysis(), CG);
|
||||||
return CG;
|
return CG;
|
||||||
|
@ -86,7 +87,7 @@ public class Util extends com.ibm.wala.cast.js.ipa.callgraph.Util {
|
||||||
public static JSCFABuilder makeHTMLCGBuilder(URL url) throws IOException {
|
public static JSCFABuilder makeHTMLCGBuilder(URL url) throws IOException {
|
||||||
JavaScriptLoader.addBootstrapFile(WebUtil.preamble);
|
JavaScriptLoader.addBootstrapFile(WebUtil.preamble);
|
||||||
Set<MappedSourceModule> script = WebUtil.extractScriptFromHTML(url);
|
Set<MappedSourceModule> script = WebUtil.extractScriptFromHTML(url);
|
||||||
JSCFABuilder builder = makeCGBuilder(script.toArray(new SourceModule[script.size()]), false);
|
JSCFABuilder builder = makeCGBuilder(new WebPageLoaderFactory(translatorFactory), script.toArray(new SourceModule[script.size()]), false);
|
||||||
builder.setBaseURL(url);
|
builder.setBaseURL(url);
|
||||||
return builder;
|
return builder;
|
||||||
}
|
}
|
||||||
|
@ -105,8 +106,7 @@ public class Util extends com.ibm.wala.cast.js.ipa.callgraph.Util {
|
||||||
return CG;
|
return CG;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static JSCFABuilder makeCGBuilder(SourceModule[] scripts, boolean useOneCFA) throws IOException {
|
public static JSCFABuilder makeCGBuilder(JavaScriptLoaderFactory loaders, SourceModule[] scripts, boolean useOneCFA) throws IOException {
|
||||||
JavaScriptLoaderFactory loaders = makeLoaders();
|
|
||||||
AnalysisScope scope = makeScope(scripts, loaders, JavaScriptLoader.JS);
|
AnalysisScope scope = makeScope(scripts, loaders, JavaScriptLoader.JS);
|
||||||
return makeCG(loaders, scope, useOneCFA);
|
return makeCG(loaders, scope, useOneCFA);
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,7 +15,7 @@ note_post_parameters = function notePostParameters(url) {
|
||||||
// hook for analysis of Web pages
|
// hook for analysis of Web pages
|
||||||
};
|
};
|
||||||
|
|
||||||
function NamedNodeList() {
|
NamedNodeList = function NamedNodeList() {
|
||||||
var maxLength = 10;
|
var maxLength = 10;
|
||||||
var local = new Array(10);
|
var local = new Array(10);
|
||||||
var counter = -1;
|
var counter = -1;
|
||||||
|
@ -85,7 +85,7 @@ function NamedNodeList() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function DOMNode() { // An impostor for the Node class
|
DOMNode = function DOMNode() { // An impostor for the Node class
|
||||||
this.childNodes = new NamedNodeList();
|
this.childNodes = new NamedNodeList();
|
||||||
this.insertBefore = function insertBefore(newChild, refChild) {
|
this.insertBefore = function insertBefore(newChild, refChild) {
|
||||||
this.childNodes.insertBefore(newChild, refChild);
|
this.childNodes.insertBefore(newChild, refChild);
|
||||||
|
@ -116,7 +116,7 @@ function DOMNode() { // An impostor for the Node class
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function DOMDocument() {
|
DOMDocument = function DOMDocument() {
|
||||||
this.temp = DOMNode;
|
this.temp = DOMNode;
|
||||||
this.temp();
|
this.temp();
|
||||||
|
|
||||||
|
@ -137,11 +137,11 @@ function DOMDocument() {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
function HTMLBody(){
|
HTMLBody = function HTMLBody(){
|
||||||
this.innerHTML = new String();
|
this.innerHTML = new String();
|
||||||
}
|
}
|
||||||
|
|
||||||
function DOMHTMLDocument() {
|
DOMHTMLDocument = function DOMHTMLDocument() {
|
||||||
this.temp = DOMDocument;
|
this.temp = DOMDocument;
|
||||||
this.temp();
|
this.temp();
|
||||||
this.URL = new String();
|
this.URL = new String();
|
||||||
|
@ -150,7 +150,7 @@ function DOMHTMLDocument() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
function Location(){
|
Location = function Location(){
|
||||||
this.host = new String();
|
this.host = new String();
|
||||||
this.hostname = new String();
|
this.hostname = new String();
|
||||||
this.href = new String();
|
this.href = new String();
|
||||||
|
@ -163,14 +163,14 @@ function Location(){
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
function DOMWindow(){
|
DOMWindow = function DOMWindow(){
|
||||||
this.name = new String();
|
this.name = new String();
|
||||||
this.open = function window_open(url, stuff) {
|
this.open = function window_open(url, stuff) {
|
||||||
note_url(url);
|
note_url(url);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
function DOJOObj(){
|
DOJOObj = function DOJOObj(){
|
||||||
this.moduleUrl = function module_url(str1, str2){
|
this.moduleUrl = function module_url(str1, str2){
|
||||||
return str1 + str2;
|
return str1 + str2;
|
||||||
}
|
}
|
||||||
|
@ -194,7 +194,7 @@ window.XMLHttpRequest = XMLHttpRequest;
|
||||||
|
|
||||||
var dojo = new DOJOObj();
|
var dojo = new DOJOObj();
|
||||||
|
|
||||||
function DOMElement() { // An impostor for the Element class
|
DOMElement = function DOMElement() { // An impostor for the Element class
|
||||||
// inherits from Node
|
// inherits from Node
|
||||||
this.temp = DOMNode;
|
this.temp = DOMNode;
|
||||||
this.temp();
|
this.temp();
|
||||||
|
@ -215,7 +215,7 @@ function DOMElement() { // An impostor for the Element class
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function DOMHTMLElement() { // An impostor for the HTMLElement class
|
DOMHTMLElement = function DOMHTMLElement() { // An impostor for the HTMLElement class
|
||||||
// inherits from Element
|
// inherits from Element
|
||||||
this.temp = DOMElement;
|
this.temp = DOMElement;
|
||||||
this.temp();
|
this.temp();
|
||||||
|
@ -234,7 +234,7 @@ function DOMHTMLElement() { // An impostor for the HTMLElement class
|
||||||
var dynamic_node = 0;
|
var dynamic_node = 0;
|
||||||
|
|
||||||
// Just a hack until all HTML elements have corresponding constructors
|
// Just a hack until all HTML elements have corresponding constructors
|
||||||
function DOMHTMLGenericElement(tagName) {
|
DOMHTMLGenericElement = function DOMHTMLGenericElement(tagName) {
|
||||||
// inherits from Element
|
// inherits from Element
|
||||||
this.temp = DOMHTMLElement;
|
this.temp = DOMHTMLElement;
|
||||||
this.temp();
|
this.temp();
|
||||||
|
@ -253,7 +253,7 @@ function DOMHTMLGenericElement(tagName) {
|
||||||
|
|
||||||
var formCount = 0;
|
var formCount = 0;
|
||||||
|
|
||||||
function DOMHTMLFormElement() {
|
DOMHTMLFormElement = function DOMHTMLFormElement() {
|
||||||
// inherits from HTMLElement
|
// inherits from HTMLElement
|
||||||
this.temp = DOMHTMLElement;
|
this.temp = DOMHTMLElement;
|
||||||
this.temp();
|
this.temp();
|
||||||
|
@ -281,7 +281,7 @@ function DOMHTMLFormElement() {
|
||||||
this.target = null;
|
this.target = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
function DOMHTMLTableElement () {
|
DOMHTMLTableElement = function DOMHTMLTableElement () {
|
||||||
// inherits from HTMLElement
|
// inherits from HTMLElement
|
||||||
this.temp = DOMHTMLElement;
|
this.temp = DOMHTMLElement;
|
||||||
this.temp();
|
this.temp();
|
||||||
|
|
|
@ -0,0 +1,91 @@
|
||||||
|
package com.ibm.wala.cast.js.html;
|
||||||
|
|
||||||
|
import com.ibm.wala.cast.ir.translator.TranslatorToIR;
|
||||||
|
import com.ibm.wala.cast.js.loader.JavaScriptLoader;
|
||||||
|
import com.ibm.wala.cast.js.loader.JavaScriptLoaderFactory;
|
||||||
|
import com.ibm.wala.cast.js.ssa.JSInstructionFactory;
|
||||||
|
import com.ibm.wala.cast.js.translator.JSAstTranslator;
|
||||||
|
import com.ibm.wala.cast.js.translator.JavaScriptTranslatorFactory;
|
||||||
|
import com.ibm.wala.cast.tree.CAst;
|
||||||
|
import com.ibm.wala.cast.tree.CAstNode;
|
||||||
|
import com.ibm.wala.cast.tree.impl.CAstImpl;
|
||||||
|
import com.ibm.wala.cast.tree.impl.CAstOperator;
|
||||||
|
import com.ibm.wala.classLoader.IClassLoader;
|
||||||
|
import com.ibm.wala.ipa.cha.IClassHierarchy;
|
||||||
|
|
||||||
|
public class WebPageLoaderFactory extends JavaScriptLoaderFactory {
|
||||||
|
|
||||||
|
public WebPageLoaderFactory(JavaScriptTranslatorFactory factory) {
|
||||||
|
super(factory);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected IClassLoader makeTheLoader(IClassHierarchy cha) {
|
||||||
|
return new JavaScriptLoader( cha, translatorFactory ) {
|
||||||
|
@Override
|
||||||
|
protected TranslatorToIR initTranslator() {
|
||||||
|
return new JSAstTranslator(this) {
|
||||||
|
private final CAst Ast = new CAstImpl();
|
||||||
|
|
||||||
|
private boolean isScriptBody(WalkContext context) {
|
||||||
|
return context.top().getName().equals( "__WINDOW_MAIN__" );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected int doGlobalRead(CAstNode n, WalkContext context, String name) {
|
||||||
|
int result = context.currentScope().allocateTempValue();
|
||||||
|
if (isScriptBody(context) && ! "$$undefined".equals(name) && ! "window".equals(name)) {
|
||||||
|
|
||||||
|
// check if field is defined on 'window'
|
||||||
|
int windowVal = super.doLocalRead(context, "this");
|
||||||
|
int isDefined = context.currentScope().allocateTempValue();
|
||||||
|
context.currentScope().getConstantValue(name);
|
||||||
|
doIsFieldDefined(context, isDefined, windowVal, Ast.makeConstant(name));
|
||||||
|
context.cfg().addInstruction(
|
||||||
|
insts.ConditionalBranchInstruction(
|
||||||
|
translateConditionOpcode(CAstOperator.OP_NE),
|
||||||
|
null,
|
||||||
|
isDefined,
|
||||||
|
context.currentScope().getConstantValue(new Integer(0))));
|
||||||
|
PreBasicBlock srcB = context.cfg().getCurrentBlock();
|
||||||
|
|
||||||
|
// field lookup of value
|
||||||
|
context.cfg().newBlock(true);
|
||||||
|
context.cfg().addInstruction(((JSInstructionFactory) insts).GetInstruction(result, windowVal, name));
|
||||||
|
context.cfg().addInstruction(insts.GotoInstruction());
|
||||||
|
PreBasicBlock trueB = context.cfg().getCurrentBlock();
|
||||||
|
|
||||||
|
// read global
|
||||||
|
context.cfg().newBlock(false);
|
||||||
|
PreBasicBlock falseB = context.cfg().getCurrentBlock();
|
||||||
|
int sr = super.doGlobalRead(n, context, name);
|
||||||
|
context.cfg().addInstruction(((JSInstructionFactory) insts).AssignInstruction(result, sr));
|
||||||
|
|
||||||
|
// end
|
||||||
|
context.cfg().newBlock(true);
|
||||||
|
|
||||||
|
context.cfg().addEdge(trueB, context.cfg().getCurrentBlock());
|
||||||
|
context.cfg().addEdge(srcB, falseB);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
return super.doGlobalRead(n, context, name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void doLocalWrite(WalkContext context, String nm, int rval) {
|
||||||
|
if (isScriptBody(context)) {
|
||||||
|
int windowVal = super.doLocalRead(context, "this");
|
||||||
|
context.currentScope().getConstantValue(nm);
|
||||||
|
context.cfg().addInstruction(((JSInstructionFactory) insts).PutInstruction(windowVal, rval, nm));
|
||||||
|
}
|
||||||
|
|
||||||
|
super.doLocalWrite(context, nm, rval);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
|
@ -482,7 +482,7 @@ public class JSSSAPropagationCallGraphBuilder extends AstSSAPropagationCallGraph
|
||||||
|
|
||||||
IR sourceIR = getCFAContextInterpreter().getIR(caller);
|
IR sourceIR = getCFAContextInterpreter().getIR(caller);
|
||||||
SymbolTable sourceST = sourceIR.getSymbolTable();
|
SymbolTable sourceST = sourceIR.getSymbolTable();
|
||||||
|
|
||||||
IR targetIR = getCFAContextInterpreter().getIR(target);
|
IR targetIR = getCFAContextInterpreter().getIR(target);
|
||||||
SymbolTable targetST = targetIR.getSymbolTable();
|
SymbolTable targetST = targetIR.getSymbolTable();
|
||||||
|
|
||||||
|
@ -504,7 +504,7 @@ public class JSSSAPropagationCallGraphBuilder extends AstSSAPropagationCallGraph
|
||||||
|
|
||||||
// pass actual arguments to formals in the normal way
|
// pass actual arguments to formals in the normal way
|
||||||
for (int i = 0; i < Math.min(paramCount, argCount); i++) {
|
for (int i = 0; i < Math.min(paramCount, argCount); i++) {
|
||||||
int fn = targetST.getConstant(i);
|
InstanceKey[] fn = new InstanceKey[]{ getInstanceKeyForConstant(JavaScriptTypes.Number, i) };
|
||||||
PointerKey F = getTargetPointerKey(target, i);
|
PointerKey F = getTargetPointerKey(target, i);
|
||||||
|
|
||||||
if (constParams != null && constParams[i] != null) {
|
if (constParams != null && constParams[i] != null) {
|
||||||
|
@ -528,7 +528,7 @@ public class JSSSAPropagationCallGraphBuilder extends AstSSAPropagationCallGraph
|
||||||
if (paramCount < argCount) {
|
if (paramCount < argCount) {
|
||||||
if (av != -1) {
|
if (av != -1) {
|
||||||
for (int i = paramCount; i < argCount; i++) {
|
for (int i = paramCount; i < argCount; i++) {
|
||||||
int fn = targetST.getConstant(i);
|
InstanceKey[] fn = new InstanceKey[]{ getInstanceKeyForConstant(JavaScriptTypes.Number, i) };
|
||||||
if (constParams != null && constParams[i] != null) {
|
if (constParams != null && constParams[i] != null) {
|
||||||
targetVisitor.newFieldWrite(target, av, fn, constParams[i]);
|
targetVisitor.newFieldWrite(target, av, fn, constParams[i]);
|
||||||
} else {
|
} else {
|
||||||
|
@ -554,8 +554,8 @@ public class JSSSAPropagationCallGraphBuilder extends AstSSAPropagationCallGraph
|
||||||
|
|
||||||
// write `length' in argument objects
|
// write `length' in argument objects
|
||||||
if (av != -1) {
|
if (av != -1) {
|
||||||
int svn = targetST.getConstant(argCount);
|
InstanceKey[] svn = new InstanceKey[]{ getInstanceKeyForConstant(JavaScriptTypes.Number, argCount) };
|
||||||
int lnv = targetST.getConstant("length");
|
InstanceKey[] lnv = new InstanceKey[]{ getInstanceKeyForConstant(JavaScriptTypes.String, "length") };
|
||||||
targetVisitor.newFieldWrite(target, av, lnv, svn);
|
targetVisitor.newFieldWrite(target, av, lnv, svn);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -10,6 +10,7 @@
|
||||||
*****************************************************************************/
|
*****************************************************************************/
|
||||||
package com.ibm.wala.cast.js.ipa.callgraph;
|
package com.ibm.wala.cast.js.ipa.callgraph;
|
||||||
|
|
||||||
|
import com.ibm.wala.cast.ipa.callgraph.LexicalScopingResolverContexts;
|
||||||
import com.ibm.wala.cast.ipa.callgraph.ScopeMappingKeysContextSelector;
|
import com.ibm.wala.cast.ipa.callgraph.ScopeMappingKeysContextSelector;
|
||||||
import com.ibm.wala.ipa.callgraph.AnalysisCache;
|
import com.ibm.wala.ipa.callgraph.AnalysisCache;
|
||||||
import com.ibm.wala.ipa.callgraph.AnalysisOptions;
|
import com.ibm.wala.ipa.callgraph.AnalysisOptions;
|
||||||
|
@ -42,6 +43,7 @@ public class JSZeroOrOneXCFABuilder extends JSCFABuilder {
|
||||||
ContextSelector contextSelector = appContextSelector == null ? def : new DelegatingContextSelector(appContextSelector, def);
|
ContextSelector contextSelector = appContextSelector == null ? def : new DelegatingContextSelector(appContextSelector, def);
|
||||||
contextSelector = new ScopeMappingKeysContextSelector(contextSelector);
|
contextSelector = new ScopeMappingKeysContextSelector(contextSelector);
|
||||||
contextSelector = new JavaScriptConstructorContextSelector(contextSelector);
|
contextSelector = new JavaScriptConstructorContextSelector(contextSelector);
|
||||||
|
contextSelector = new LexicalScopingResolverContexts(this, contextSelector);
|
||||||
if (doOneCFA) {
|
if (doOneCFA) {
|
||||||
contextSelector = new nCFAContextSelector(1, contextSelector);
|
contextSelector = new nCFAContextSelector(1, contextSelector);
|
||||||
}
|
}
|
||||||
|
|
|
@ -58,7 +58,7 @@ public class Util extends com.ibm.wala.cast.ipa.callgraph.Util {
|
||||||
* the translator factory to be used for analysis TODO: pass the factory where
|
* the translator factory to be used for analysis TODO: pass the factory where
|
||||||
* needed instead of using a global?
|
* needed instead of using a global?
|
||||||
*/
|
*/
|
||||||
private static JavaScriptTranslatorFactory translatorFactory;
|
protected static JavaScriptTranslatorFactory translatorFactory;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set up the translator factory. This method should be called before invoking
|
* Set up the translator factory. This method should be called before invoking
|
||||||
|
|
|
@ -21,7 +21,7 @@ import com.ibm.wala.types.ClassLoaderReference;
|
||||||
* Creates the single {@link IClassLoader class loader} used for JavaScript.
|
* Creates the single {@link IClassLoader class loader} used for JavaScript.
|
||||||
*/
|
*/
|
||||||
public class JavaScriptLoaderFactory extends SingleClassLoaderFactory {
|
public class JavaScriptLoaderFactory extends SingleClassLoaderFactory {
|
||||||
private final JavaScriptTranslatorFactory translatorFactory;
|
protected final JavaScriptTranslatorFactory translatorFactory;
|
||||||
|
|
||||||
public JavaScriptLoaderFactory(JavaScriptTranslatorFactory factory) {
|
public JavaScriptLoaderFactory(JavaScriptTranslatorFactory factory) {
|
||||||
this.translatorFactory = factory;
|
this.translatorFactory = factory;
|
||||||
|
|
|
@ -58,7 +58,7 @@ public class JSAstTranslator extends AstTranslator {
|
||||||
}
|
}
|
||||||
|
|
||||||
protected boolean treatGlobalsAsLexicallyScoped() {
|
protected boolean treatGlobalsAsLexicallyScoped() {
|
||||||
return true;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected boolean useLocalValuesForLexicalVars() {
|
protected boolean useLocalValuesForLexicalVars() {
|
||||||
|
@ -145,12 +145,7 @@ public class JSAstTranslator extends AstTranslator {
|
||||||
|
|
||||||
// force creation of these constants by calling the getter methods
|
// force creation of these constants by calling the getter methods
|
||||||
symtab.getNullConstant();
|
symtab.getNullConstant();
|
||||||
symtab.getConstant("arguments");
|
|
||||||
symtab.getConstant("length");
|
|
||||||
for (int i = 0; i < 20; i++) {
|
|
||||||
symtab.getConstant(i);
|
|
||||||
}
|
|
||||||
|
|
||||||
((JavaScriptLoader) loader).defineCodeBodyCode("L" + fnName, cfg, symtab, hasCatchBlock, caughtTypes, hasMonitorOp, LI,
|
((JavaScriptLoader) loader).defineCodeBodyCode("L" + fnName, cfg, symtab, hasCatchBlock, caughtTypes, hasMonitorOp, LI,
|
||||||
debugInfo);
|
debugInfo);
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,6 +17,7 @@ import java.util.Set;
|
||||||
|
|
||||||
import com.ibm.wala.analysis.reflection.ReflectionContextInterpreter;
|
import com.ibm.wala.analysis.reflection.ReflectionContextInterpreter;
|
||||||
import com.ibm.wala.cast.ipa.callgraph.AstCallGraph.AstCGNode;
|
import com.ibm.wala.cast.ipa.callgraph.AstCallGraph.AstCGNode;
|
||||||
|
import com.ibm.wala.cast.ipa.callgraph.LexicalScopingResolverContexts.Resolver;
|
||||||
import com.ibm.wala.cast.ipa.callgraph.ScopeMappingInstanceKeys.ScopeMappingInstanceKey;
|
import com.ibm.wala.cast.ipa.callgraph.ScopeMappingInstanceKeys.ScopeMappingInstanceKey;
|
||||||
import com.ibm.wala.cast.ir.ssa.AbstractLexicalInvoke;
|
import com.ibm.wala.cast.ir.ssa.AbstractLexicalInvoke;
|
||||||
import com.ibm.wala.cast.ir.ssa.AstAssertInstruction;
|
import com.ibm.wala.cast.ir.ssa.AstAssertInstruction;
|
||||||
|
@ -26,6 +27,7 @@ import com.ibm.wala.cast.ir.ssa.AstGlobalWrite;
|
||||||
import com.ibm.wala.cast.ir.ssa.AstIRFactory.AstIR;
|
import com.ibm.wala.cast.ir.ssa.AstIRFactory.AstIR;
|
||||||
import com.ibm.wala.cast.ir.ssa.AstInstructionVisitor;
|
import com.ibm.wala.cast.ir.ssa.AstInstructionVisitor;
|
||||||
import com.ibm.wala.cast.ir.ssa.AstIsDefinedInstruction;
|
import com.ibm.wala.cast.ir.ssa.AstIsDefinedInstruction;
|
||||||
|
import com.ibm.wala.cast.ir.ssa.AstLexicalAccess;
|
||||||
import com.ibm.wala.cast.ir.ssa.AstLexicalAccess.Access;
|
import com.ibm.wala.cast.ir.ssa.AstLexicalAccess.Access;
|
||||||
import com.ibm.wala.cast.ir.ssa.AstLexicalRead;
|
import com.ibm.wala.cast.ir.ssa.AstLexicalRead;
|
||||||
import com.ibm.wala.cast.ir.ssa.AstLexicalWrite;
|
import com.ibm.wala.cast.ir.ssa.AstLexicalWrite;
|
||||||
|
@ -301,39 +303,30 @@ public abstract class AstSSAPropagationCallGraphBuilder extends SSAPropagationCa
|
||||||
return ((AstPointerKeyFactory) getBuilder().getPointerKeyFactory()).getPointerKeysForReflectedFieldWrite(I, F);
|
return ((AstPointerKeyFactory) getBuilder().getPointerKeyFactory()).getPointerKeysForReflectedFieldWrite(I, F);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void visitLexical(final LexicalOperator op) {
|
private void visitLexical(AstLexicalAccess instruction, final LexicalOperator op) {
|
||||||
final PointerKey function = getPointerKeyForLocal(1);
|
op.doLexicalPointerKeys(false);
|
||||||
if (contentsAreInvariant(symbolTable, du, 1)) {
|
if (! checkLexicalInstruction(instruction)) {
|
||||||
op.doLexicalPointerKeys();
|
system.newSideEffect(op, getPointerKeyForLocal(1));
|
||||||
} else {
|
|
||||||
system.newSideEffect(op, function);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// when a new caller is added for node, re-process the lexical access
|
|
||||||
class LexicalScopingCallback implements Function<Object, Object> {
|
|
||||||
public Object apply(Object ignore) {
|
|
||||||
op.doLexicalPointerKeys();
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
private LexicalOperator getOperator() {
|
|
||||||
return op;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int hashCode() {
|
|
||||||
return op.hashCode();
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean equals(Object o) {
|
|
||||||
return (o instanceof LexicalScopingCallback) && ((LexicalScopingCallback) o).getOperator().equals(op);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
((AstCGNode) node).addCallback(new LexicalScopingCallback());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void visitAstLexicalRead(AstLexicalRead instruction) {
|
private boolean checkLexicalInstruction(AstLexicalAccess instruction) {
|
||||||
visitLexical(new LexicalOperator((AstCGNode) node, instruction.getAccesses(), true) {
|
Resolver r = (Resolver)node.getContext().get(LexicalScopingResolverContexts.RESOLVER);
|
||||||
|
if (r == null) {
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
for(Access a : instruction.getAccesses()) {
|
||||||
|
if (r.getLexicalSites(a) == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void visitAstLexicalRead(AstLexicalRead instruction) {
|
||||||
|
visitLexical(instruction, new LexicalOperator((AstCGNode) node, instruction.getAccesses(), true) {
|
||||||
protected void action(PointerKey lexicalKey, int vn) {
|
protected void action(PointerKey lexicalKey, int vn) {
|
||||||
PointerKey lval = getPointerKeyForLocal(vn);
|
PointerKey lval = getPointerKeyForLocal(vn);
|
||||||
if (lexicalKey instanceof LocalPointerKey) {
|
if (lexicalKey instanceof LocalPointerKey) {
|
||||||
|
@ -360,7 +353,7 @@ public abstract class AstSSAPropagationCallGraphBuilder extends SSAPropagationCa
|
||||||
}
|
}
|
||||||
|
|
||||||
public void visitAstLexicalWrite(AstLexicalWrite instruction) {
|
public void visitAstLexicalWrite(AstLexicalWrite instruction) {
|
||||||
visitLexical(new LexicalOperator((AstCGNode) node, instruction.getAccesses(), false) {
|
visitLexical(instruction, new LexicalOperator((AstCGNode) node, instruction.getAccesses(), false) {
|
||||||
protected void action(PointerKey lexicalKey, int vn) {
|
protected void action(PointerKey lexicalKey, int vn) {
|
||||||
PointerKey rval = getPointerKeyForLocal(vn);
|
PointerKey rval = getPointerKeyForLocal(vn);
|
||||||
if (contentsAreInvariant(symbolTable, du, vn)) {
|
if (contentsAreInvariant(symbolTable, du, vn)) {
|
||||||
|
@ -403,11 +396,10 @@ public abstract class AstSSAPropagationCallGraphBuilder extends SSAPropagationCa
|
||||||
} catch (UTFDataFormatException e) {
|
} catch (UTFDataFormatException e) {
|
||||||
Assertions.UNREACHABLE();
|
Assertions.UNREACHABLE();
|
||||||
}
|
}
|
||||||
int fieldNameVn = symtab.getConstant(fieldName);
|
|
||||||
|
|
||||||
final PointerKey objKey = getPointerKeyForLocal(objVn);
|
final PointerKey objKey = getPointerKeyForLocal(objVn);
|
||||||
|
|
||||||
final InstanceKey[] fieldNameKeys = getInvariantContents(fieldNameVn);
|
final InstanceKey[] fieldNameKeys = new InstanceKey[]{ getInstanceKeyForConstant(fieldName) };
|
||||||
assert fieldNameKeys.length == 1;
|
assert fieldNameKeys.length == 1;
|
||||||
|
|
||||||
if (contentsAreInvariant(symtab, du, objVn)) {
|
if (contentsAreInvariant(symtab, du, objVn)) {
|
||||||
|
@ -539,12 +531,14 @@ public abstract class AstSSAPropagationCallGraphBuilder extends SSAPropagationCa
|
||||||
// callees where the name is not written;
|
// callees where the name is not written;
|
||||||
// in such cases, the original value (rk) is preserved
|
// in such cases, the original value (rk) is preserved
|
||||||
PointerKey rk = getBuilder().getPointerKeyForLocal(node, r.valueNumber);
|
PointerKey rk = getBuilder().getPointerKeyForLocal(node, r.valueNumber);
|
||||||
PointerKey wk = getBuilder().getPointerKeyForLocal(node, w.valueNumber);
|
PointerKey wk = getBuilder().getPointerKeyForLocal(node, w.valueNumber);
|
||||||
if (contentsAreInvariant(symbolTable, du, r.valueNumber)) {
|
if (contentsAreInvariant(node.getIR().getSymbolTable(), du, r.valueNumber)) {
|
||||||
system.recordImplicitPointsToSet(rk);
|
system.recordImplicitPointsToSet(rk);
|
||||||
for (InstanceKey ik : getInvariantContents(r.valueNumber)) {
|
final InstanceKey[] objKeys = getInvariantContents(r.valueNumber);
|
||||||
system.newConstraint(wk, ik);
|
|
||||||
}
|
for (int i = 0; i < objKeys.length; i++) {
|
||||||
|
system.newConstraint(wk, objKeys[0]);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
system.newConstraint(wk, assignOperator, rk);
|
system.newConstraint(wk, assignOperator, rk);
|
||||||
}
|
}
|
||||||
|
@ -600,7 +594,8 @@ public abstract class AstSSAPropagationCallGraphBuilder extends SSAPropagationCa
|
||||||
* {@link AstConstraintVisitor#handleRootLexicalReference(String, String, CGNode)}
|
* {@link AstConstraintVisitor#handleRootLexicalReference(String, String, CGNode)}
|
||||||
* .
|
* .
|
||||||
*/
|
*/
|
||||||
private void doLexicalPointerKeys() {
|
private void doLexicalPointerKeys(boolean funargsOnly) {
|
||||||
|
Resolver r = (Resolver)node.getContext().get(LexicalScopingResolverContexts.RESOLVER);
|
||||||
for (int i = 0; i < accesses.length; i++) {
|
for (int i = 0; i < accesses.length; i++) {
|
||||||
final String name = accesses[i].variableName;
|
final String name = accesses[i].variableName;
|
||||||
final String definer = accesses[i].variableDefiner;
|
final String definer = accesses[i].variableDefiner;
|
||||||
|
@ -609,49 +604,31 @@ public abstract class AstSSAPropagationCallGraphBuilder extends SSAPropagationCa
|
||||||
if (AstTranslator.DEBUG_LEXICAL)
|
if (AstTranslator.DEBUG_LEXICAL)
|
||||||
System.err.println(("looking up lexical parent " + definer));
|
System.err.println(("looking up lexical parent " + definer));
|
||||||
|
|
||||||
for (Iterator<CGNode> DS = getLexicalDefiners(node, definer).iterator(); DS.hasNext();) {
|
Iterator<Pair<CallSiteReference,CGNode>> sites;
|
||||||
final CGNode D = DS.next();
|
if (r != null && (sites = r.getLexicalSites(accesses[i])) != null) {
|
||||||
|
if (! funargsOnly) {
|
||||||
Iterator PS = new NumberedDFSDiscoverTimeIterator<CGNode>(getBuilder().getCallGraph(), node) {
|
while(sites.hasNext()) {
|
||||||
/**
|
Pair<CallSiteReference,CGNode> x = sites.next();
|
||||||
*
|
PointerKey V =
|
||||||
*/
|
isLoad ? getLocalReadKey(x.snd, x.fst, name, definer) : getLocalWriteKey(x.snd, x.fst, name, definer);
|
||||||
private static final long serialVersionUID = 4546217460630659884L;
|
|
||||||
|
|
||||||
protected void visitEdge(CGNode callee, CGNode caller) {
|
|
||||||
CGNode from = (CGNode) caller;
|
|
||||||
CGNode to = (CGNode) callee;
|
|
||||||
|
|
||||||
for (Iterator SS = cg.getPossibleSites(from, to); SS.hasNext();) {
|
|
||||||
CallSiteReference site = (CallSiteReference) SS.next();
|
|
||||||
|
|
||||||
PointerKey V = isLoad ? getLocalReadKey(from, site, name, definer, D) : getLocalWriteKey(from, site, name,
|
|
||||||
definer, D);
|
|
||||||
|
|
||||||
if (V != null) {
|
if (V != null) {
|
||||||
action(V, vn);
|
action(V, vn);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
protected Iterator<? extends CGNode> getConnected(CGNode n) {
|
Set<CGNode> creators = getLexicalDefiners(node, Pair.make(name, definer));
|
||||||
if (n.equals(D))
|
for(CGNode n : creators) {
|
||||||
return EmptyIterator.instance();
|
PointerKey funargKey = handleRootLexicalReference(name, definer, n);
|
||||||
else
|
action(funargKey, vn);
|
||||||
// traverse backwards
|
|
||||||
return G.getPredNodes(n);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
while (PS.hasNext()) {
|
|
||||||
PS.next();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public byte evaluate(PointsToSetVariable lhs, PointsToSetVariable rhs) {
|
public byte evaluate(PointsToSetVariable lhs, PointsToSetVariable rhs) {
|
||||||
doLexicalPointerKeys();
|
doLexicalPointerKeys(true);
|
||||||
return NOT_CHANGED;
|
return NOT_CHANGED;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -699,7 +676,7 @@ public abstract class AstSSAPropagationCallGraphBuilder extends SSAPropagationCa
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private Set<CGNode> getLexicalDefiners(final CGNode opNode, final String definer) {
|
private Set<CGNode> getLexicalDefiners(final CGNode opNode, final Pair<String,String> definer) {
|
||||||
if (definer == null) {
|
if (definer == null) {
|
||||||
return Collections.singleton(getBuilder().getCallGraph().getFakeRootNode());
|
return Collections.singleton(getBuilder().getCallGraph().getFakeRootNode());
|
||||||
|
|
||||||
|
@ -716,7 +693,10 @@ public abstract class AstSSAPropagationCallGraphBuilder extends SSAPropagationCa
|
||||||
for (int f = 0; f < functionKeys.length; f++) {
|
for (int f = 0; f < functionKeys.length; f++) {
|
||||||
system.findOrCreateIndexForInstanceKey(functionKeys[f]);
|
system.findOrCreateIndexForInstanceKey(functionKeys[f]);
|
||||||
ScopeMappingInstanceKey K = (ScopeMappingInstanceKey) functionKeys[f];
|
ScopeMappingInstanceKey K = (ScopeMappingInstanceKey) functionKeys[f];
|
||||||
result.add(K.getDefiningNode(definer));
|
Iterator<CGNode> x = K.getFunargNodes(definer);
|
||||||
|
while (x.hasNext()) {
|
||||||
|
result.add(x.next());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
PointsToSetVariable FV = system.findOrCreatePointsToSet(F);
|
PointsToSetVariable FV = system.findOrCreatePointsToSet(F);
|
||||||
|
@ -726,7 +706,10 @@ public abstract class AstSSAPropagationCallGraphBuilder extends SSAPropagationCa
|
||||||
InstanceKey iKey = system.getInstanceKey(ptr);
|
InstanceKey iKey = system.getInstanceKey(ptr);
|
||||||
if (iKey instanceof ScopeMappingInstanceKey) {
|
if (iKey instanceof ScopeMappingInstanceKey) {
|
||||||
ScopeMappingInstanceKey K = (ScopeMappingInstanceKey) iKey;
|
ScopeMappingInstanceKey K = (ScopeMappingInstanceKey) iKey;
|
||||||
result.add(K.getDefiningNode(definer));
|
Iterator<CGNode> x = K.getFunargNodes(definer);
|
||||||
|
while (x.hasNext()) {
|
||||||
|
result.add(x.next());
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
Assertions.UNREACHABLE("unexpected instance key " + iKey);
|
Assertions.UNREACHABLE("unexpected instance key " + iKey);
|
||||||
}
|
}
|
||||||
|
@ -842,163 +825,135 @@ public abstract class AstSSAPropagationCallGraphBuilder extends SSAPropagationCa
|
||||||
* now know the name is accessed by some transitive callee), thereby
|
* now know the name is accessed by some transitive callee), thereby
|
||||||
* requiring marking of the IR as mutated.
|
* requiring marking of the IR as mutated.
|
||||||
*/
|
*/
|
||||||
private PointerKey getLocalReadKey(CGNode n, CallSiteReference callSite, String name, String definer, CGNode definingNode) {
|
private PointerKey getLocalReadKey(CGNode n, CallSiteReference callSite, String name, String definer) {
|
||||||
IMethod M = n.getMethod();
|
AstIR ir = (AstIR) n.getIR();
|
||||||
if (n == getBuilder().getCallGraph().getFakeRootNode()) {
|
int pc = callSite.getProgramCounter();
|
||||||
return handleRootLexicalReference(name, definer, definingNode);
|
LexicalInformation L = ((AstIR) n.getIR()).lexicalInfo();
|
||||||
|
|
||||||
|
AbstractLexicalInvoke I = (AbstractLexicalInvoke) ir.getInstructions()[pc];
|
||||||
|
|
||||||
|
// find existing explicit lexical use
|
||||||
|
for (int i = I.getNumberOfParameters(); i <= I.getLastLexicalUse(); i++) {
|
||||||
|
Access A = I.getLexicalUse(i);
|
||||||
|
if (A.variableName.equals(name) && isEqual(A.variableDefiner, definer)) {
|
||||||
|
return getBuilder().getPointerKeyForLocal(n, A.valueNumber);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
else if (M instanceof AstMethod) {
|
// make new lexical use
|
||||||
AstIR ir = (AstIR) n.getIR();
|
int values[] = L.getExposedUses(pc);
|
||||||
int pc = callSite.getProgramCounter();
|
Pair names[] = L.getExposedNames();
|
||||||
LexicalInformation L = ((AstIR) n.getIR()).lexicalInfo();
|
if (names != null && names.length > 0) {
|
||||||
|
for (int i = 0; i < names.length; i++) {
|
||||||
|
if (name.equals(names[i].fst) && isEqual(definer, names[i].snd)) {
|
||||||
|
if (values[i] == -1)
|
||||||
|
return null;
|
||||||
|
|
||||||
// some people have no lexical uses at all
|
I.addLexicalUse(new Access(name, definer, values[i]));
|
||||||
if (L == null) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
AbstractLexicalInvoke I = (AbstractLexicalInvoke) ir.getInstructions()[pc];
|
if (SSAConversion.DEBUG_UNDO)
|
||||||
|
System.err.println(("copy use #" + (-i - 1) + " to use #" + (I.getNumberOfUses() - 1) + " at inst " + pc));
|
||||||
|
|
||||||
// find existing explicit lexical use
|
SSAConversion.copyUse(ir, pc, -i - 1, pc, I.getNumberOfUses() - 1);
|
||||||
for (int i = I.getNumberOfParameters(); i <= I.getLastLexicalUse(); i++) {
|
|
||||||
Access A = I.getLexicalUse(i);
|
((AstCallGraph.AstCGNode) n).setLexicallyMutatedIR(ir);
|
||||||
if (A.variableName.equals(name) && isEqual(A.variableDefiner, definer)) {
|
|
||||||
return getBuilder().getPointerKeyForLocal(n, A.valueNumber);
|
return getBuilder().getPointerKeyForLocal(n, values[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// make new lexical use
|
|
||||||
int values[] = L.getExposedUses(pc);
|
|
||||||
Pair names[] = L.getExposedNames();
|
|
||||||
if (names != null && names.length > 0) {
|
|
||||||
for (int i = 0; i < names.length; i++) {
|
|
||||||
if (name.equals(names[i].fst) && isEqual(definer, names[i].snd)) {
|
|
||||||
if (values[i] == -1)
|
|
||||||
return null;
|
|
||||||
|
|
||||||
I.addLexicalUse(new Access(name, definer, values[i]));
|
|
||||||
|
|
||||||
if (SSAConversion.DEBUG_UNDO)
|
|
||||||
System.err.println(("copy use #" + (-i - 1) + " to use #" + (I.getNumberOfUses() - 1) + " at inst " + pc));
|
|
||||||
|
|
||||||
SSAConversion.copyUse(ir, pc, -i - 1, pc, I.getNumberOfUses() - 1);
|
|
||||||
|
|
||||||
((AstCallGraph.AstCGNode) n).setLexicallyMutatedIR(ir);
|
|
||||||
|
|
||||||
return getBuilder().getPointerKeyForLocal(n, values[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
|
|
||||||
} else {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private PointerKey getLocalWriteKey(CGNode n, CallSiteReference callSite, String name, String definer, CGNode definingNode) {
|
|
||||||
IMethod M = n.getMethod();
|
|
||||||
if (n == getBuilder().getCallGraph().getFakeRootNode()) {
|
|
||||||
return handleRootLexicalReference(name, definer, definingNode);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
else if (M instanceof AstMethod) {
|
return null;
|
||||||
AstMethod AstM = (AstMethod) M;
|
|
||||||
AstIR ir = (AstIR) n.getIR();
|
|
||||||
LexicalInformation L = ir.lexicalInfo();
|
|
||||||
|
|
||||||
// some people have no lexical uses at all
|
}
|
||||||
if (L == null)
|
|
||||||
return null;
|
|
||||||
|
|
||||||
int pc = callSite.getProgramCounter();
|
private PointerKey getLocalWriteKey(CGNode n, CallSiteReference callSite, String name, String definer) {
|
||||||
AbstractLexicalInvoke I = (AbstractLexicalInvoke) ir.getInstructions()[pc];
|
AstMethod AstM = (AstMethod) n.getMethod();;
|
||||||
|
AstIR ir = (AstIR) n.getIR();
|
||||||
|
LexicalInformation L = ir.lexicalInfo();
|
||||||
|
|
||||||
// find existing explicit lexical def
|
int pc = callSite.getProgramCounter();
|
||||||
for (int i = 2; i < I.getNumberOfDefs(); i++) {
|
AbstractLexicalInvoke I = (AbstractLexicalInvoke) ir.getInstructions()[pc];
|
||||||
Access A = I.getLexicalDef(i);
|
|
||||||
if (A.variableName.equals(name) && isEqual(A.variableDefiner, definer)) {
|
// find existing explicit lexical def
|
||||||
return getBuilder().getPointerKeyForLocal(n, A.valueNumber);
|
for (int i = 2; i < I.getNumberOfDefs(); i++) {
|
||||||
}
|
Access A = I.getLexicalDef(i);
|
||||||
|
if (A.variableName.equals(name) && isEqual(A.variableDefiner, definer)) {
|
||||||
|
return getBuilder().getPointerKeyForLocal(n, A.valueNumber);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// make new lexical def
|
// make new lexical def
|
||||||
int values[] = L.getExposedUses(pc);
|
int values[] = L.getExposedUses(pc);
|
||||||
Pair names[] = L.getExposedNames();
|
Pair names[] = L.getExposedNames();
|
||||||
if (names != null && names.length > 0) {
|
if (names != null && names.length > 0) {
|
||||||
for (int i = 0; i < names.length; i++) {
|
for (int i = 0; i < names.length; i++) {
|
||||||
if (name.equals(names[i].fst) && isEqual(definer, names[i].snd)) {
|
if (name.equals(names[i].fst) && isEqual(definer, names[i].snd)) {
|
||||||
if (values[i] == -1)
|
if (values[i] == -1)
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
// find calls that may be altered, and clear their caches
|
// find calls that may be altered, and clear their caches
|
||||||
DefUse newDU = getAnalysisCache().getSSACache().findOrCreateDU(ir, n.getContext());
|
DefUse newDU = getAnalysisCache().getSSACache().findOrCreateDU(ir, n.getContext());
|
||||||
Iterator<SSAInstruction> insts = newDU.getUses(values[i]);
|
Iterator<SSAInstruction> insts = newDU.getUses(values[i]);
|
||||||
while (insts.hasNext()) {
|
while (insts.hasNext()) {
|
||||||
SSAInstruction inst = insts.next();
|
SSAInstruction inst = insts.next();
|
||||||
if (inst instanceof SSAAbstractInvokeInstruction) {
|
if (inst instanceof SSAAbstractInvokeInstruction) {
|
||||||
System.err.println("clearing for " + inst);
|
System.err.println("clearing for " + inst);
|
||||||
CallSiteReference cs = ((SSAAbstractInvokeInstruction) inst).getCallSite();
|
CallSiteReference cs = ((SSAAbstractInvokeInstruction) inst).getCallSite();
|
||||||
((AstCallGraph.AstCGNode) n).clearMutatedCache(cs);
|
((AstCallGraph.AstCGNode) n).clearMutatedCache(cs);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// if values[i] was altered by copy propagation, we must undo
|
// if values[i] was altered by copy propagation, we must undo
|
||||||
// that to ensure we do not bash the wrong value number in the
|
// that to ensure we do not bash the wrong value number in the
|
||||||
// the next steps.
|
// the next steps.
|
||||||
SSAConversion.undoCopyPropagation(ir, pc, -i - 1);
|
SSAConversion.undoCopyPropagation(ir, pc, -i - 1);
|
||||||
|
|
||||||
// possibly new instruction due to renames, so get it again
|
// possibly new instruction due to renames, so get it again
|
||||||
I = (AbstractLexicalInvoke) ir.getInstructions()[pc];
|
I = (AbstractLexicalInvoke) ir.getInstructions()[pc];
|
||||||
|
|
||||||
// we assume that the callee might not necessarily write,
|
// we assume that the callee might not necessarily write,
|
||||||
// so the call becomes like a phi node. hence it needs a
|
// so the call becomes like a phi node. hence it needs a
|
||||||
// read of the old value
|
// read of the old value
|
||||||
ensureRead: {
|
ensureRead: {
|
||||||
for (int l = 0; l < I.getNumberOfUses(); l++) {
|
for (int l = 0; l < I.getNumberOfUses(); l++) {
|
||||||
if (I.isLexicalUse(l)) {
|
if (I.isLexicalUse(l)) {
|
||||||
Access r = I.getLexicalUse(l);
|
Access r = I.getLexicalUse(l);
|
||||||
if (name.equals(r.variableName)) {
|
if (name.equals(r.variableName)) {
|
||||||
if (definer == null ? r.variableDefiner == null : definer.equals(r.variableDefiner)) {
|
if (definer == null ? r.variableDefiner == null : definer.equals(r.variableDefiner)) {
|
||||||
break ensureRead;
|
break ensureRead;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
I.addLexicalUse(new Access(name, definer, values[i]));
|
|
||||||
}
|
}
|
||||||
|
I.addLexicalUse(new Access(name, definer, values[i]));
|
||||||
// add new lexical definition
|
|
||||||
I.addLexicalDef(new Access(name, definer, values[i]));
|
|
||||||
|
|
||||||
if (SSAConversion.DEBUG_UNDO)
|
|
||||||
System.err.println("new def of " + values[i] + " at inst " + pc + ": " + I);
|
|
||||||
|
|
||||||
// new def has broken SSA form for values[i], so fix for that
|
|
||||||
// value
|
|
||||||
MutableIntSet vs = IntSetUtil.make();
|
|
||||||
vs.add(values[i]);
|
|
||||||
SSAConversion.convert(AstM, ir, getOptions().getSSAOptions());
|
|
||||||
|
|
||||||
// force analysis to be redone
|
|
||||||
// TODO: only values[i] uses need to be re-done.
|
|
||||||
ir.lexicalInfo().handleAlteration();
|
|
||||||
((AstCallGraph.AstCGNode) n).setLexicallyMutatedIR(ir);
|
|
||||||
getAnalysisCache().getSSACache().invalidateDU(M, n.getContext());
|
|
||||||
getBuilder().markChanged(n);
|
|
||||||
|
|
||||||
// get SSA-renamed def from call site instruction
|
|
||||||
return getLocalWriteKey(n, callSite, name, definer, definingNode);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// add new lexical definition
|
||||||
|
I.addLexicalDef(new Access(name, definer, values[i]));
|
||||||
|
|
||||||
|
if (SSAConversion.DEBUG_UNDO)
|
||||||
|
System.err.println("new def of " + values[i] + " at inst " + pc + ": " + I);
|
||||||
|
|
||||||
|
// new def has broken SSA form for values[i], so fix for that value
|
||||||
|
MutableIntSet vs = IntSetUtil.make();
|
||||||
|
vs.add(values[i]);
|
||||||
|
SSAConversion.convert(AstM, ir, getOptions().getSSAOptions());
|
||||||
|
|
||||||
|
// force analysis to be redone
|
||||||
|
// TODO: only values[i] uses need to be re-done.
|
||||||
|
ir.lexicalInfo().handleAlteration();
|
||||||
|
((AstCallGraph.AstCGNode) n).setLexicallyMutatedIR(ir);
|
||||||
|
getAnalysisCache().getSSACache().invalidateDU(AstM, n.getContext());
|
||||||
|
getBuilder().markChanged(n);
|
||||||
|
|
||||||
|
// get SSA-renamed def from call site instruction
|
||||||
|
return getLocalWriteKey(n, callSite, name, definer);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
|
||||||
} else {
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
// /////////////////////////////////////////////////////////////////////////
|
// /////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -1074,74 +1029,10 @@ public abstract class AstSSAPropagationCallGraphBuilder extends SSAPropagationCa
|
||||||
system.recordImplicitPointsToSet(fieldKey);
|
system.recordImplicitPointsToSet(fieldKey);
|
||||||
InstanceKey[] fieldsKeys = getInvariantContents(symtab, du, opNode, fieldsVn);
|
InstanceKey[] fieldsKeys = getInvariantContents(symtab, du, opNode, fieldsVn);
|
||||||
|
|
||||||
for (int o = 0; o < objKeys.length; o++) {
|
newFieldOperationObjectAndFieldConstant(isLoadOperation, action, objKeys, fieldsKeys);
|
||||||
PointerKey objCatalog = getPointerKeyForObjectCatalog(objKeys[o]);
|
|
||||||
for (int f = 0; f < fieldsKeys.length; f++) {
|
|
||||||
if (isLoadOperation) {
|
|
||||||
for (Iterator keys = getPointerKeysForReflectedFieldRead(objKeys[o], fieldsKeys[f]); keys.hasNext();) {
|
|
||||||
AbstractFieldPointerKey key = (AbstractFieldPointerKey) keys.next();
|
|
||||||
if (DEBUG_PROPERTIES)
|
|
||||||
action.dump(key, true, true);
|
|
||||||
action.action(key);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (objCatalog != null) {
|
|
||||||
system.newConstraint(objCatalog, fieldsKeys[f]);
|
|
||||||
}
|
|
||||||
for (Iterator keys = getPointerKeysForReflectedFieldWrite(objKeys[o], fieldsKeys[f]); keys.hasNext();) {
|
|
||||||
AbstractFieldPointerKey key = (AbstractFieldPointerKey) keys.next();
|
|
||||||
if (DEBUG_PROPERTIES)
|
|
||||||
action.dump(key, true, true);
|
|
||||||
action.action(key);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
if (!isLoadOperation) {
|
newFieldOperationOnlyObjectConstant(isLoadOperation, action, fieldKey, objKeys);
|
||||||
for (int o = 0; o < objKeys.length; o++) {
|
|
||||||
PointerKey objCatalog = getPointerKeyForObjectCatalog(objKeys[o]);
|
|
||||||
if (objCatalog != null) {
|
|
||||||
system.newConstraint(objCatalog, assignOperator, fieldKey);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
system.newSideEffect(new UnaryOperator<PointsToSetVariable>() {
|
|
||||||
public byte evaluate(PointsToSetVariable lhs, PointsToSetVariable rhs) {
|
|
||||||
final IntSetVariable fields = (IntSetVariable) rhs;
|
|
||||||
if (fields.getValue() != null) {
|
|
||||||
fields.getValue().foreach(new IntSetAction() {
|
|
||||||
public void act(int fptr) {
|
|
||||||
InstanceKey field = system.getInstanceKey(fptr);
|
|
||||||
for (int o = 0; o < objKeys.length; o++) {
|
|
||||||
for (Iterator keys = isLoadOperation ? getPointerKeysForReflectedFieldRead(objKeys[o], field)
|
|
||||||
: getPointerKeysForReflectedFieldWrite(objKeys[o], field); keys.hasNext();) {
|
|
||||||
AbstractFieldPointerKey key = (AbstractFieldPointerKey) keys.next();
|
|
||||||
if (DEBUG_PROPERTIES)
|
|
||||||
action.dump(key, false, true);
|
|
||||||
action.action(key);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
return NOT_CHANGED;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int hashCode() {
|
|
||||||
return System.identityHashCode(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean equals(Object o) {
|
|
||||||
return o == this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String toString() {
|
|
||||||
return "field op" + objVn + ", " + fieldsVn;
|
|
||||||
}
|
|
||||||
}, fieldKey);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
@ -1149,101 +1040,10 @@ public abstract class AstSSAPropagationCallGraphBuilder extends SSAPropagationCa
|
||||||
system.recordImplicitPointsToSet(fieldKey);
|
system.recordImplicitPointsToSet(fieldKey);
|
||||||
final InstanceKey[] fieldsKeys = getInvariantContents(symtab, du, opNode, fieldsVn);
|
final InstanceKey[] fieldsKeys = getInvariantContents(symtab, du, opNode, fieldsVn);
|
||||||
|
|
||||||
system.newSideEffect(new UnaryOperator<PointsToSetVariable>() {
|
newFieldOperationOnlyFieldConstant(isLoadOperation, action, objKey, fieldsKeys);
|
||||||
public byte evaluate(PointsToSetVariable lhs, PointsToSetVariable rhs) {
|
|
||||||
final IntSetVariable objects = (IntSetVariable) rhs;
|
|
||||||
if (objects.getValue() != null) {
|
|
||||||
objects.getValue().foreach(new IntSetAction() {
|
|
||||||
public void act(int optr) {
|
|
||||||
InstanceKey object = system.getInstanceKey(optr);
|
|
||||||
PointerKey objCatalog = getPointerKeyForObjectCatalog(object);
|
|
||||||
for (int f = 0; f < fieldsKeys.length; f++) {
|
|
||||||
if (isLoadOperation) {
|
|
||||||
for (Iterator keys = getPointerKeysForReflectedFieldRead(object, fieldsKeys[f]); keys.hasNext();) {
|
|
||||||
AbstractFieldPointerKey key = (AbstractFieldPointerKey) keys.next();
|
|
||||||
if (DEBUG_PROPERTIES)
|
|
||||||
action.dump(key, true, false);
|
|
||||||
action.action(key);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (objCatalog != null) {
|
|
||||||
system.newConstraint(objCatalog, fieldsKeys[f]);
|
|
||||||
}
|
|
||||||
for (Iterator keys = getPointerKeysForReflectedFieldWrite(object, fieldsKeys[f]); keys.hasNext();) {
|
|
||||||
AbstractFieldPointerKey key = (AbstractFieldPointerKey) keys.next();
|
|
||||||
if (DEBUG_PROPERTIES)
|
|
||||||
action.dump(key, true, false);
|
|
||||||
action.action(key);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
return NOT_CHANGED;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int hashCode() {
|
|
||||||
return System.identityHashCode(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean equals(Object o) {
|
|
||||||
return o == this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String toString() {
|
|
||||||
return "field op" + objVn + ", " + fieldsVn;
|
|
||||||
}
|
|
||||||
}, objKey);
|
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
system.newSideEffect(new AbstractOperator<PointsToSetVariable>() {
|
newFieldFullOperation(isLoadOperation, action, objKey, fieldKey);
|
||||||
public byte evaluate(PointsToSetVariable lhs, final PointsToSetVariable[] rhs) {
|
|
||||||
final IntSetVariable receivers = (IntSetVariable) rhs[0];
|
|
||||||
final IntSetVariable fields = (IntSetVariable) rhs[1];
|
|
||||||
if (receivers.getValue() != null && fields.getValue() != null) {
|
|
||||||
receivers.getValue().foreach(new IntSetAction() {
|
|
||||||
public void act(int rptr) {
|
|
||||||
final InstanceKey receiver = system.getInstanceKey(rptr);
|
|
||||||
|
|
||||||
if (!isLoadOperation) {
|
|
||||||
PointerKey cat = getPointerKeyForObjectCatalog(receiver);
|
|
||||||
if (cat != null) {
|
|
||||||
system.newConstraint(cat, assignOperator, fieldKey);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fields.getValue().foreach(new IntSetAction() {
|
|
||||||
public void act(int fptr) {
|
|
||||||
InstanceKey field = system.getInstanceKey(fptr);
|
|
||||||
for (Iterator keys = isLoadOperation ? getPointerKeysForReflectedFieldRead(receiver, field)
|
|
||||||
: getPointerKeysForReflectedFieldWrite(receiver, field); keys.hasNext();) {
|
|
||||||
AbstractFieldPointerKey key = (AbstractFieldPointerKey) keys.next();
|
|
||||||
if (DEBUG_PROPERTIES)
|
|
||||||
action.dump(key, false, false);
|
|
||||||
action.action(key);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
return NOT_CHANGED;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String toString() {
|
|
||||||
return "field op";
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean equals(Object o) {
|
|
||||||
return o == this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int hashCode() {
|
|
||||||
return System.identityHashCode(this);
|
|
||||||
}
|
|
||||||
}, objKey, fieldKey);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1251,6 +1051,210 @@ public abstract class AstSSAPropagationCallGraphBuilder extends SSAPropagationCa
|
||||||
System.err.println("finished\n");
|
System.err.println("finished\n");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected void newFieldOperationFieldConstant(CGNode opNode,
|
||||||
|
final boolean isLoadOperation,
|
||||||
|
final ReflectedFieldAction action,
|
||||||
|
final int objVn,
|
||||||
|
final InstanceKey[] fieldsKeys)
|
||||||
|
{
|
||||||
|
IR ir = getBuilder().getCFAContextInterpreter().getIR(opNode);
|
||||||
|
SymbolTable symtab = ir.getSymbolTable();
|
||||||
|
DefUse du = getBuilder().getCFAContextInterpreter().getDU(opNode);
|
||||||
|
PointerKey objKey = getBuilder().getPointerKeyForLocal(opNode, objVn);
|
||||||
|
|
||||||
|
if (contentsAreInvariant(symtab, du, objVn)) {
|
||||||
|
system.recordImplicitPointsToSet(objKey);
|
||||||
|
InstanceKey[] objectKeys = getInvariantContents(symtab, du, opNode, objVn);
|
||||||
|
|
||||||
|
newFieldOperationObjectAndFieldConstant(isLoadOperation, action, objectKeys, fieldsKeys);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
newFieldOperationOnlyFieldConstant(isLoadOperation, action, objKey, fieldsKeys);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private void newFieldFullOperation(final boolean isLoadOperation, final ReflectedFieldAction action, PointerKey objKey,
|
||||||
|
final PointerKey fieldKey) {
|
||||||
|
system.newSideEffect(new AbstractOperator<PointsToSetVariable>() {
|
||||||
|
public byte evaluate(PointsToSetVariable lhs, final PointsToSetVariable[] rhs) {
|
||||||
|
final IntSetVariable receivers = (IntSetVariable) rhs[0];
|
||||||
|
final IntSetVariable fields = (IntSetVariable) rhs[1];
|
||||||
|
if (receivers.getValue() != null && fields.getValue() != null) {
|
||||||
|
receivers.getValue().foreach(new IntSetAction() {
|
||||||
|
public void act(int rptr) {
|
||||||
|
final InstanceKey receiver = system.getInstanceKey(rptr);
|
||||||
|
|
||||||
|
if (!isLoadOperation) {
|
||||||
|
PointerKey cat = getPointerKeyForObjectCatalog(receiver);
|
||||||
|
if (cat != null) {
|
||||||
|
system.newConstraint(cat, assignOperator, fieldKey);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fields.getValue().foreach(new IntSetAction() {
|
||||||
|
public void act(int fptr) {
|
||||||
|
InstanceKey field = system.getInstanceKey(fptr);
|
||||||
|
for (Iterator keys = isLoadOperation ? getPointerKeysForReflectedFieldRead(receiver, field)
|
||||||
|
: getPointerKeysForReflectedFieldWrite(receiver, field); keys.hasNext();) {
|
||||||
|
AbstractFieldPointerKey key = (AbstractFieldPointerKey) keys.next();
|
||||||
|
if (DEBUG_PROPERTIES)
|
||||||
|
action.dump(key, false, false);
|
||||||
|
action.action(key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return NOT_CHANGED;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String toString() {
|
||||||
|
return "field op";
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean equals(Object o) {
|
||||||
|
return o == this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int hashCode() {
|
||||||
|
return System.identityHashCode(this);
|
||||||
|
}
|
||||||
|
}, objKey, fieldKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void newFieldOperationOnlyFieldConstant(final boolean isLoadOperation,
|
||||||
|
final ReflectedFieldAction action,
|
||||||
|
final PointerKey objKey,
|
||||||
|
final InstanceKey[] fieldsKeys)
|
||||||
|
{
|
||||||
|
system.newSideEffect(new UnaryOperator<PointsToSetVariable>() {
|
||||||
|
public byte evaluate(PointsToSetVariable lhs, PointsToSetVariable rhs) {
|
||||||
|
final IntSetVariable objects = (IntSetVariable) rhs;
|
||||||
|
if (objects.getValue() != null) {
|
||||||
|
objects.getValue().foreach(new IntSetAction() {
|
||||||
|
public void act(int optr) {
|
||||||
|
InstanceKey object = system.getInstanceKey(optr);
|
||||||
|
PointerKey objCatalog = getPointerKeyForObjectCatalog(object);
|
||||||
|
for (int f = 0; f < fieldsKeys.length; f++) {
|
||||||
|
if (isLoadOperation) {
|
||||||
|
for (Iterator keys = getPointerKeysForReflectedFieldRead(object, fieldsKeys[f]); keys.hasNext();) {
|
||||||
|
AbstractFieldPointerKey key = (AbstractFieldPointerKey) keys.next();
|
||||||
|
if (DEBUG_PROPERTIES)
|
||||||
|
action.dump(key, true, false);
|
||||||
|
action.action(key);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (objCatalog != null) {
|
||||||
|
system.newConstraint(objCatalog, fieldsKeys[f]);
|
||||||
|
}
|
||||||
|
for (Iterator keys = getPointerKeysForReflectedFieldWrite(object, fieldsKeys[f]); keys.hasNext();) {
|
||||||
|
AbstractFieldPointerKey key = (AbstractFieldPointerKey) keys.next();
|
||||||
|
if (DEBUG_PROPERTIES)
|
||||||
|
action.dump(key, true, false);
|
||||||
|
action.action(key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return NOT_CHANGED;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int hashCode() {
|
||||||
|
return System.identityHashCode(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean equals(Object o) {
|
||||||
|
return o == this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String toString() {
|
||||||
|
return "field op" + objKey;
|
||||||
|
}
|
||||||
|
}, objKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void newFieldOperationOnlyObjectConstant(final boolean isLoadOperation,
|
||||||
|
final ReflectedFieldAction action,
|
||||||
|
final PointerKey fieldKey,
|
||||||
|
final InstanceKey[] objKeys)
|
||||||
|
{
|
||||||
|
if (!isLoadOperation) {
|
||||||
|
for (int o = 0; o < objKeys.length; o++) {
|
||||||
|
PointerKey objCatalog = getPointerKeyForObjectCatalog(objKeys[o]);
|
||||||
|
if (objCatalog != null) {
|
||||||
|
system.newConstraint(objCatalog, assignOperator, fieldKey);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
system.newSideEffect(new UnaryOperator<PointsToSetVariable>() {
|
||||||
|
public byte evaluate(PointsToSetVariable lhs, PointsToSetVariable rhs) {
|
||||||
|
final IntSetVariable fields = (IntSetVariable) rhs;
|
||||||
|
if (fields.getValue() != null) {
|
||||||
|
fields.getValue().foreach(new IntSetAction() {
|
||||||
|
public void act(int fptr) {
|
||||||
|
InstanceKey field = system.getInstanceKey(fptr);
|
||||||
|
for (int o = 0; o < objKeys.length; o++) {
|
||||||
|
for (Iterator keys = isLoadOperation ? getPointerKeysForReflectedFieldRead(objKeys[o], field)
|
||||||
|
: getPointerKeysForReflectedFieldWrite(objKeys[o], field); keys.hasNext();) {
|
||||||
|
AbstractFieldPointerKey key = (AbstractFieldPointerKey) keys.next();
|
||||||
|
if (DEBUG_PROPERTIES)
|
||||||
|
action.dump(key, false, true);
|
||||||
|
action.action(key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return NOT_CHANGED;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int hashCode() {
|
||||||
|
return System.identityHashCode(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean equals(Object o) {
|
||||||
|
return o == this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String toString() {
|
||||||
|
return "field op" + fieldKey;
|
||||||
|
}
|
||||||
|
}, fieldKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void newFieldOperationObjectAndFieldConstant(final boolean isLoadOperation, final ReflectedFieldAction action,
|
||||||
|
final InstanceKey[] objKeys, InstanceKey[] fieldsKeys) {
|
||||||
|
for (int o = 0; o < objKeys.length; o++) {
|
||||||
|
PointerKey objCatalog = getPointerKeyForObjectCatalog(objKeys[o]);
|
||||||
|
for (int f = 0; f < fieldsKeys.length; f++) {
|
||||||
|
if (isLoadOperation) {
|
||||||
|
for (Iterator keys = getPointerKeysForReflectedFieldRead(objKeys[o], fieldsKeys[f]); keys.hasNext();) {
|
||||||
|
AbstractFieldPointerKey key = (AbstractFieldPointerKey) keys.next();
|
||||||
|
if (DEBUG_PROPERTIES)
|
||||||
|
action.dump(key, true, true);
|
||||||
|
action.action(key);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (objCatalog != null) {
|
||||||
|
system.newConstraint(objCatalog, fieldsKeys[f]);
|
||||||
|
}
|
||||||
|
for (Iterator keys = getPointerKeysForReflectedFieldWrite(objKeys[o], fieldsKeys[f]); keys.hasNext();) {
|
||||||
|
AbstractFieldPointerKey key = (AbstractFieldPointerKey) keys.next();
|
||||||
|
if (DEBUG_PROPERTIES)
|
||||||
|
action.dump(key, true, true);
|
||||||
|
action.action(key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void newFieldWrite(CGNode opNode, int objVn, int fieldsVn, int rhsVn) {
|
public void newFieldWrite(CGNode opNode, int objVn, int fieldsVn, int rhsVn) {
|
||||||
IR ir = getBuilder().getCFAContextInterpreter().getIR(opNode);
|
IR ir = getBuilder().getCFAContextInterpreter().getIR(opNode);
|
||||||
|
@ -1265,46 +1269,61 @@ public abstract class AstSSAPropagationCallGraphBuilder extends SSAPropagationCa
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void newFieldWrite(CGNode opNode, int objVn, int fieldsVn, final InstanceKey[] rhsFixedValues) {
|
private final class ConstantWriter implements ReflectedFieldAction {
|
||||||
try {
|
private final InstanceKey[] rhsFixedValues;
|
||||||
|
|
||||||
|
private ConstantWriter(InstanceKey[] rhsFixedValues) {
|
||||||
|
this.rhsFixedValues = rhsFixedValues;
|
||||||
|
}
|
||||||
|
|
||||||
newFieldOperation(opNode, objVn, fieldsVn, false, new ReflectedFieldAction() {
|
public void dump(AbstractFieldPointerKey fieldKey, boolean constObj, boolean constProp) {
|
||||||
public void dump(AbstractFieldPointerKey fieldKey, boolean constObj, boolean constProp) {
|
System.err.println(("writing fixed rvals to " + fieldKey + " " + constObj + ", " + constProp));
|
||||||
System.err.println(("writing fixed rvals to " + fieldKey + " " + constObj + ", " + constProp));
|
for (int i = 0; i < rhsFixedValues.length; i++) {
|
||||||
for (int i = 0; i < rhsFixedValues.length; i++) {
|
System.err.println(("writing " + rhsFixedValues[i]));
|
||||||
System.err.println(("writing " + rhsFixedValues[i]));
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void action(AbstractFieldPointerKey fieldKey) {
|
||||||
|
if (!representsNullType(fieldKey.getInstanceKey())) {
|
||||||
|
for (int i = 0; i < rhsFixedValues.length; i++) {
|
||||||
|
system.findOrCreateIndexForInstanceKey(rhsFixedValues[i]);
|
||||||
|
system.newConstraint(fieldKey, rhsFixedValues[i]);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
public void action(AbstractFieldPointerKey fieldKey) {
|
|
||||||
if (!representsNullType(fieldKey.getInstanceKey())) {
|
|
||||||
for (int i = 0; i < rhsFixedValues.length; i++) {
|
|
||||||
system.findOrCreateIndexForInstanceKey(rhsFixedValues[i]);
|
|
||||||
system.newConstraint(fieldKey, rhsFixedValues[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
} catch (RuntimeException e) {
|
|
||||||
System.err.println("error: " + e);
|
|
||||||
System.err.println(getBuilder().getCFAContextInterpreter().getIR(opNode));
|
|
||||||
throw e;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void newFieldWrite(CGNode opNode, int objVn, int fieldsVn, final InstanceKey[] rhsFixedValues) {
|
||||||
|
newFieldOperation(opNode, objVn, fieldsVn, false, new ConstantWriter(rhsFixedValues));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void newFieldWrite(CGNode opNode, int objVn, InstanceKey[] fieldKeys, final InstanceKey[] rhsValues) {
|
||||||
|
newFieldOperationFieldConstant(opNode, false, new ConstantWriter(rhsValues), objVn, fieldKeys);
|
||||||
|
}
|
||||||
|
|
||||||
|
private final class NormalWriter implements ReflectedFieldAction {
|
||||||
|
private final PointerKey rhs;
|
||||||
|
|
||||||
|
private NormalWriter(PointerKey rhs) {
|
||||||
|
this.rhs = rhs;
|
||||||
|
}
|
||||||
|
public void dump(AbstractFieldPointerKey fieldKey, boolean constObj, boolean constProp) {
|
||||||
|
System.err.println(("write " + rhs + " to " + fieldKey + " " + constObj + ", " + constProp));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void action(AbstractFieldPointerKey fieldKey) {
|
||||||
|
if (!representsNullType(fieldKey.getInstanceKey())) {
|
||||||
|
system.newConstraint(fieldKey, assignOperator, rhs);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
public void newFieldWrite(CGNode opNode, int objVn, int fieldsVn, final PointerKey rhs) {
|
public void newFieldWrite(CGNode opNode, int objVn, int fieldsVn, final PointerKey rhs) {
|
||||||
newFieldOperation(opNode, objVn, fieldsVn, false, new ReflectedFieldAction() {
|
newFieldOperation(opNode, objVn, fieldsVn, false, new NormalWriter(rhs));
|
||||||
public void dump(AbstractFieldPointerKey fieldKey, boolean constObj, boolean constProp) {
|
}
|
||||||
System.err.println(("write " + rhs + " to " + fieldKey + " " + constObj + ", " + constProp));
|
|
||||||
}
|
|
||||||
|
|
||||||
public void action(AbstractFieldPointerKey fieldKey) {
|
public void newFieldWrite(CGNode opNode, int objVn, InstanceKey[] fieldKeys, final PointerKey rhs) {
|
||||||
if (!representsNullType(fieldKey.getInstanceKey())) {
|
newFieldOperationFieldConstant(opNode, false, new NormalWriter(rhs), objVn, fieldKeys);
|
||||||
system.newConstraint(fieldKey, assignOperator, rhs);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void newFieldRead(CGNode opNode, int objVn, int fieldsVn, int lhsVn) {
|
protected void newFieldRead(CGNode opNode, int objVn, int fieldsVn, int lhsVn) {
|
||||||
|
|
|
@ -0,0 +1,220 @@
|
||||||
|
package com.ibm.wala.cast.ipa.callgraph;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import com.ibm.wala.cast.ir.ssa.AstLexicalAccess.Access;
|
||||||
|
import com.ibm.wala.cast.loader.AstMethod;
|
||||||
|
import com.ibm.wala.cast.loader.AstMethod.LexicalInformation;
|
||||||
|
import com.ibm.wala.classLoader.CallSiteReference;
|
||||||
|
import com.ibm.wala.classLoader.IMethod;
|
||||||
|
import com.ibm.wala.ipa.callgraph.CGNode;
|
||||||
|
import com.ibm.wala.ipa.callgraph.Context;
|
||||||
|
import com.ibm.wala.ipa.callgraph.ContextItem;
|
||||||
|
import com.ibm.wala.ipa.callgraph.ContextKey;
|
||||||
|
import com.ibm.wala.ipa.callgraph.ContextSelector;
|
||||||
|
import com.ibm.wala.ipa.callgraph.propagation.InstanceKey;
|
||||||
|
import com.ibm.wala.ipa.callgraph.propagation.PropagationCallGraphBuilder;
|
||||||
|
import com.ibm.wala.util.collections.CompoundIterator;
|
||||||
|
import com.ibm.wala.util.collections.EmptyIterator;
|
||||||
|
import com.ibm.wala.util.collections.MapIterator;
|
||||||
|
import com.ibm.wala.util.collections.NonNullSingletonIterator;
|
||||||
|
import com.ibm.wala.util.collections.Pair;
|
||||||
|
import com.ibm.wala.util.functions.Function;
|
||||||
|
import com.ibm.wala.util.intset.IntSet;
|
||||||
|
|
||||||
|
public final class LexicalScopingResolverContexts implements ContextSelector {
|
||||||
|
|
||||||
|
public static final ContextKey RESOLVER = new ContextKey() {
|
||||||
|
public final String toString() {
|
||||||
|
return "Resolver Key";
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
public static class Resolver extends HashMap<Pair<String,String>, Object> implements ContextItem {
|
||||||
|
private final Map<Pair<String,String>,CGNode> funargKeys = new HashMap<Pair<String,String>,CGNode>();
|
||||||
|
private final Resolver parent;
|
||||||
|
|
||||||
|
private Resolver(Resolver parent) {
|
||||||
|
super(1);
|
||||||
|
this.parent = parent;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Iterator<Pair<CallSiteReference,CGNode>> getLexicalSitesRec(final Object x) {
|
||||||
|
if (x == null) {
|
||||||
|
return null;
|
||||||
|
} else if (x instanceof CGNode) {
|
||||||
|
return new MapIterator<CallSiteReference,Pair<CallSiteReference,CGNode>>(
|
||||||
|
((CGNode)x).iterateCallSites(),
|
||||||
|
new Function<CallSiteReference,Pair<CallSiteReference,CGNode>>() {
|
||||||
|
public Pair<CallSiteReference, CGNode> apply(CallSiteReference object) {
|
||||||
|
return Pair.make(object, (CGNode)x);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
} else if (x instanceof Pair) {
|
||||||
|
return new NonNullSingletonIterator(x);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
Iterator<Pair<CallSiteReference,CGNode>> result = EmptyIterator.instance();
|
||||||
|
Iterator<?> c = ((Collection<?>) x).iterator();
|
||||||
|
while(c.hasNext()) {
|
||||||
|
result = new CompoundIterator<Pair<CallSiteReference,CGNode>>(result, getLexicalSitesRec(c.next()));
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void add(Pair<String,String> name, Pair<CallSiteReference,CGNode> site) {
|
||||||
|
if (! containsKey(name)) {
|
||||||
|
put(name, site);
|
||||||
|
} else {
|
||||||
|
Object x = get(name);
|
||||||
|
if (! x.equals(site)) {
|
||||||
|
if (x instanceof Collection) {
|
||||||
|
((Collection)x).add(site);
|
||||||
|
} else {
|
||||||
|
Collection<Object> s = new HashSet<Object>(2);
|
||||||
|
s.add(x);
|
||||||
|
s.add(site);
|
||||||
|
put(name,s);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public Iterator<Pair<CallSiteReference,CGNode>> getLexicalSites(Pair<String,String> p) {
|
||||||
|
return getLexicalSitesRec(get(p));
|
||||||
|
}
|
||||||
|
|
||||||
|
public Iterator<Pair<CallSiteReference,CGNode>> getLexicalSites(Access a) {
|
||||||
|
return getLexicalSites(Pair.make(a.variableName, a.variableDefiner));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addFunarg(Pair<String,String> var, CGNode target) {
|
||||||
|
funargKeys.put(var, target);
|
||||||
|
}
|
||||||
|
|
||||||
|
public CGNode getFunarg(Pair<String,String> var) {
|
||||||
|
return funargKeys.get(var);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private class LexicalScopingResolverContext implements Context {
|
||||||
|
private final Resolver governingCallSites;
|
||||||
|
private final Context base;
|
||||||
|
|
||||||
|
public int hashCode() {
|
||||||
|
return governingCallSites==null? 1077651: governingCallSites.keySet().hashCode();
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean equals(Object o) {
|
||||||
|
if (this == o) {
|
||||||
|
return true;
|
||||||
|
} else if (getClass().equals(o.getClass())) {
|
||||||
|
LexicalScopingResolverContext c = (LexicalScopingResolverContext)o;
|
||||||
|
return (base==null? c.base==null: base.equals(c.base))
|
||||||
|
&&
|
||||||
|
(governingCallSites.equals(c.governingCallSites));
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public ContextItem get(ContextKey name) {
|
||||||
|
return name.equals(RESOLVER)? governingCallSites: base!=null? base.get(name): null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private LexicalScopingResolverContext(Resolver governingCallSites, Context base) {
|
||||||
|
this.base = base;
|
||||||
|
this.governingCallSites = governingCallSites;
|
||||||
|
}
|
||||||
|
|
||||||
|
private LexicalScopingResolverContext(CGNode source, CallSiteReference callSite, Context base) {
|
||||||
|
Context srcContext = source.getContext();
|
||||||
|
Resolver srcResolver = (Resolver) srcContext.get(RESOLVER);
|
||||||
|
|
||||||
|
this.base = base;
|
||||||
|
this.governingCallSites = new Resolver(srcResolver);
|
||||||
|
|
||||||
|
if (source.getMethod() instanceof AstMethod) {
|
||||||
|
LexicalInformation LI = ((AstMethod)source.getMethod()).lexicalInfo();
|
||||||
|
int[] exposedUses = LI.getExposedUses(callSite.getProgramCounter());
|
||||||
|
int[] exposedExitUses = LI.getExitExposedUses();
|
||||||
|
if (exposedUses.length > 0) {
|
||||||
|
Pair<String,String> exposedNames[] = LI.getExposedNames();
|
||||||
|
for(int i = 0; i < exposedUses.length; i++) {
|
||||||
|
if (exposedUses[i] != -1) {
|
||||||
|
governingCallSites.add(exposedNames[i], Pair.make(callSite, source));
|
||||||
|
}
|
||||||
|
if (exposedExitUses[i] != -1) {
|
||||||
|
governingCallSites.addFunarg(exposedNames[i], source);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (srcResolver != null) {
|
||||||
|
for(Pair<String,String> x : srcResolver.keySet()) {
|
||||||
|
Iterator<Pair<CallSiteReference,CGNode>> sites = srcResolver.getLexicalSites(x);
|
||||||
|
while (sites.hasNext()) {
|
||||||
|
governingCallSites.add(x, sites.next());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private final ContextSelector base;
|
||||||
|
|
||||||
|
private final PropagationCallGraphBuilder builder;
|
||||||
|
|
||||||
|
public LexicalScopingResolverContexts(PropagationCallGraphBuilder builder, ContextSelector base) {
|
||||||
|
this.base = base;
|
||||||
|
this.builder = builder;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Context checkForRecursion(IMethod target, Resolver srcResolver) {
|
||||||
|
while (srcResolver != null) {
|
||||||
|
for(CGNode n : builder.getCallGraph().getNodes(target.getReference())) {
|
||||||
|
if (n.getContext().get(RESOLVER) == srcResolver) {
|
||||||
|
return n.getContext();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
srcResolver = srcResolver.parent;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Context getCalleeTarget(CGNode caller, CallSiteReference site, IMethod callee, InstanceKey[] actualParameters) {
|
||||||
|
Context baseContext = base.getCalleeTarget(caller, site, callee, actualParameters);
|
||||||
|
Resolver resolver = (Resolver)caller.getContext().get(RESOLVER);
|
||||||
|
|
||||||
|
Context recursiveParent = checkForRecursion(callee, resolver);
|
||||||
|
if (recursiveParent != null) {
|
||||||
|
return recursiveParent;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (caller.getMethod() instanceof AstMethod
|
||||||
|
&&
|
||||||
|
((AstMethod)caller.getMethod()).lexicalInfo().getExposedUses(site.getProgramCounter()).length > 0)
|
||||||
|
{
|
||||||
|
return new LexicalScopingResolverContext(caller, site, baseContext);
|
||||||
|
}
|
||||||
|
|
||||||
|
else if (resolver != null) {
|
||||||
|
return new LexicalScopingResolverContext(resolver, baseContext);
|
||||||
|
}
|
||||||
|
|
||||||
|
else {
|
||||||
|
return baseContext;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public IntSet getRelevantParameters(CGNode caller, CallSiteReference site) {
|
||||||
|
return base.getRelevantParameters(caller, site);
|
||||||
|
}
|
||||||
|
}
|
|
@ -34,7 +34,7 @@ public class LexicalScopingSSAContextInterpreter extends AstContextInsensitiveSS
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return getAnalysisCache().getSSACache().findOrCreateIR(node.getMethod(), node.getContext(), options.getSSAOptions());
|
return super.getIR(node);
|
||||||
}
|
}
|
||||||
|
|
||||||
public DefUse getDU(CGNode node) {
|
public DefUse getDU(CGNode node) {
|
||||||
|
@ -45,7 +45,7 @@ public class LexicalScopingSSAContextInterpreter extends AstContextInsensitiveSS
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return getAnalysisCache().getSSACache().findOrCreateDU(node.getMethod(), node.getContext(), options.getSSAOptions());
|
return super.getDU(node);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,10 +10,9 @@
|
||||||
*****************************************************************************/
|
*****************************************************************************/
|
||||||
package com.ibm.wala.cast.ipa.callgraph;
|
package com.ibm.wala.cast.ipa.callgraph;
|
||||||
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
|
|
||||||
import com.ibm.wala.cast.ir.translator.AstTranslator;
|
import com.ibm.wala.cast.ipa.callgraph.LexicalScopingResolverContexts.Resolver;
|
||||||
import com.ibm.wala.cast.loader.AstMethod.LexicalParent;
|
import com.ibm.wala.cast.loader.AstMethod.LexicalParent;
|
||||||
import com.ibm.wala.classLoader.IClass;
|
import com.ibm.wala.classLoader.IClass;
|
||||||
import com.ibm.wala.classLoader.NewSiteReference;
|
import com.ibm.wala.classLoader.NewSiteReference;
|
||||||
|
@ -21,11 +20,14 @@ import com.ibm.wala.classLoader.ProgramCounter;
|
||||||
import com.ibm.wala.ipa.callgraph.CGNode;
|
import com.ibm.wala.ipa.callgraph.CGNode;
|
||||||
import com.ibm.wala.ipa.callgraph.propagation.InstanceKey;
|
import com.ibm.wala.ipa.callgraph.propagation.InstanceKey;
|
||||||
import com.ibm.wala.ipa.callgraph.propagation.InstanceKeyFactory;
|
import com.ibm.wala.ipa.callgraph.propagation.InstanceKeyFactory;
|
||||||
|
import com.ibm.wala.ipa.callgraph.propagation.PointerKey;
|
||||||
import com.ibm.wala.ipa.callgraph.propagation.PropagationCallGraphBuilder;
|
import com.ibm.wala.ipa.callgraph.propagation.PropagationCallGraphBuilder;
|
||||||
import com.ibm.wala.types.TypeReference;
|
import com.ibm.wala.types.TypeReference;
|
||||||
import com.ibm.wala.util.collections.HashMapFactory;
|
import com.ibm.wala.util.collections.CompoundIterator;
|
||||||
import com.ibm.wala.util.graph.impl.GraphInverter;
|
import com.ibm.wala.util.collections.EmptyIterator;
|
||||||
import com.ibm.wala.util.graph.traverse.DFS;
|
import com.ibm.wala.util.collections.NonNullSingletonIterator;
|
||||||
|
import com.ibm.wala.util.collections.Pair;
|
||||||
|
import com.ibm.wala.util.intset.OrdinalSet;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An {@link InstanceKeyFactory} that returns {@link ScopeMappingInstanceKey}s
|
* An {@link InstanceKeyFactory} that returns {@link ScopeMappingInstanceKey}s
|
||||||
|
@ -33,12 +35,6 @@ import com.ibm.wala.util.graph.traverse.DFS;
|
||||||
*/
|
*/
|
||||||
abstract public class ScopeMappingInstanceKeys implements InstanceKeyFactory {
|
abstract public class ScopeMappingInstanceKeys implements InstanceKeyFactory {
|
||||||
|
|
||||||
/**
|
|
||||||
* return all {@link LexicalParent}s of methods represented by base (a single
|
|
||||||
* method for JavaScript, all instance methods in Java).
|
|
||||||
*/
|
|
||||||
protected abstract LexicalParent[] getParents(InstanceKey base);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* does base require a scope mapping key? Typically, true if base is allocated
|
* does base require a scope mapping key? Typically, true if base is allocated
|
||||||
* in a nested lexical scope
|
* in a nested lexical scope
|
||||||
|
@ -76,47 +72,16 @@ abstract public class ScopeMappingInstanceKeys implements InstanceKeyFactory {
|
||||||
*/
|
*/
|
||||||
private final CGNode creator;
|
private final CGNode creator;
|
||||||
|
|
||||||
/**
|
|
||||||
* mapping from lexical parent names to the corresponding CGNodes
|
|
||||||
*/
|
|
||||||
private final HashMap<String, CGNode> scopeMap;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* compute the {@link CGNode} correspond to each specified
|
* compute the {@link CGNode} correspond to each specified
|
||||||
* {@link LexicalParent} of {@link #base}, populating {@link #scopeMap}
|
* {@link LexicalParent} of {@link #base}, populating {@link #scopeMap}
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
private void computeLexicalParentCGNodes() {
|
|
||||||
if (AstTranslator.DEBUG_LEXICAL)
|
|
||||||
System.err.println(("starting search for parents at " + creator));
|
|
||||||
final LexicalParent[] parents = getParents(base);
|
|
||||||
Iterator<CGNode> preds = DFS.iterateDiscoverTime(GraphInverter.invert(builder.getCallGraph()), creator);
|
|
||||||
int toDo = parents.length;
|
|
||||||
while (preds.hasNext()) {
|
|
||||||
CGNode pred = preds.next();
|
|
||||||
for (int i = 0; i < parents.length; i++) {
|
|
||||||
if (parents[i] != null) {
|
|
||||||
if (pred.getMethod() == parents[i].getMethod()) {
|
|
||||||
if (scopeMap.containsKey(parents[i].getName()))
|
|
||||||
assert scopeMap.get(parents[i].getName()) == pred;
|
|
||||||
else {
|
|
||||||
toDo--;
|
|
||||||
scopeMap.put(parents[i].getName(), pred);
|
|
||||||
if (AstTranslator.DEBUG_LEXICAL)
|
|
||||||
System.err.println(("Adding lexical parent " + parents[i].getName() + " for " + base + " at " + creator
|
|
||||||
+ "(toDo is now " + toDo + ")"));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private ScopeMappingInstanceKey(CGNode creator, InstanceKey base) {
|
private ScopeMappingInstanceKey(CGNode creator, InstanceKey base) {
|
||||||
this.creator = creator;
|
this.creator = creator;
|
||||||
this.base = base;
|
this.base = base;
|
||||||
this.scopeMap = HashMapFactory.make();
|
|
||||||
computeLexicalParentCGNodes();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public IClass getConcreteType() {
|
public IClass getConcreteType() {
|
||||||
|
@ -128,8 +93,26 @@ abstract public class ScopeMappingInstanceKeys implements InstanceKeyFactory {
|
||||||
* @param definer
|
* @param definer
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
CGNode getDefiningNode(String definer) {
|
Iterator<CGNode> getFunargNodes(Pair<String,String> name) {
|
||||||
return scopeMap.get(definer);
|
Iterator<CGNode> result = EmptyIterator.instance();
|
||||||
|
|
||||||
|
Resolver r = (Resolver)creator.getContext().get(LexicalScopingResolverContexts.RESOLVER);
|
||||||
|
if (r != null) {
|
||||||
|
CGNode def = r.getFunarg(name);
|
||||||
|
if (def != null) {
|
||||||
|
result = new NonNullSingletonIterator<CGNode>(def);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
PointerKey funcKey = builder.getPointerKeyForLocal(creator, 1);
|
||||||
|
OrdinalSet<InstanceKey> funcPtrs = builder.getPointerAnalysis().getPointsToSet(funcKey);
|
||||||
|
for(InstanceKey x : funcPtrs) {
|
||||||
|
if (x instanceof ScopeMappingInstanceKey) {
|
||||||
|
result = new CompoundIterator<CGNode>(result, ((ScopeMappingInstanceKey)x).getFunargNodes(name));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int hashCode() {
|
public int hashCode() {
|
||||||
|
@ -146,10 +129,10 @@ abstract public class ScopeMappingInstanceKeys implements InstanceKeyFactory {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public InstanceKey getInstanceKeyForAllocation(CGNode node, NewSiteReference allocation) {
|
public InstanceKey getInstanceKeyForAllocation(CGNode creatorNode, NewSiteReference allocationSite) {
|
||||||
InstanceKey base = basic.getInstanceKeyForAllocation(node, allocation);
|
InstanceKey base = basic.getInstanceKeyForAllocation(creatorNode, allocationSite);
|
||||||
if (base != null && needsScopeMappingKey(base)) {
|
if (base != null && needsScopeMappingKey(base)) {
|
||||||
return new ScopeMappingInstanceKey(node, base);
|
return new ScopeMappingInstanceKey(creatorNode, base);
|
||||||
} else {
|
} else {
|
||||||
return base;
|
return base;
|
||||||
}
|
}
|
||||||
|
|
|
@ -461,9 +461,13 @@ public class SSAConversion extends AbstractSSAConversion {
|
||||||
|
|
||||||
int[] exitLive = lexicalInfo.getExitExposedUses();
|
int[] exitLive = lexicalInfo.getExitExposedUses();
|
||||||
BitVector v = new BitVector();
|
BitVector v = new BitVector();
|
||||||
if (exitLive != null)
|
if (exitLive != null) {
|
||||||
for (int i = 0; i < exitLive.length; i++)
|
for (int i = 0; i < exitLive.length; i++) {
|
||||||
v.set(exitLive[i]);
|
if (exitLive[i] > -1) {
|
||||||
|
v.set(exitLive[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
this.liveness = LiveAnalysis.perform(CFG, symtab, v);
|
this.liveness = LiveAnalysis.perform(CFG, symtab, v);
|
||||||
|
|
||||||
if (DEBUG) {
|
if (DEBUG) {
|
||||||
|
@ -514,7 +518,7 @@ public class SSAConversion extends AbstractSSAConversion {
|
||||||
int[] exitLives = lexicalInfo.getExitExposedUses();
|
int[] exitLives = lexicalInfo.getExitExposedUses();
|
||||||
if (exitLives != null) {
|
if (exitLives != null) {
|
||||||
for (int i = 0; i < exitLives.length; i++) {
|
for (int i = 0; i < exitLives.length; i++) {
|
||||||
if (!skip(exitLives[i])) {
|
if (exitLives[i] != -1 && !skip(exitLives[i])) {
|
||||||
assert !S[exitLives[i]].isEmpty();
|
assert !S[exitLives[i]].isEmpty();
|
||||||
exitLives[i] = top(exitLives[i]);
|
exitLives[i] = top(exitLives[i]);
|
||||||
}
|
}
|
||||||
|
|
|
@ -2245,11 +2245,15 @@ public abstract class AstTranslator extends CAstVisitor implements ArrayOpHandle
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private int[] buildLexicalUseArray(Pair<Pair<String, String>, Integer>[] exposedNames) {
|
private int[] buildLexicalUseArray(Pair<Pair<String, String>, Integer>[] exposedNames, String entityName) {
|
||||||
if (exposedNames != null) {
|
if (exposedNames != null) {
|
||||||
int[] lexicalUses = new int[exposedNames.length];
|
int[] lexicalUses = new int[exposedNames.length];
|
||||||
for (int j = 0; j < exposedNames.length; j++) {
|
for (int j = 0; j < exposedNames.length; j++) {
|
||||||
lexicalUses[j] = exposedNames[j].snd;
|
if (entityName == null || entityName.equals(exposedNames[j].fst.snd)) {
|
||||||
|
lexicalUses[j] = exposedNames[j].snd;
|
||||||
|
} else {
|
||||||
|
lexicalUses[j] = -1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return lexicalUses;
|
return lexicalUses;
|
||||||
|
@ -2273,7 +2277,7 @@ public abstract class AstTranslator extends CAstVisitor implements ArrayOpHandle
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
AstLexicalInformation(Scope scope, SSAInstruction[] instrs, Set<Pair<Pair<String, String>, Integer>> exposedNamesSet,
|
AstLexicalInformation(String entityName, Scope scope, SSAInstruction[] instrs, Set<Pair<Pair<String, String>, Integer>> exposedNamesSet,
|
||||||
Set<Access> accesses) {
|
Set<Access> accesses) {
|
||||||
Pair<Pair<String, String>, Integer>[] EN = null;
|
Pair<Pair<String, String>, Integer>[] EN = null;
|
||||||
if (exposedNamesSet != null) {
|
if (exposedNamesSet != null) {
|
||||||
|
@ -2285,12 +2289,12 @@ public abstract class AstTranslator extends CAstVisitor implements ArrayOpHandle
|
||||||
// the value numbers stored in exitLexicalUses and instructionLexicalUses
|
// the value numbers stored in exitLexicalUses and instructionLexicalUses
|
||||||
// are identical at first; they will be updated
|
// are identical at first; they will be updated
|
||||||
// as needed during the final SSA conversion
|
// as needed during the final SSA conversion
|
||||||
this.exitLexicalUses = buildLexicalUseArray(EN);
|
this.exitLexicalUses = buildLexicalUseArray(EN, entityName);
|
||||||
|
|
||||||
this.instructionLexicalUses = new int[instrs.length][];
|
this.instructionLexicalUses = new int[instrs.length][];
|
||||||
for (int i = 0; i < instrs.length; i++) {
|
for (int i = 0; i < instrs.length; i++) {
|
||||||
if (instrs[i] instanceof SSAAbstractInvokeInstruction) {
|
if (instrs[i] instanceof SSAAbstractInvokeInstruction) {
|
||||||
this.instructionLexicalUses[i] = buildLexicalUseArray(EN);
|
this.instructionLexicalUses[i] = buildLexicalUseArray(EN, null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2330,8 +2334,10 @@ public abstract class AstTranslator extends CAstVisitor implements ArrayOpHandle
|
||||||
return exitLexicalUses;
|
return exitLexicalUses;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static final int[] NONE = new int[0];
|
||||||
|
|
||||||
public int[] getExposedUses(int instructionOffset) {
|
public int[] getExposedUses(int instructionOffset) {
|
||||||
return instructionLexicalUses[instructionOffset];
|
return instructionLexicalUses[instructionOffset]==null? NONE: instructionLexicalUses[instructionOffset];
|
||||||
}
|
}
|
||||||
|
|
||||||
public IntSet getAllExposedUses() {
|
public IntSet getAllExposedUses() {
|
||||||
|
@ -2339,7 +2345,9 @@ public abstract class AstTranslator extends CAstVisitor implements ArrayOpHandle
|
||||||
allExposedUses = IntSetUtil.make();
|
allExposedUses = IntSetUtil.make();
|
||||||
if (exitLexicalUses != null) {
|
if (exitLexicalUses != null) {
|
||||||
for (int i = 0; i < exitLexicalUses.length; i++) {
|
for (int i = 0; i < exitLexicalUses.length; i++) {
|
||||||
allExposedUses.add(exitLexicalUses[i]);
|
if (exitLexicalUses[i] > 0) {
|
||||||
|
allExposedUses.add(exitLexicalUses[i]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (instructionLexicalUses != null) {
|
if (instructionLexicalUses != null) {
|
||||||
|
@ -2765,7 +2773,7 @@ public abstract class AstTranslator extends CAstVisitor implements ArrayOpHandle
|
||||||
// (put here to allow subclasses to handle stuff in scoped entities)
|
// (put here to allow subclasses to handle stuff in scoped entities)
|
||||||
// assemble lexical information
|
// assemble lexical information
|
||||||
patchLexicalAccesses(cfg.getInstructions(), accesses.get(n));
|
patchLexicalAccesses(cfg.getInstructions(), accesses.get(n));
|
||||||
AstLexicalInformation LI = new AstLexicalInformation((AbstractScope) functionContext.currentScope(), cfg.getInstructions(),
|
AstLexicalInformation LI = new AstLexicalInformation(getEntityName(n), (AbstractScope) functionContext.currentScope(), cfg.getInstructions(),
|
||||||
exposedNames.get(n), accesses.get(n));
|
exposedNames.get(n), accesses.get(n));
|
||||||
|
|
||||||
DebuggingInformation DBG = new AstDebuggingInformation(n.getPosition(), line, nms);
|
DebuggingInformation DBG = new AstDebuggingInformation(n.getPosition(), line, nms);
|
||||||
|
|
|
@ -48,7 +48,7 @@ public abstract class AstMethod implements IMethod {
|
||||||
|
|
||||||
public IntSet getAllExposedUses();
|
public IntSet getAllExposedUses();
|
||||||
|
|
||||||
public Pair[] getExposedNames();
|
public Pair<String, String>[] getExposedNames();
|
||||||
|
|
||||||
public String[] getScopingParents();
|
public String[] getScopingParents();
|
||||||
|
|
||||||
|
@ -141,7 +141,7 @@ public abstract class AstMethod implements IMethod {
|
||||||
* methods containing state possibly referenced lexically in this
|
* methods containing state possibly referenced lexically in this
|
||||||
* method
|
* method
|
||||||
*/
|
*/
|
||||||
public abstract class LexicalParent {
|
public static abstract class LexicalParent {
|
||||||
public abstract String getName();
|
public abstract String getName();
|
||||||
public abstract AstMethod getMethod();
|
public abstract AstMethod getMethod();
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue