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;
|
||||
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.JSSourceExtractor;
|
||||
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.jericho.JerichoHtmlParser;
|
||||
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.util.CancelException;
|
||||
|
||||
public class JsViewerDriver {
|
||||
public class JsViewerDriver extends Util {
|
||||
public static void main(String args[]) throws ClassHierarchyException, IllegalArgumentException, IOException, CancelException {
|
||||
|
||||
if (args.length != 1){
|
||||
|
@ -39,7 +40,7 @@ public class JsViewerDriver {
|
|||
|
||||
SourceModule[] sources = getSources(domless, url);
|
||||
|
||||
JSCFABuilder builder = Util.makeCGBuilder(sources, false);
|
||||
JSCFABuilder builder = makeCGBuilder(new WebPageLoaderFactory(translatorFactory), sources, false);
|
||||
builder.setBaseURL(url);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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 );
|
||||
|
||||
aa();
|
||||
|
|
|
@ -45,6 +45,24 @@ public class TestForInLoopHack extends TestJSCallGraphShape {
|
|||
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[][] {
|
||||
new Object[] { ROOT,
|
||||
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");
|
||||
CallGraph CG = Util.makeHTMLCG(url);
|
||||
verifyGraphAssertions(CG, assertionsForSwineFlu);
|
||||
System.err.println(CG);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -281,12 +281,31 @@ public abstract class TestSimplePageCallGraphShape extends TestJSCallGraphShape
|
|||
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 {
|
||||
URL url = getClass().getClassLoader().getResource("pages/jquery.html");
|
||||
CallGraph CG = Util.makeHTMLCG(url);
|
||||
}
|
||||
*/
|
||||
|
||||
/*
|
||||
@Test public void testDojoTest() throws IllegalArgumentException, IOException, CancelException {
|
||||
URL url = getClass().getClassLoader().getResource("pages/dojo/test.html");
|
||||
CallGraph CG = Util.makeHTMLCG(url);
|
||||
|
|
|
@ -19,6 +19,7 @@ import java.util.Set;
|
|||
import junit.framework.Assert;
|
||||
|
||||
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.ipa.callgraph.JSCFABuilder;
|
||||
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,
|
||||
CancelException {
|
||||
PropagationCallGraphBuilder b = makeCGBuilder(scripts, useOneCFA);
|
||||
PropagationCallGraphBuilder b = makeCGBuilder(makeLoaders(), scripts, useOneCFA);
|
||||
CallGraph CG = b.makeCallGraph(b.getOptions());
|
||||
dumpCG(b.getPointerAnalysis(), 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 {
|
||||
JavaScriptLoader.addBootstrapFile(WebUtil.preamble);
|
||||
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);
|
||||
return builder;
|
||||
}
|
||||
|
@ -105,8 +106,7 @@ public class Util extends com.ibm.wala.cast.js.ipa.callgraph.Util {
|
|||
return CG;
|
||||
}
|
||||
|
||||
public static JSCFABuilder makeCGBuilder(SourceModule[] scripts, boolean useOneCFA) throws IOException {
|
||||
JavaScriptLoaderFactory loaders = makeLoaders();
|
||||
public static JSCFABuilder makeCGBuilder(JavaScriptLoaderFactory loaders, SourceModule[] scripts, boolean useOneCFA) throws IOException {
|
||||
AnalysisScope scope = makeScope(scripts, loaders, JavaScriptLoader.JS);
|
||||
return makeCG(loaders, scope, useOneCFA);
|
||||
}
|
||||
|
|
|
@ -15,7 +15,7 @@ note_post_parameters = function notePostParameters(url) {
|
|||
// hook for analysis of Web pages
|
||||
};
|
||||
|
||||
function NamedNodeList() {
|
||||
NamedNodeList = function NamedNodeList() {
|
||||
var maxLength = 10;
|
||||
var local = new Array(10);
|
||||
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.insertBefore = function 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();
|
||||
|
||||
|
@ -137,11 +137,11 @@ function DOMDocument() {
|
|||
};
|
||||
}
|
||||
|
||||
function HTMLBody(){
|
||||
HTMLBody = function HTMLBody(){
|
||||
this.innerHTML = new String();
|
||||
}
|
||||
|
||||
function DOMHTMLDocument() {
|
||||
DOMHTMLDocument = function DOMHTMLDocument() {
|
||||
this.temp = DOMDocument;
|
||||
this.temp();
|
||||
this.URL = new String();
|
||||
|
@ -150,7 +150,7 @@ function DOMHTMLDocument() {
|
|||
}
|
||||
|
||||
|
||||
function Location(){
|
||||
Location = function Location(){
|
||||
this.host = new String();
|
||||
this.hostname = new String();
|
||||
this.href = new String();
|
||||
|
@ -163,14 +163,14 @@ function Location(){
|
|||
}
|
||||
|
||||
|
||||
function DOMWindow(){
|
||||
DOMWindow = function DOMWindow(){
|
||||
this.name = new String();
|
||||
this.open = function window_open(url, stuff) {
|
||||
note_url(url);
|
||||
};
|
||||
}
|
||||
|
||||
function DOJOObj(){
|
||||
DOJOObj = function DOJOObj(){
|
||||
this.moduleUrl = function module_url(str1, str2){
|
||||
return str1 + str2;
|
||||
}
|
||||
|
@ -194,7 +194,7 @@ window.XMLHttpRequest = XMLHttpRequest;
|
|||
|
||||
var dojo = new DOJOObj();
|
||||
|
||||
function DOMElement() { // An impostor for the Element class
|
||||
DOMElement = function DOMElement() { // An impostor for the Element class
|
||||
// inherits from Node
|
||||
this.temp = DOMNode;
|
||||
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
|
||||
this.temp = DOMElement;
|
||||
this.temp();
|
||||
|
@ -234,7 +234,7 @@ function DOMHTMLElement() { // An impostor for the HTMLElement class
|
|||
var dynamic_node = 0;
|
||||
|
||||
// Just a hack until all HTML elements have corresponding constructors
|
||||
function DOMHTMLGenericElement(tagName) {
|
||||
DOMHTMLGenericElement = function DOMHTMLGenericElement(tagName) {
|
||||
// inherits from Element
|
||||
this.temp = DOMHTMLElement;
|
||||
this.temp();
|
||||
|
@ -253,7 +253,7 @@ function DOMHTMLGenericElement(tagName) {
|
|||
|
||||
var formCount = 0;
|
||||
|
||||
function DOMHTMLFormElement() {
|
||||
DOMHTMLFormElement = function DOMHTMLFormElement() {
|
||||
// inherits from HTMLElement
|
||||
this.temp = DOMHTMLElement;
|
||||
this.temp();
|
||||
|
@ -281,7 +281,7 @@ function DOMHTMLFormElement() {
|
|||
this.target = null;
|
||||
}
|
||||
|
||||
function DOMHTMLTableElement () {
|
||||
DOMHTMLTableElement = function DOMHTMLTableElement () {
|
||||
// inherits from HTMLElement
|
||||
this.temp = DOMHTMLElement;
|
||||
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);
|
||||
SymbolTable sourceST = sourceIR.getSymbolTable();
|
||||
|
||||
|
||||
IR targetIR = getCFAContextInterpreter().getIR(target);
|
||||
SymbolTable targetST = targetIR.getSymbolTable();
|
||||
|
||||
|
@ -504,7 +504,7 @@ public class JSSSAPropagationCallGraphBuilder extends AstSSAPropagationCallGraph
|
|||
|
||||
// pass actual arguments to formals in the normal way
|
||||
for (int i = 0; i < Math.min(paramCount, argCount); i++) {
|
||||
int fn = targetST.getConstant(i);
|
||||
InstanceKey[] fn = new InstanceKey[]{ getInstanceKeyForConstant(JavaScriptTypes.Number, i) };
|
||||
PointerKey F = getTargetPointerKey(target, i);
|
||||
|
||||
if (constParams != null && constParams[i] != null) {
|
||||
|
@ -528,7 +528,7 @@ public class JSSSAPropagationCallGraphBuilder extends AstSSAPropagationCallGraph
|
|||
if (paramCount < argCount) {
|
||||
if (av != -1) {
|
||||
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) {
|
||||
targetVisitor.newFieldWrite(target, av, fn, constParams[i]);
|
||||
} else {
|
||||
|
@ -554,8 +554,8 @@ public class JSSSAPropagationCallGraphBuilder extends AstSSAPropagationCallGraph
|
|||
|
||||
// write `length' in argument objects
|
||||
if (av != -1) {
|
||||
int svn = targetST.getConstant(argCount);
|
||||
int lnv = targetST.getConstant("length");
|
||||
InstanceKey[] svn = new InstanceKey[]{ getInstanceKeyForConstant(JavaScriptTypes.Number, argCount) };
|
||||
InstanceKey[] lnv = new InstanceKey[]{ getInstanceKeyForConstant(JavaScriptTypes.String, "length") };
|
||||
targetVisitor.newFieldWrite(target, av, lnv, svn);
|
||||
}
|
||||
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
*****************************************************************************/
|
||||
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.ipa.callgraph.AnalysisCache;
|
||||
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 = new ScopeMappingKeysContextSelector(contextSelector);
|
||||
contextSelector = new JavaScriptConstructorContextSelector(contextSelector);
|
||||
contextSelector = new LexicalScopingResolverContexts(this, contextSelector);
|
||||
if (doOneCFA) {
|
||||
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
|
||||
* 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
|
||||
|
|
|
@ -21,7 +21,7 @@ import com.ibm.wala.types.ClassLoaderReference;
|
|||
* Creates the single {@link IClassLoader class loader} used for JavaScript.
|
||||
*/
|
||||
public class JavaScriptLoaderFactory extends SingleClassLoaderFactory {
|
||||
private final JavaScriptTranslatorFactory translatorFactory;
|
||||
protected final JavaScriptTranslatorFactory translatorFactory;
|
||||
|
||||
public JavaScriptLoaderFactory(JavaScriptTranslatorFactory factory) {
|
||||
this.translatorFactory = factory;
|
||||
|
|
|
@ -58,7 +58,7 @@ public class JSAstTranslator extends AstTranslator {
|
|||
}
|
||||
|
||||
protected boolean treatGlobalsAsLexicallyScoped() {
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
protected boolean useLocalValuesForLexicalVars() {
|
||||
|
@ -145,12 +145,7 @@ public class JSAstTranslator extends AstTranslator {
|
|||
|
||||
// force creation of these constants by calling the getter methods
|
||||
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,
|
||||
debugInfo);
|
||||
}
|
||||
|
|
|
@ -17,6 +17,7 @@ import java.util.Set;
|
|||
|
||||
import com.ibm.wala.analysis.reflection.ReflectionContextInterpreter;
|
||||
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.ir.ssa.AbstractLexicalInvoke;
|
||||
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.AstInstructionVisitor;
|
||||
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.AstLexicalRead;
|
||||
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);
|
||||
}
|
||||
|
||||
private void visitLexical(final LexicalOperator op) {
|
||||
final PointerKey function = getPointerKeyForLocal(1);
|
||||
if (contentsAreInvariant(symbolTable, du, 1)) {
|
||||
op.doLexicalPointerKeys();
|
||||
} else {
|
||||
system.newSideEffect(op, function);
|
||||
private void visitLexical(AstLexicalAccess instruction, final LexicalOperator op) {
|
||||
op.doLexicalPointerKeys(false);
|
||||
if (! checkLexicalInstruction(instruction)) {
|
||||
system.newSideEffect(op, getPointerKeyForLocal(1));
|
||||
}
|
||||
|
||||
// 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) {
|
||||
visitLexical(new LexicalOperator((AstCGNode) node, instruction.getAccesses(), true) {
|
||||
private boolean checkLexicalInstruction(AstLexicalAccess instruction) {
|
||||
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) {
|
||||
PointerKey lval = getPointerKeyForLocal(vn);
|
||||
if (lexicalKey instanceof LocalPointerKey) {
|
||||
|
@ -360,7 +353,7 @@ public abstract class AstSSAPropagationCallGraphBuilder extends SSAPropagationCa
|
|||
}
|
||||
|
||||
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) {
|
||||
PointerKey rval = getPointerKeyForLocal(vn);
|
||||
if (contentsAreInvariant(symbolTable, du, vn)) {
|
||||
|
@ -403,11 +396,10 @@ public abstract class AstSSAPropagationCallGraphBuilder extends SSAPropagationCa
|
|||
} catch (UTFDataFormatException e) {
|
||||
Assertions.UNREACHABLE();
|
||||
}
|
||||
int fieldNameVn = symtab.getConstant(fieldName);
|
||||
|
||||
final PointerKey objKey = getPointerKeyForLocal(objVn);
|
||||
|
||||
final InstanceKey[] fieldNameKeys = getInvariantContents(fieldNameVn);
|
||||
final InstanceKey[] fieldNameKeys = new InstanceKey[]{ getInstanceKeyForConstant(fieldName) };
|
||||
assert fieldNameKeys.length == 1;
|
||||
|
||||
if (contentsAreInvariant(symtab, du, objVn)) {
|
||||
|
@ -539,12 +531,14 @@ public abstract class AstSSAPropagationCallGraphBuilder extends SSAPropagationCa
|
|||
// callees where the name is not written;
|
||||
// in such cases, the original value (rk) is preserved
|
||||
PointerKey rk = getBuilder().getPointerKeyForLocal(node, r.valueNumber);
|
||||
PointerKey wk = getBuilder().getPointerKeyForLocal(node, w.valueNumber);
|
||||
if (contentsAreInvariant(symbolTable, du, r.valueNumber)) {
|
||||
PointerKey wk = getBuilder().getPointerKeyForLocal(node, w.valueNumber);
|
||||
if (contentsAreInvariant(node.getIR().getSymbolTable(), du, r.valueNumber)) {
|
||||
system.recordImplicitPointsToSet(rk);
|
||||
for (InstanceKey ik : getInvariantContents(r.valueNumber)) {
|
||||
system.newConstraint(wk, ik);
|
||||
}
|
||||
final InstanceKey[] objKeys = getInvariantContents(r.valueNumber);
|
||||
|
||||
for (int i = 0; i < objKeys.length; i++) {
|
||||
system.newConstraint(wk, objKeys[0]);
|
||||
}
|
||||
} else {
|
||||
system.newConstraint(wk, assignOperator, rk);
|
||||
}
|
||||
|
@ -600,7 +594,8 @@ public abstract class AstSSAPropagationCallGraphBuilder extends SSAPropagationCa
|
|||
* {@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++) {
|
||||
final String name = accesses[i].variableName;
|
||||
final String definer = accesses[i].variableDefiner;
|
||||
|
@ -609,49 +604,31 @@ public abstract class AstSSAPropagationCallGraphBuilder extends SSAPropagationCa
|
|||
if (AstTranslator.DEBUG_LEXICAL)
|
||||
System.err.println(("looking up lexical parent " + definer));
|
||||
|
||||
for (Iterator<CGNode> DS = getLexicalDefiners(node, definer).iterator(); DS.hasNext();) {
|
||||
final CGNode D = DS.next();
|
||||
|
||||
Iterator PS = new NumberedDFSDiscoverTimeIterator<CGNode>(getBuilder().getCallGraph(), node) {
|
||||
/**
|
||||
*
|
||||
*/
|
||||
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);
|
||||
Iterator<Pair<CallSiteReference,CGNode>> sites;
|
||||
if (r != null && (sites = r.getLexicalSites(accesses[i])) != null) {
|
||||
if (! funargsOnly) {
|
||||
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);
|
||||
|
||||
if (V != null) {
|
||||
action(V, vn);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected Iterator<? extends CGNode> getConnected(CGNode n) {
|
||||
if (n.equals(D))
|
||||
return EmptyIterator.instance();
|
||||
else
|
||||
// traverse backwards
|
||||
return G.getPredNodes(n);
|
||||
}
|
||||
};
|
||||
|
||||
while (PS.hasNext()) {
|
||||
PS.next();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
Set<CGNode> creators = getLexicalDefiners(node, Pair.make(name, definer));
|
||||
for(CGNode n : creators) {
|
||||
PointerKey funargKey = handleRootLexicalReference(name, definer, n);
|
||||
action(funargKey, vn);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public byte evaluate(PointsToSetVariable lhs, PointsToSetVariable rhs) {
|
||||
doLexicalPointerKeys();
|
||||
doLexicalPointerKeys(true);
|
||||
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) {
|
||||
return Collections.singleton(getBuilder().getCallGraph().getFakeRootNode());
|
||||
|
||||
|
@ -716,7 +693,10 @@ public abstract class AstSSAPropagationCallGraphBuilder extends SSAPropagationCa
|
|||
for (int f = 0; f < functionKeys.length; f++) {
|
||||
system.findOrCreateIndexForInstanceKey(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 {
|
||||
PointsToSetVariable FV = system.findOrCreatePointsToSet(F);
|
||||
|
@ -726,7 +706,10 @@ public abstract class AstSSAPropagationCallGraphBuilder extends SSAPropagationCa
|
|||
InstanceKey iKey = system.getInstanceKey(ptr);
|
||||
if (iKey instanceof ScopeMappingInstanceKey) {
|
||||
ScopeMappingInstanceKey K = (ScopeMappingInstanceKey) iKey;
|
||||
result.add(K.getDefiningNode(definer));
|
||||
Iterator<CGNode> x = K.getFunargNodes(definer);
|
||||
while (x.hasNext()) {
|
||||
result.add(x.next());
|
||||
}
|
||||
} else {
|
||||
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
|
||||
* requiring marking of the IR as mutated.
|
||||
*/
|
||||
private PointerKey getLocalReadKey(CGNode n, CallSiteReference callSite, String name, String definer, CGNode definingNode) {
|
||||
IMethod M = n.getMethod();
|
||||
if (n == getBuilder().getCallGraph().getFakeRootNode()) {
|
||||
return handleRootLexicalReference(name, definer, definingNode);
|
||||
private PointerKey getLocalReadKey(CGNode n, CallSiteReference callSite, String name, String definer) {
|
||||
AstIR ir = (AstIR) n.getIR();
|
||||
int pc = callSite.getProgramCounter();
|
||||
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) {
|
||||
AstIR ir = (AstIR) n.getIR();
|
||||
int pc = callSite.getProgramCounter();
|
||||
LexicalInformation L = ((AstIR) n.getIR()).lexicalInfo();
|
||||
// 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;
|
||||
|
||||
// some people have no lexical uses at all
|
||||
if (L == null) {
|
||||
return null;
|
||||
}
|
||||
I.addLexicalUse(new Access(name, definer, values[i]));
|
||||
|
||||
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
|
||||
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);
|
||||
SSAConversion.copyUse(ir, pc, -i - 1, pc, I.getNumberOfUses() - 1);
|
||||
|
||||
((AstCallGraph.AstCGNode) n).setLexicallyMutatedIR(ir);
|
||||
|
||||
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) {
|
||||
AstMethod AstM = (AstMethod) M;
|
||||
AstIR ir = (AstIR) n.getIR();
|
||||
LexicalInformation L = ir.lexicalInfo();
|
||||
return null;
|
||||
|
||||
// some people have no lexical uses at all
|
||||
if (L == null)
|
||||
return null;
|
||||
}
|
||||
|
||||
int pc = callSite.getProgramCounter();
|
||||
AbstractLexicalInvoke I = (AbstractLexicalInvoke) ir.getInstructions()[pc];
|
||||
private PointerKey getLocalWriteKey(CGNode n, CallSiteReference callSite, String name, String definer) {
|
||||
AstMethod AstM = (AstMethod) n.getMethod();;
|
||||
AstIR ir = (AstIR) n.getIR();
|
||||
LexicalInformation L = ir.lexicalInfo();
|
||||
|
||||
// find existing explicit lexical def
|
||||
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);
|
||||
}
|
||||
int pc = callSite.getProgramCounter();
|
||||
AbstractLexicalInvoke I = (AbstractLexicalInvoke) ir.getInstructions()[pc];
|
||||
|
||||
// find existing explicit lexical def
|
||||
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
|
||||
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;
|
||||
// make new lexical def
|
||||
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;
|
||||
|
||||
// find calls that may be altered, and clear their caches
|
||||
DefUse newDU = getAnalysisCache().getSSACache().findOrCreateDU(ir, n.getContext());
|
||||
Iterator<SSAInstruction> insts = newDU.getUses(values[i]);
|
||||
while (insts.hasNext()) {
|
||||
SSAInstruction inst = insts.next();
|
||||
if (inst instanceof SSAAbstractInvokeInstruction) {
|
||||
System.err.println("clearing for " + inst);
|
||||
CallSiteReference cs = ((SSAAbstractInvokeInstruction) inst).getCallSite();
|
||||
((AstCallGraph.AstCGNode) n).clearMutatedCache(cs);
|
||||
}
|
||||
// find calls that may be altered, and clear their caches
|
||||
DefUse newDU = getAnalysisCache().getSSACache().findOrCreateDU(ir, n.getContext());
|
||||
Iterator<SSAInstruction> insts = newDU.getUses(values[i]);
|
||||
while (insts.hasNext()) {
|
||||
SSAInstruction inst = insts.next();
|
||||
if (inst instanceof SSAAbstractInvokeInstruction) {
|
||||
System.err.println("clearing for " + inst);
|
||||
CallSiteReference cs = ((SSAAbstractInvokeInstruction) inst).getCallSite();
|
||||
((AstCallGraph.AstCGNode) n).clearMutatedCache(cs);
|
||||
}
|
||||
}
|
||||
|
||||
// if values[i] was altered by copy propagation, we must undo
|
||||
// that to ensure we do not bash the wrong value number in the
|
||||
// the next steps.
|
||||
SSAConversion.undoCopyPropagation(ir, pc, -i - 1);
|
||||
// if values[i] was altered by copy propagation, we must undo
|
||||
// that to ensure we do not bash the wrong value number in the
|
||||
// the next steps.
|
||||
SSAConversion.undoCopyPropagation(ir, pc, -i - 1);
|
||||
|
||||
// possibly new instruction due to renames, so get it again
|
||||
I = (AbstractLexicalInvoke) ir.getInstructions()[pc];
|
||||
// possibly new instruction due to renames, so get it again
|
||||
I = (AbstractLexicalInvoke) ir.getInstructions()[pc];
|
||||
|
||||
// we assume that the callee might not necessarily write,
|
||||
// so the call becomes like a phi node. hence it needs a
|
||||
// read of the old value
|
||||
ensureRead: {
|
||||
for (int l = 0; l < I.getNumberOfUses(); l++) {
|
||||
if (I.isLexicalUse(l)) {
|
||||
Access r = I.getLexicalUse(l);
|
||||
if (name.equals(r.variableName)) {
|
||||
if (definer == null ? r.variableDefiner == null : definer.equals(r.variableDefiner)) {
|
||||
break ensureRead;
|
||||
}
|
||||
// we assume that the callee might not necessarily write,
|
||||
// so the call becomes like a phi node. hence it needs a
|
||||
// read of the old value
|
||||
ensureRead: {
|
||||
for (int l = 0; l < I.getNumberOfUses(); l++) {
|
||||
if (I.isLexicalUse(l)) {
|
||||
Access r = I.getLexicalUse(l);
|
||||
if (name.equals(r.variableName)) {
|
||||
if (definer == null ? r.variableDefiner == null : definer.equals(r.variableDefiner)) {
|
||||
break ensureRead;
|
||||
}
|
||||
}
|
||||
}
|
||||
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);
|
||||
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(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);
|
||||
InstanceKey[] fieldsKeys = getInvariantContents(symtab, du, opNode, fieldsVn);
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
newFieldOperationObjectAndFieldConstant(isLoadOperation, action, objKeys, fieldsKeys);
|
||||
|
||||
} else {
|
||||
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" + objVn + ", " + fieldsVn;
|
||||
}
|
||||
}, fieldKey);
|
||||
newFieldOperationOnlyObjectConstant(isLoadOperation, action, fieldKey, objKeys);
|
||||
}
|
||||
|
||||
} else {
|
||||
|
@ -1149,101 +1040,10 @@ public abstract class AstSSAPropagationCallGraphBuilder extends SSAPropagationCa
|
|||
system.recordImplicitPointsToSet(fieldKey);
|
||||
final InstanceKey[] fieldsKeys = getInvariantContents(symtab, du, opNode, fieldsVn);
|
||||
|
||||
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" + objVn + ", " + fieldsVn;
|
||||
}
|
||||
}, objKey);
|
||||
newFieldOperationOnlyFieldConstant(isLoadOperation, action, objKey, fieldsKeys);
|
||||
|
||||
} else {
|
||||
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);
|
||||
newFieldFullOperation(isLoadOperation, action, objKey, fieldKey);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1251,6 +1051,210 @@ public abstract class AstSSAPropagationCallGraphBuilder extends SSAPropagationCa
|
|||
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) {
|
||||
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) {
|
||||
try {
|
||||
private final class ConstantWriter implements ReflectedFieldAction {
|
||||
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) {
|
||||
System.err.println(("writing fixed rvals to " + fieldKey + " " + constObj + ", " + constProp));
|
||||
for (int i = 0; i < rhsFixedValues.length; i++) {
|
||||
System.err.println(("writing " + rhsFixedValues[i]));
|
||||
}
|
||||
public void dump(AbstractFieldPointerKey fieldKey, boolean constObj, boolean constProp) {
|
||||
System.err.println(("writing fixed rvals to " + fieldKey + " " + constObj + ", " + constProp));
|
||||
for (int i = 0; i < rhsFixedValues.length; 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) {
|
||||
newFieldOperation(opNode, objVn, fieldsVn, false, new ReflectedFieldAction() {
|
||||
public void dump(AbstractFieldPointerKey fieldKey, boolean constObj, boolean constProp) {
|
||||
System.err.println(("write " + rhs + " to " + fieldKey + " " + constObj + ", " + constProp));
|
||||
}
|
||||
newFieldOperation(opNode, objVn, fieldsVn, false, new NormalWriter(rhs));
|
||||
}
|
||||
|
||||
public void action(AbstractFieldPointerKey fieldKey) {
|
||||
if (!representsNullType(fieldKey.getInstanceKey())) {
|
||||
system.newConstraint(fieldKey, assignOperator, rhs);
|
||||
}
|
||||
}
|
||||
});
|
||||
public void newFieldWrite(CGNode opNode, int objVn, InstanceKey[] fieldKeys, final PointerKey rhs) {
|
||||
newFieldOperationFieldConstant(opNode, false, new NormalWriter(rhs), objVn, fieldKeys);
|
||||
}
|
||||
|
||||
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) {
|
||||
|
@ -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;
|
||||
|
||||
import java.util.HashMap;
|
||||
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.classLoader.IClass;
|
||||
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.propagation.InstanceKey;
|
||||
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.types.TypeReference;
|
||||
import com.ibm.wala.util.collections.HashMapFactory;
|
||||
import com.ibm.wala.util.graph.impl.GraphInverter;
|
||||
import com.ibm.wala.util.graph.traverse.DFS;
|
||||
import com.ibm.wala.util.collections.CompoundIterator;
|
||||
import com.ibm.wala.util.collections.EmptyIterator;
|
||||
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
|
||||
|
@ -33,12 +35,6 @@ import com.ibm.wala.util.graph.traverse.DFS;
|
|||
*/
|
||||
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
|
||||
* in a nested lexical scope
|
||||
|
@ -76,47 +72,16 @@ abstract public class ScopeMappingInstanceKeys implements InstanceKeyFactory {
|
|||
*/
|
||||
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
|
||||
* {@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) {
|
||||
this.creator = creator;
|
||||
this.base = base;
|
||||
this.scopeMap = HashMapFactory.make();
|
||||
computeLexicalParentCGNodes();
|
||||
}
|
||||
|
||||
public IClass getConcreteType() {
|
||||
|
@ -128,8 +93,26 @@ abstract public class ScopeMappingInstanceKeys implements InstanceKeyFactory {
|
|||
* @param definer
|
||||
* @return
|
||||
*/
|
||||
CGNode getDefiningNode(String definer) {
|
||||
return scopeMap.get(definer);
|
||||
Iterator<CGNode> getFunargNodes(Pair<String,String> name) {
|
||||
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() {
|
||||
|
@ -146,10 +129,10 @@ abstract public class ScopeMappingInstanceKeys implements InstanceKeyFactory {
|
|||
}
|
||||
}
|
||||
|
||||
public InstanceKey getInstanceKeyForAllocation(CGNode node, NewSiteReference allocation) {
|
||||
InstanceKey base = basic.getInstanceKeyForAllocation(node, allocation);
|
||||
public InstanceKey getInstanceKeyForAllocation(CGNode creatorNode, NewSiteReference allocationSite) {
|
||||
InstanceKey base = basic.getInstanceKeyForAllocation(creatorNode, allocationSite);
|
||||
if (base != null && needsScopeMappingKey(base)) {
|
||||
return new ScopeMappingInstanceKey(node, base);
|
||||
return new ScopeMappingInstanceKey(creatorNode, base);
|
||||
} else {
|
||||
return base;
|
||||
}
|
||||
|
|
|
@ -461,9 +461,13 @@ public class SSAConversion extends AbstractSSAConversion {
|
|||
|
||||
int[] exitLive = lexicalInfo.getExitExposedUses();
|
||||
BitVector v = new BitVector();
|
||||
if (exitLive != null)
|
||||
for (int i = 0; i < exitLive.length; i++)
|
||||
v.set(exitLive[i]);
|
||||
if (exitLive != null) {
|
||||
for (int i = 0; i < exitLive.length; i++) {
|
||||
if (exitLive[i] > -1) {
|
||||
v.set(exitLive[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
this.liveness = LiveAnalysis.perform(CFG, symtab, v);
|
||||
|
||||
if (DEBUG) {
|
||||
|
@ -514,7 +518,7 @@ public class SSAConversion extends AbstractSSAConversion {
|
|||
int[] exitLives = lexicalInfo.getExitExposedUses();
|
||||
if (exitLives != null) {
|
||||
for (int i = 0; i < exitLives.length; i++) {
|
||||
if (!skip(exitLives[i])) {
|
||||
if (exitLives[i] != -1 && !skip(exitLives[i])) {
|
||||
assert !S[exitLives[i]].isEmpty();
|
||||
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) {
|
||||
int[] lexicalUses = new int[exposedNames.length];
|
||||
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;
|
||||
|
@ -2273,7 +2277,7 @@ public abstract class AstTranslator extends CAstVisitor implements ArrayOpHandle
|
|||
}
|
||||
|
||||
@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) {
|
||||
Pair<Pair<String, String>, Integer>[] EN = null;
|
||||
if (exposedNamesSet != null) {
|
||||
|
@ -2285,12 +2289,12 @@ public abstract class AstTranslator extends CAstVisitor implements ArrayOpHandle
|
|||
// the value numbers stored in exitLexicalUses and instructionLexicalUses
|
||||
// are identical at first; they will be updated
|
||||
// as needed during the final SSA conversion
|
||||
this.exitLexicalUses = buildLexicalUseArray(EN);
|
||||
this.exitLexicalUses = buildLexicalUseArray(EN, entityName);
|
||||
|
||||
this.instructionLexicalUses = new int[instrs.length][];
|
||||
for (int i = 0; i < instrs.length; i++) {
|
||||
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;
|
||||
}
|
||||
|
||||
private static final int[] NONE = new int[0];
|
||||
|
||||
public int[] getExposedUses(int instructionOffset) {
|
||||
return instructionLexicalUses[instructionOffset];
|
||||
return instructionLexicalUses[instructionOffset]==null? NONE: instructionLexicalUses[instructionOffset];
|
||||
}
|
||||
|
||||
public IntSet getAllExposedUses() {
|
||||
|
@ -2339,7 +2345,9 @@ public abstract class AstTranslator extends CAstVisitor implements ArrayOpHandle
|
|||
allExposedUses = IntSetUtil.make();
|
||||
if (exitLexicalUses != null) {
|
||||
for (int i = 0; i < exitLexicalUses.length; i++) {
|
||||
allExposedUses.add(exitLexicalUses[i]);
|
||||
if (exitLexicalUses[i] > 0) {
|
||||
allExposedUses.add(exitLexicalUses[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
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)
|
||||
// assemble lexical information
|
||||
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));
|
||||
|
||||
DebuggingInformation DBG = new AstDebuggingInformation(n.getPosition(), line, nms);
|
||||
|
|
|
@ -48,7 +48,7 @@ public abstract class AstMethod implements IMethod {
|
|||
|
||||
public IntSet getAllExposedUses();
|
||||
|
||||
public Pair[] getExposedNames();
|
||||
public Pair<String, String>[] getExposedNames();
|
||||
|
||||
public String[] getScopingParents();
|
||||
|
||||
|
@ -141,7 +141,7 @@ public abstract class AstMethod implements IMethod {
|
|||
* methods containing state possibly referenced lexically in this
|
||||
* method
|
||||
*/
|
||||
public abstract class LexicalParent {
|
||||
public static abstract class LexicalParent {
|
||||
public abstract String getName();
|
||||
public abstract AstMethod getMethod();
|
||||
|
||||
|
|
Loading…
Reference in New Issue