845 lines
28 KiB
Java
845 lines
28 KiB
Java
/*
|
|
* Copyright 2000-2014 JetBrains s.r.o.
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
package org.jetbrains.java.decompiler.modules.decompiler.sforms;
|
|
|
|
import org.jetbrains.java.decompiler.code.CodeConstants;
|
|
import org.jetbrains.java.decompiler.modules.decompiler.exps.*;
|
|
import org.jetbrains.java.decompiler.modules.decompiler.sforms.FlattenStatementsHelper.FinallyPathWrapper;
|
|
import org.jetbrains.java.decompiler.modules.decompiler.stats.*;
|
|
import org.jetbrains.java.decompiler.modules.decompiler.vars.VarVersionEdge;
|
|
import org.jetbrains.java.decompiler.modules.decompiler.vars.VarVersionNode;
|
|
import org.jetbrains.java.decompiler.modules.decompiler.vars.VarVersionPaar;
|
|
import org.jetbrains.java.decompiler.modules.decompiler.vars.VarVersionsGraph;
|
|
import org.jetbrains.java.decompiler.struct.StructMethod;
|
|
import org.jetbrains.java.decompiler.struct.gen.MethodDescriptor;
|
|
import org.jetbrains.java.decompiler.util.FastSparseSetFactory;
|
|
import org.jetbrains.java.decompiler.util.FastSparseSetFactory.FastSparseSet;
|
|
import org.jetbrains.java.decompiler.util.InterpreterUtil;
|
|
import org.jetbrains.java.decompiler.util.SFormsFastMapDirect;
|
|
import org.jetbrains.java.decompiler.util.VBStyleCollection;
|
|
|
|
import java.util.ArrayList;
|
|
import java.util.HashMap;
|
|
import java.util.HashSet;
|
|
import java.util.List;
|
|
import java.util.Map.Entry;
|
|
|
|
public class SSAUConstructorSparseEx {
|
|
|
|
// node id, var, version
|
|
private HashMap<String, SFormsFastMapDirect> inVarVersions = new HashMap<String, SFormsFastMapDirect>();
|
|
//private HashMap<String, HashMap<Integer, FastSet<Integer>>> inVarVersions = new HashMap<String, HashMap<Integer, FastSet<Integer>>>();
|
|
|
|
// node id, var, version (direct branch)
|
|
private HashMap<String, SFormsFastMapDirect> outVarVersions = new HashMap<String, SFormsFastMapDirect>();
|
|
//private HashMap<String, HashMap<Integer, FastSet<Integer>>> outVarVersions = new HashMap<String, HashMap<Integer, FastSet<Integer>>>();
|
|
|
|
// node id, var, version (negative branch)
|
|
private HashMap<String, SFormsFastMapDirect> outNegVarVersions = new HashMap<String, SFormsFastMapDirect>();
|
|
//private HashMap<String, HashMap<Integer, FastSet<Integer>>> outNegVarVersions = new HashMap<String, HashMap<Integer, FastSet<Integer>>>();
|
|
|
|
// node id, var, version
|
|
private HashMap<String, SFormsFastMapDirect> extraVarVersions = new HashMap<String, SFormsFastMapDirect>();
|
|
//private HashMap<String, HashMap<Integer, FastSet<Integer>>> extraVarVersions = new HashMap<String, HashMap<Integer, FastSet<Integer>>>();
|
|
|
|
// (var, version), version
|
|
private HashMap<VarVersionPaar, HashSet<Integer>> phi = new HashMap<VarVersionPaar, HashSet<Integer>>();
|
|
|
|
// var, version
|
|
private HashMap<Integer, Integer> lastversion = new HashMap<Integer, Integer>();
|
|
|
|
// version, protected ranges (catch, finally)
|
|
private HashMap<VarVersionPaar, Integer> mapVersionFirstRange = new HashMap<VarVersionPaar, Integer>();
|
|
|
|
// version, version
|
|
private HashMap<VarVersionPaar, VarVersionPaar> phantomppnodes = new HashMap<VarVersionPaar, VarVersionPaar>(); // ++ and --
|
|
|
|
// node.id, version, version
|
|
private HashMap<String, HashMap<VarVersionPaar, VarVersionPaar>> phantomexitnodes =
|
|
new HashMap<String, HashMap<VarVersionPaar, VarVersionPaar>>(); // finally exits
|
|
|
|
// versions memory dependencies
|
|
private VarVersionsGraph ssuversions = new VarVersionsGraph();
|
|
|
|
// field access vars (exprent id, var id)
|
|
private HashMap<Integer, Integer> mapFieldVars = new HashMap<Integer, Integer>();
|
|
|
|
// field access counter
|
|
private int fieldvarcounter = -1;
|
|
|
|
// set factory
|
|
private FastSparseSetFactory<Integer> factory;
|
|
|
|
public void splitVariables(RootStatement root, StructMethod mt) {
|
|
|
|
FlattenStatementsHelper flatthelper = new FlattenStatementsHelper();
|
|
DirectGraph dgraph = flatthelper.buildDirectGraph(root);
|
|
|
|
HashSet<Integer> setInit = new HashSet<Integer>();
|
|
for (int i = 0; i < 64; i++) {
|
|
setInit.add(i);
|
|
}
|
|
factory = new FastSparseSetFactory<Integer>(setInit);
|
|
|
|
extraVarVersions.put(dgraph.first.id, createFirstMap(mt, root));
|
|
|
|
setCatchMaps(root, dgraph, flatthelper);
|
|
|
|
// try {
|
|
// DotExporter.toDotFile(dgraph, new File("c:\\Temp\\gr12_my.dot"));
|
|
// } catch(Exception ex) {ex.printStackTrace();}
|
|
|
|
HashSet<String> updated = new HashSet<String>();
|
|
do {
|
|
// System.out.println("~~~~~~~~~~~~~ \r\n"+root.toJava());
|
|
ssaStatements(dgraph, updated, false);
|
|
// System.out.println("~~~~~~~~~~~~~ \r\n"+root.toJava());
|
|
}
|
|
while (!updated.isEmpty());
|
|
|
|
|
|
ssaStatements(dgraph, updated, true);
|
|
|
|
ssuversions.initDominators();
|
|
}
|
|
|
|
private void ssaStatements(DirectGraph dgraph, HashSet<String> updated, boolean calcLiveVars) {
|
|
|
|
for (DirectNode node : dgraph.nodes) {
|
|
|
|
updated.remove(node.id);
|
|
mergeInVarMaps(node, dgraph);
|
|
|
|
SFormsFastMapDirect varmap = new SFormsFastMapDirect(inVarVersions.get(node.id));
|
|
|
|
SFormsFastMapDirect[] varmaparr = new SFormsFastMapDirect[]{varmap, null};
|
|
|
|
if (node.exprents != null) {
|
|
for (Exprent expr : node.exprents) {
|
|
processExprent(expr, varmaparr, node.statement, calcLiveVars);
|
|
}
|
|
}
|
|
|
|
if (varmaparr[1] == null) {
|
|
varmaparr[1] = varmaparr[0];
|
|
}
|
|
|
|
// quick solution: 'dummy' field variables should not cross basic block borders (otherwise problems e.g. with finally loops - usage without assignment in a loop)
|
|
// For the full solution consider adding a dummy assignment at the entry point of the method
|
|
boolean allow_field_propagation = node.succs.isEmpty() || (node.succs.size() == 1 && node.succs.get(0).preds.size() == 1);
|
|
|
|
if (!allow_field_propagation && varmaparr[0] != null) {
|
|
varmaparr[0].removeAllFields();
|
|
varmaparr[1].removeAllFields();
|
|
}
|
|
|
|
boolean this_updated = !mapsEqual(varmaparr[0], outVarVersions.get(node.id))
|
|
|| (outNegVarVersions.containsKey(node.id) && !mapsEqual(varmaparr[1], outNegVarVersions.get(node.id)));
|
|
|
|
if (this_updated) {
|
|
|
|
outVarVersions.put(node.id, varmaparr[0]);
|
|
if (dgraph.mapNegIfBranch.containsKey(node.id)) {
|
|
outNegVarVersions.put(node.id, varmaparr[1]);
|
|
}
|
|
|
|
for (DirectNode nd : node.succs) {
|
|
updated.add(nd.id);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
private void processExprent(Exprent expr, SFormsFastMapDirect[] varmaparr, Statement stat, boolean calcLiveVars) {
|
|
|
|
if (expr == null) {
|
|
return;
|
|
}
|
|
|
|
|
|
VarExprent varassign = null;
|
|
boolean finished = false;
|
|
|
|
switch (expr.type) {
|
|
case Exprent.EXPRENT_ASSIGNMENT:
|
|
AssignmentExprent assexpr = (AssignmentExprent)expr;
|
|
if (assexpr.getCondType() == AssignmentExprent.CONDITION_NONE) {
|
|
Exprent dest = assexpr.getLeft();
|
|
if (dest.type == Exprent.EXPRENT_VAR) {
|
|
varassign = (VarExprent)dest;
|
|
}
|
|
}
|
|
break;
|
|
case Exprent.EXPRENT_FUNCTION:
|
|
FunctionExprent func = (FunctionExprent)expr;
|
|
switch (func.getFuncType()) {
|
|
case FunctionExprent.FUNCTION_IIF:
|
|
processExprent(func.getLstOperands().get(0), varmaparr, stat, calcLiveVars);
|
|
|
|
SFormsFastMapDirect varmapFalse;
|
|
if (varmaparr[1] == null) {
|
|
varmapFalse = new SFormsFastMapDirect(varmaparr[0]);
|
|
}
|
|
else {
|
|
varmapFalse = varmaparr[1];
|
|
varmaparr[1] = null;
|
|
}
|
|
|
|
processExprent(func.getLstOperands().get(1), varmaparr, stat, calcLiveVars);
|
|
|
|
SFormsFastMapDirect[] varmaparrNeg = new SFormsFastMapDirect[]{varmapFalse, null};
|
|
processExprent(func.getLstOperands().get(2), varmaparrNeg, stat, calcLiveVars);
|
|
|
|
mergeMaps(varmaparr[0], varmaparrNeg[0]);
|
|
varmaparr[1] = null;
|
|
|
|
finished = true;
|
|
break;
|
|
case FunctionExprent.FUNCTION_CADD:
|
|
processExprent(func.getLstOperands().get(0), varmaparr, stat, calcLiveVars);
|
|
|
|
SFormsFastMapDirect[] varmaparrAnd = new SFormsFastMapDirect[]{new SFormsFastMapDirect(varmaparr[0]), null};
|
|
|
|
processExprent(func.getLstOperands().get(1), varmaparrAnd, stat, calcLiveVars);
|
|
|
|
// false map
|
|
varmaparr[1] = mergeMaps(varmaparr[varmaparr[1] == null ? 0 : 1], varmaparrAnd[varmaparrAnd[1] == null ? 0 : 1]);
|
|
// true map
|
|
varmaparr[0] = varmaparrAnd[0];
|
|
|
|
finished = true;
|
|
break;
|
|
case FunctionExprent.FUNCTION_COR:
|
|
processExprent(func.getLstOperands().get(0), varmaparr, stat, calcLiveVars);
|
|
|
|
SFormsFastMapDirect[] varmaparrOr =
|
|
new SFormsFastMapDirect[]{new SFormsFastMapDirect(varmaparr[varmaparr[1] == null ? 0 : 1]), null};
|
|
|
|
processExprent(func.getLstOperands().get(1), varmaparrOr, stat, calcLiveVars);
|
|
|
|
// false map
|
|
varmaparr[1] = varmaparrOr[varmaparrOr[1] == null ? 0 : 1];
|
|
// true map
|
|
varmaparr[0] = mergeMaps(varmaparr[0], varmaparrOr[0]);
|
|
|
|
finished = true;
|
|
}
|
|
}
|
|
|
|
if (!finished) {
|
|
List<Exprent> lst = expr.getAllExprents();
|
|
lst.remove(varassign);
|
|
|
|
for (Exprent ex : lst) {
|
|
processExprent(ex, varmaparr, stat, calcLiveVars);
|
|
}
|
|
}
|
|
|
|
|
|
SFormsFastMapDirect varmap = varmaparr[0];
|
|
|
|
// field access
|
|
if (expr.type == Exprent.EXPRENT_FIELD) {
|
|
|
|
int index;
|
|
if (mapFieldVars.containsKey(expr.id)) {
|
|
index = mapFieldVars.get(expr.id);
|
|
}
|
|
else {
|
|
index = fieldvarcounter--;
|
|
mapFieldVars.put(expr.id, index);
|
|
|
|
// ssu graph
|
|
ssuversions.createNode(new VarVersionPaar(index, 1));
|
|
}
|
|
|
|
setCurrentVar(varmap, index, 1);
|
|
}
|
|
else if (expr.type == Exprent.EXPRENT_INVOCATION ||
|
|
(expr.type == Exprent.EXPRENT_ASSIGNMENT && ((AssignmentExprent)expr).getLeft().type == Exprent.EXPRENT_FIELD) ||
|
|
(expr.type == Exprent.EXPRENT_NEW && ((NewExprent)expr).getNewType().type == CodeConstants.TYPE_OBJECT) ||
|
|
expr.type == Exprent.EXPRENT_FUNCTION) {
|
|
|
|
boolean ismmpp = true;
|
|
|
|
if (expr.type == Exprent.EXPRENT_FUNCTION) {
|
|
|
|
ismmpp = false;
|
|
|
|
FunctionExprent fexpr = (FunctionExprent)expr;
|
|
if (fexpr.getFuncType() >= FunctionExprent.FUNCTION_IMM && fexpr.getFuncType() <= FunctionExprent.FUNCTION_PPI) {
|
|
if (fexpr.getLstOperands().get(0).type == Exprent.EXPRENT_FIELD) {
|
|
ismmpp = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (ismmpp) {
|
|
varmap.removeAllFields();
|
|
}
|
|
}
|
|
|
|
|
|
if (varassign != null) {
|
|
|
|
Integer varindex = varassign.getIndex();
|
|
|
|
if (varassign.getVersion() == 0) {
|
|
// get next version
|
|
Integer nextver = getNextFreeVersion(varindex, stat);
|
|
|
|
// set version
|
|
varassign.setVersion(nextver);
|
|
|
|
// ssu graph
|
|
ssuversions.createNode(new VarVersionPaar(varindex, nextver));
|
|
|
|
setCurrentVar(varmap, varindex, nextver);
|
|
}
|
|
else {
|
|
if (calcLiveVars) {
|
|
varMapToGraph(new VarVersionPaar(varindex.intValue(), varassign.getVersion()), varmap);
|
|
}
|
|
setCurrentVar(varmap, varindex, varassign.getVersion());
|
|
}
|
|
}
|
|
else if (expr.type == Exprent.EXPRENT_FUNCTION) { // MM or PP function
|
|
FunctionExprent func = (FunctionExprent)expr;
|
|
|
|
switch (func.getFuncType()) {
|
|
case FunctionExprent.FUNCTION_IMM:
|
|
case FunctionExprent.FUNCTION_MMI:
|
|
case FunctionExprent.FUNCTION_IPP:
|
|
case FunctionExprent.FUNCTION_PPI:
|
|
|
|
if (func.getLstOperands().get(0).type == Exprent.EXPRENT_VAR) {
|
|
VarExprent var = (VarExprent)func.getLstOperands().get(0);
|
|
Integer varindex = var.getIndex();
|
|
VarVersionPaar varpaar = new VarVersionPaar(varindex.intValue(), var.getVersion());
|
|
|
|
// ssu graph
|
|
VarVersionPaar phantomver = phantomppnodes.get(varpaar);
|
|
if (phantomver == null) {
|
|
// get next version
|
|
Integer nextver = getNextFreeVersion(varindex, null);
|
|
phantomver = new VarVersionPaar(varindex, nextver);
|
|
//ssuversions.createOrGetNode(phantomver);
|
|
ssuversions.createNode(phantomver);
|
|
|
|
VarVersionNode vernode = ssuversions.nodes.getWithKey(varpaar);
|
|
|
|
FastSparseSet<Integer> vers = factory.spawnEmptySet();
|
|
if (vernode.preds.size() == 1) {
|
|
vers.add(vernode.preds.iterator().next().source.version);
|
|
}
|
|
else {
|
|
for (VarVersionEdge edge : vernode.preds) {
|
|
vers.add(edge.source.preds.iterator().next().source.version);
|
|
}
|
|
}
|
|
vers.add(nextver);
|
|
createOrUpdatePhiNode(varpaar, vers, stat);
|
|
phantomppnodes.put(varpaar, phantomver);
|
|
}
|
|
if (calcLiveVars) {
|
|
varMapToGraph(varpaar, varmap);
|
|
}
|
|
setCurrentVar(varmap, varindex.intValue(), var.getVersion());
|
|
}
|
|
}
|
|
}
|
|
else if (expr.type == Exprent.EXPRENT_VAR) {
|
|
|
|
VarExprent vardest = (VarExprent)expr;
|
|
|
|
Integer varindex = vardest.getIndex();
|
|
Integer current_vers = vardest.getVersion();
|
|
|
|
FastSparseSet<Integer> vers = varmap.get(varindex);
|
|
|
|
int cardinality = vers.getCardinality();
|
|
if (cardinality == 1) { // size == 1
|
|
if (current_vers.intValue() != 0) {
|
|
if (calcLiveVars) {
|
|
varMapToGraph(new VarVersionPaar(varindex, current_vers), varmap);
|
|
}
|
|
setCurrentVar(varmap, varindex, current_vers);
|
|
}
|
|
else {
|
|
// split last version
|
|
Integer usever = getNextFreeVersion(varindex, stat);
|
|
|
|
// set version
|
|
vardest.setVersion(usever);
|
|
setCurrentVar(varmap, varindex, usever);
|
|
|
|
// ssu graph
|
|
Integer lastver = vers.iterator().next();
|
|
VarVersionNode prenode = ssuversions.nodes.getWithKey(new VarVersionPaar(varindex, lastver));
|
|
VarVersionNode usenode = ssuversions.createNode(new VarVersionPaar(varindex, usever));
|
|
VarVersionEdge edge = new VarVersionEdge(VarVersionEdge.EDGE_GENERAL, prenode, usenode);
|
|
prenode.addSuccessor(edge);
|
|
usenode.addPredecessor(edge);
|
|
}
|
|
}
|
|
else if (cardinality == 2) { // size > 1
|
|
|
|
if (current_vers.intValue() != 0) {
|
|
if (calcLiveVars) {
|
|
varMapToGraph(new VarVersionPaar(varindex, current_vers), varmap);
|
|
}
|
|
setCurrentVar(varmap, varindex, current_vers);
|
|
}
|
|
else {
|
|
// split version
|
|
Integer usever = getNextFreeVersion(varindex, stat);
|
|
// set version
|
|
vardest.setVersion(usever);
|
|
|
|
// ssu node
|
|
ssuversions.createNode(new VarVersionPaar(varindex, usever));
|
|
|
|
setCurrentVar(varmap, varindex, usever);
|
|
|
|
current_vers = usever;
|
|
}
|
|
|
|
createOrUpdatePhiNode(new VarVersionPaar(varindex, current_vers), vers, stat);
|
|
} // vers.size() == 0 means uninitialized variable, which is impossible
|
|
}
|
|
}
|
|
|
|
private void createOrUpdatePhiNode(VarVersionPaar phivar, FastSparseSet<Integer> vers, Statement stat) {
|
|
|
|
FastSparseSet<Integer> versCopy = vers.getCopy();
|
|
HashSet<Integer> phiVers = new HashSet<Integer>();
|
|
|
|
// take into account the corresponding mm/pp node if existing
|
|
int ppvers = phantomppnodes.containsKey(phivar) ? phantomppnodes.get(phivar).version : -1;
|
|
|
|
// ssu graph
|
|
VarVersionNode phinode = ssuversions.nodes.getWithKey(phivar);
|
|
List<VarVersionEdge> lstPreds = new ArrayList<VarVersionEdge>(phinode.preds);
|
|
if (lstPreds.size() == 1) {
|
|
// not yet a phi node
|
|
VarVersionEdge edge = lstPreds.get(0);
|
|
edge.source.removeSuccessor(edge);
|
|
phinode.removePredecessor(edge);
|
|
}
|
|
else {
|
|
for (VarVersionEdge edge : lstPreds) {
|
|
int verssrc = edge.source.preds.iterator().next().source.version;
|
|
if (!vers.contains(verssrc) && verssrc != ppvers) {
|
|
edge.source.removeSuccessor(edge);
|
|
phinode.removePredecessor(edge);
|
|
}
|
|
else {
|
|
versCopy.remove(verssrc);
|
|
phiVers.add(verssrc);
|
|
}
|
|
}
|
|
}
|
|
|
|
List<VarVersionNode> colnodes = new ArrayList<VarVersionNode>();
|
|
List<VarVersionPaar> colpaars = new ArrayList<VarVersionPaar>();
|
|
|
|
for (Integer ver : versCopy) {
|
|
|
|
VarVersionNode prenode = ssuversions.nodes.getWithKey(new VarVersionPaar(phivar.var, ver.intValue()));
|
|
|
|
Integer tempver = getNextFreeVersion(phivar.var, stat);
|
|
|
|
VarVersionNode tempnode = new VarVersionNode(phivar.var, tempver.intValue());
|
|
|
|
colnodes.add(tempnode);
|
|
colpaars.add(new VarVersionPaar(phivar.var, tempver.intValue()));
|
|
|
|
VarVersionEdge edge = new VarVersionEdge(VarVersionEdge.EDGE_GENERAL, prenode, tempnode);
|
|
|
|
prenode.addSuccessor(edge);
|
|
tempnode.addPredecessor(edge);
|
|
|
|
|
|
edge = new VarVersionEdge(VarVersionEdge.EDGE_GENERAL, tempnode, phinode);
|
|
tempnode.addSuccessor(edge);
|
|
phinode.addPredecessor(edge);
|
|
|
|
phiVers.add(tempver);
|
|
}
|
|
|
|
ssuversions.addNodes(colnodes, colpaars);
|
|
|
|
// update phi node
|
|
phi.put(phivar, phiVers);
|
|
}
|
|
|
|
private void varMapToGraph(VarVersionPaar varpaar, SFormsFastMapDirect varmap) {
|
|
|
|
VBStyleCollection<VarVersionNode, VarVersionPaar> nodes = ssuversions.nodes;
|
|
|
|
VarVersionNode node = nodes.getWithKey(varpaar);
|
|
|
|
node.live = new SFormsFastMapDirect(varmap);
|
|
}
|
|
|
|
private Integer getNextFreeVersion(Integer var, Statement stat) {
|
|
|
|
Integer nextver = lastversion.get(var);
|
|
|
|
if (nextver == null) {
|
|
nextver = new Integer(1);
|
|
}
|
|
else {
|
|
nextver = new Integer(nextver.intValue() + 1);
|
|
}
|
|
lastversion.put(var, nextver);
|
|
|
|
// save the first protected range, containing current statement
|
|
if (stat != null) { // null iff phantom version
|
|
Integer firstRangeId = getFirstProtectedRange(stat);
|
|
if (firstRangeId != null) {
|
|
mapVersionFirstRange.put(new VarVersionPaar(var, nextver), firstRangeId);
|
|
}
|
|
}
|
|
|
|
return nextver;
|
|
}
|
|
|
|
private void mergeInVarMaps(DirectNode node, DirectGraph dgraph) {
|
|
|
|
|
|
SFormsFastMapDirect mapNew = new SFormsFastMapDirect();
|
|
|
|
for (DirectNode pred : node.preds) {
|
|
SFormsFastMapDirect mapOut = getFilteredOutMap(node.id, pred.id, dgraph, node.id);
|
|
if (mapNew.isEmpty()) {
|
|
mapNew = mapOut.getCopy();
|
|
}
|
|
else {
|
|
mergeMaps(mapNew, mapOut);
|
|
}
|
|
}
|
|
|
|
if (extraVarVersions.containsKey(node.id)) {
|
|
SFormsFastMapDirect mapExtra = extraVarVersions.get(node.id);
|
|
if (mapNew.isEmpty()) {
|
|
mapNew = mapExtra.getCopy();
|
|
}
|
|
else {
|
|
mergeMaps(mapNew, mapExtra);
|
|
}
|
|
}
|
|
|
|
inVarVersions.put(node.id, mapNew);
|
|
}
|
|
|
|
private SFormsFastMapDirect getFilteredOutMap(String nodeid, String predid, DirectGraph dgraph, String destid) {
|
|
|
|
SFormsFastMapDirect mapNew = new SFormsFastMapDirect();
|
|
|
|
boolean isFinallyExit = dgraph.mapShortRangeFinallyPaths.containsKey(predid);
|
|
|
|
if (nodeid.equals(dgraph.mapNegIfBranch.get(predid))) {
|
|
if (outNegVarVersions.containsKey(predid)) {
|
|
mapNew = outNegVarVersions.get(predid).getCopy();
|
|
}
|
|
}
|
|
else if (outVarVersions.containsKey(predid)) {
|
|
mapNew = outVarVersions.get(predid).getCopy();
|
|
}
|
|
|
|
if (isFinallyExit) {
|
|
|
|
SFormsFastMapDirect mapNewTemp = mapNew.getCopy();
|
|
|
|
SFormsFastMapDirect mapTrueSource = new SFormsFastMapDirect();
|
|
|
|
String exceptionDest = dgraph.mapFinallyMonitorExceptionPathExits.get(predid);
|
|
boolean isExceptionMonitorExit = (exceptionDest != null && !nodeid.equals(exceptionDest));
|
|
|
|
HashSet<String> setLongPathWrapper = new HashSet<String>();
|
|
for (List<FinallyPathWrapper> lstwrapper : dgraph.mapLongRangeFinallyPaths.values()) {
|
|
for (FinallyPathWrapper finwraplong : lstwrapper) {
|
|
setLongPathWrapper.add(finwraplong.destination + "##" + finwraplong.source);
|
|
}
|
|
}
|
|
|
|
for (FinallyPathWrapper finwrap : dgraph.mapShortRangeFinallyPaths.get(predid)) {
|
|
SFormsFastMapDirect map;
|
|
|
|
boolean recFinally = dgraph.mapShortRangeFinallyPaths.containsKey(finwrap.source);
|
|
|
|
if (recFinally) {
|
|
// recursion
|
|
map = getFilteredOutMap(finwrap.entry, finwrap.source, dgraph, destid);
|
|
}
|
|
else {
|
|
if (finwrap.entry.equals(dgraph.mapNegIfBranch.get(finwrap.source))) {
|
|
map = outNegVarVersions.get(finwrap.source);
|
|
}
|
|
else {
|
|
map = outVarVersions.get(finwrap.source);
|
|
}
|
|
}
|
|
|
|
// false path?
|
|
boolean isFalsePath = true;
|
|
|
|
if (recFinally) {
|
|
isFalsePath = !finwrap.destination.equals(nodeid);
|
|
}
|
|
else {
|
|
isFalsePath = !setLongPathWrapper.contains(destid + "##" + finwrap.source);
|
|
}
|
|
|
|
if (isFalsePath) {
|
|
mapNewTemp.complement(map);
|
|
}
|
|
else {
|
|
if (mapTrueSource.isEmpty()) {
|
|
if (map != null) {
|
|
mapTrueSource = map.getCopy();
|
|
}
|
|
}
|
|
else {
|
|
mergeMaps(mapTrueSource, map);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (isExceptionMonitorExit) {
|
|
|
|
mapNew = mapTrueSource;
|
|
}
|
|
else {
|
|
|
|
mapNewTemp.union(mapTrueSource);
|
|
mapNew.intersection(mapNewTemp);
|
|
|
|
if (!mapTrueSource.isEmpty() && !mapNew.isEmpty()) { // FIXME: what for??
|
|
|
|
// replace phi versions with corresponding phantom ones
|
|
HashMap<VarVersionPaar, VarVersionPaar> mapPhantom = phantomexitnodes.get(predid);
|
|
if (mapPhantom == null) {
|
|
mapPhantom = new HashMap<VarVersionPaar, VarVersionPaar>();
|
|
}
|
|
|
|
SFormsFastMapDirect mapExitVar = mapNew.getCopy();
|
|
mapExitVar.complement(mapTrueSource);
|
|
|
|
for (Entry<Integer, FastSparseSet<Integer>> ent : mapExitVar.entryList()) {
|
|
for (Integer version : ent.getValue()) {
|
|
|
|
Integer varindex = ent.getKey();
|
|
VarVersionPaar exitvar = new VarVersionPaar(varindex, version);
|
|
FastSparseSet<Integer> newSet = mapNew.get(varindex);
|
|
|
|
// remove the actual exit version
|
|
newSet.remove(version);
|
|
|
|
// get or create phantom version
|
|
VarVersionPaar phantomvar = mapPhantom.get(exitvar);
|
|
if (phantomvar == null) {
|
|
Integer newversion = getNextFreeVersion(exitvar.var, null);
|
|
phantomvar = new VarVersionPaar(exitvar.var, newversion.intValue());
|
|
|
|
VarVersionNode exitnode = ssuversions.nodes.getWithKey(exitvar);
|
|
VarVersionNode phantomnode = ssuversions.createNode(phantomvar);
|
|
phantomnode.flags |= VarVersionNode.FLAG_PHANTOM_FINEXIT;
|
|
|
|
VarVersionEdge edge = new VarVersionEdge(VarVersionEdge.EDGE_PHANTOM, exitnode, phantomnode);
|
|
exitnode.addSuccessor(edge);
|
|
phantomnode.addPredecessor(edge);
|
|
|
|
mapPhantom.put(exitvar, phantomvar);
|
|
}
|
|
|
|
// add phantom version
|
|
newSet.add(phantomvar.version);
|
|
}
|
|
}
|
|
|
|
if (!mapPhantom.isEmpty()) {
|
|
phantomexitnodes.put(predid, mapPhantom);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return mapNew;
|
|
}
|
|
|
|
private static SFormsFastMapDirect mergeMaps(SFormsFastMapDirect mapTo, SFormsFastMapDirect map2) {
|
|
|
|
if (map2 != null && !map2.isEmpty()) {
|
|
mapTo.union(map2);
|
|
}
|
|
|
|
return mapTo;
|
|
}
|
|
|
|
private static boolean mapsEqual(SFormsFastMapDirect map1, SFormsFastMapDirect map2) {
|
|
|
|
if (map1 == null) {
|
|
return map2 == null;
|
|
}
|
|
else if (map2 == null) {
|
|
return false;
|
|
}
|
|
|
|
if (map1.size() != map2.size()) {
|
|
return false;
|
|
}
|
|
|
|
for (Entry<Integer, FastSparseSet<Integer>> ent2 : map2.entryList()) {
|
|
if (!InterpreterUtil.equalObjects(map1.get(ent2.getKey()), ent2.getValue())) {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
private void setCurrentVar(SFormsFastMapDirect varmap, Integer var, Integer vers) {
|
|
FastSparseSet<Integer> set = factory.spawnEmptySet();
|
|
set.add(vers);
|
|
varmap.put(var, set);
|
|
}
|
|
|
|
private void setCatchMaps(Statement stat, DirectGraph dgraph, FlattenStatementsHelper flatthelper) {
|
|
|
|
SFormsFastMapDirect map;
|
|
|
|
switch (stat.type) {
|
|
case Statement.TYPE_CATCHALL:
|
|
case Statement.TYPE_TRYCATCH:
|
|
|
|
List<VarExprent> lstVars;
|
|
if (stat.type == Statement.TYPE_CATCHALL) {
|
|
lstVars = ((CatchAllStatement)stat).getVars();
|
|
}
|
|
else {
|
|
lstVars = ((CatchStatement)stat).getVars();
|
|
}
|
|
|
|
for (int i = 1; i < stat.getStats().size(); i++) {
|
|
int varindex = lstVars.get(i - 1).getIndex();
|
|
int version = getNextFreeVersion(varindex, stat); // == 1
|
|
|
|
map = new SFormsFastMapDirect();
|
|
setCurrentVar(map, varindex, version);
|
|
|
|
extraVarVersions.put(dgraph.nodes.getWithKey(flatthelper.getMapDestinationNodes().get(stat.getStats().get(i).id)[0]).id, map);
|
|
//ssuversions.createOrGetNode(new VarVersionPaar(varindex, version));
|
|
ssuversions.createNode(new VarVersionPaar(varindex, version));
|
|
}
|
|
}
|
|
|
|
for (Statement st : stat.getStats()) {
|
|
setCatchMaps(st, dgraph, flatthelper);
|
|
}
|
|
}
|
|
|
|
private SFormsFastMapDirect createFirstMap(StructMethod mt, RootStatement root) {
|
|
boolean thisvar = !mt.hasModifier(CodeConstants.ACC_STATIC);
|
|
|
|
MethodDescriptor md = MethodDescriptor.parseDescriptor(mt.getDescriptor());
|
|
|
|
int paramcount = md.params.length + (thisvar ? 1 : 0);
|
|
|
|
int varindex = 0;
|
|
SFormsFastMapDirect map = new SFormsFastMapDirect();
|
|
for (int i = 0; i < paramcount; i++) {
|
|
int version = getNextFreeVersion(varindex, root); // == 1
|
|
|
|
FastSparseSet<Integer> set = factory.spawnEmptySet();
|
|
set.add(version);
|
|
map.put(varindex, set);
|
|
ssuversions.createNode(new VarVersionPaar(varindex, version));
|
|
|
|
if (thisvar) {
|
|
if (i == 0) {
|
|
varindex++;
|
|
}
|
|
else {
|
|
varindex += md.params[i - 1].stackSize;
|
|
}
|
|
}
|
|
else {
|
|
varindex += md.params[i].stackSize;
|
|
}
|
|
}
|
|
|
|
return map;
|
|
}
|
|
|
|
private static Integer getFirstProtectedRange(Statement stat) {
|
|
|
|
while (true) {
|
|
Statement parent = stat.getParent();
|
|
|
|
if (parent == null) {
|
|
break;
|
|
}
|
|
|
|
if (parent.type == Statement.TYPE_CATCHALL ||
|
|
parent.type == Statement.TYPE_TRYCATCH) {
|
|
if (parent.getFirst() == stat) {
|
|
return parent.id;
|
|
}
|
|
}
|
|
else if (parent.type == Statement.TYPE_SYNCRONIZED) {
|
|
if (((SynchronizedStatement)parent).getBody() == stat) {
|
|
return parent.id;
|
|
}
|
|
}
|
|
|
|
stat = parent;
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
public HashMap<VarVersionPaar, HashSet<Integer>> getPhi() {
|
|
return phi;
|
|
}
|
|
|
|
public VarVersionsGraph getSsuversions() {
|
|
return ssuversions;
|
|
}
|
|
|
|
public SFormsFastMapDirect getLiveVarVersionsMap(VarVersionPaar varpaar) {
|
|
|
|
|
|
VarVersionNode node = ssuversions.nodes.getWithKey(varpaar);
|
|
if (node != null) {
|
|
return node.live;
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
public HashMap<VarVersionPaar, Integer> getMapVersionFirstRange() {
|
|
return mapVersionFirstRange;
|
|
}
|
|
|
|
public HashMap<Integer, Integer> getMapFieldVars() {
|
|
return mapFieldVars;
|
|
}
|
|
}
|