| /* |
| * 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; |
| |
| import org.jetbrains.java.decompiler.code.CodeConstants; |
| import org.jetbrains.java.decompiler.modules.decompiler.exps.*; |
| import org.jetbrains.java.decompiler.modules.decompiler.sforms.*; |
| import org.jetbrains.java.decompiler.modules.decompiler.stats.DoStatement; |
| import org.jetbrains.java.decompiler.modules.decompiler.stats.RootStatement; |
| import org.jetbrains.java.decompiler.modules.decompiler.stats.Statement; |
| 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.StructClass; |
| import org.jetbrains.java.decompiler.struct.StructMethod; |
| import org.jetbrains.java.decompiler.util.FastSparseSetFactory.FastSparseSet; |
| import org.jetbrains.java.decompiler.util.InterpreterUtil; |
| import org.jetbrains.java.decompiler.util.SFormsFastMapDirect; |
| |
| import java.util.*; |
| import java.util.Map.Entry; |
| |
| |
| public class StackVarsProcessor { |
| |
| public void simplifyStackVars(RootStatement root, StructMethod mt, StructClass cl) { |
| |
| HashSet<Integer> setReorderedIfs = new HashSet<Integer>(); |
| |
| SSAUConstructorSparseEx ssau = null; |
| |
| while (true) { |
| |
| boolean found = false; |
| |
| // System.out.println("--------------- \r\n"+root.toJava()); |
| |
| SSAConstructorSparseEx ssa = new SSAConstructorSparseEx(); |
| ssa.splitVariables(root, mt); |
| |
| // System.out.println("--------------- \r\n"+root.toJava()); |
| |
| |
| SimplifyExprentsHelper sehelper = new SimplifyExprentsHelper(ssau == null); |
| while (sehelper.simplifyStackVarsStatement(root, setReorderedIfs, ssa, cl)) { |
| // System.out.println("--------------- \r\n"+root.toJava()); |
| found = true; |
| } |
| |
| |
| // System.out.println("=============== \r\n"+root.toJava()); |
| |
| setVersionsToNull(root); |
| |
| SequenceHelper.condenseSequences(root); |
| |
| ssau = new SSAUConstructorSparseEx(); |
| ssau.splitVariables(root, mt); |
| |
| // try { |
| // DotExporter.toDotFile(ssau.getSsuversions(), new File("c:\\Temp\\gr12_my.dot")); |
| // } catch(Exception ex) { |
| // ex.printStackTrace(); |
| // } |
| |
| // System.out.println("++++++++++++++++ \r\n"+root.toJava()); |
| |
| |
| if (iterateStatements(root, ssau)) { |
| found = true; |
| } |
| |
| // System.out.println("***************** \r\n"+root.toJava()); |
| |
| setVersionsToNull(root); |
| |
| if (!found) { |
| break; |
| } |
| } |
| |
| // remove unused assignments |
| ssau = new SSAUConstructorSparseEx(); |
| ssau.splitVariables(root, mt); |
| |
| // try { |
| // DotExporter.toDotFile(ssau.getSsuversions(), new File("c:\\Temp\\gr12_my.dot")); |
| // } catch(Exception ex) { |
| // ex.printStackTrace(); |
| // } |
| |
| iterateStatements(root, ssau); |
| |
| // System.out.println("~~~~~~~~~~~~~~~~~~~~~~ \r\n"+root.toJava()); |
| |
| setVersionsToNull(root); |
| } |
| |
| private static void setVersionsToNull(Statement stat) { |
| |
| if (stat.getExprents() == null) { |
| for (Object obj : stat.getSequentialObjects()) { |
| if (obj instanceof Statement) { |
| setVersionsToNull((Statement)obj); |
| } |
| else if (obj instanceof Exprent) { |
| setExprentVersionsToNull((Exprent)obj); |
| } |
| } |
| } |
| else { |
| for (Exprent exprent : stat.getExprents()) { |
| setExprentVersionsToNull(exprent); |
| } |
| } |
| } |
| |
| private static void setExprentVersionsToNull(Exprent exprent) { |
| |
| List<Exprent> lst = exprent.getAllExprents(true); |
| lst.add(exprent); |
| |
| for (Exprent expr : lst) { |
| if (expr.type == Exprent.EXPRENT_VAR) { |
| ((VarExprent)expr).setVersion(0); |
| } |
| } |
| } |
| |
| |
| private boolean iterateStatements(RootStatement root, SSAUConstructorSparseEx ssa) { |
| |
| FlattenStatementsHelper flatthelper = new FlattenStatementsHelper(); |
| DirectGraph dgraph = flatthelper.buildDirectGraph(root); |
| |
| boolean res = false; |
| |
| HashSet<DirectNode> setVisited = new HashSet<DirectNode>(); |
| LinkedList<DirectNode> stack = new LinkedList<DirectNode>(); |
| LinkedList<HashMap<VarVersionPaar, Exprent>> stackMaps = new LinkedList<HashMap<VarVersionPaar, Exprent>>(); |
| |
| stack.add(dgraph.first); |
| stackMaps.add(new HashMap<VarVersionPaar, Exprent>()); |
| |
| while (!stack.isEmpty()) { |
| |
| DirectNode nd = stack.removeFirst(); |
| HashMap<VarVersionPaar, Exprent> mapVarValues = stackMaps.removeFirst(); |
| |
| if (setVisited.contains(nd)) { |
| continue; |
| } |
| setVisited.add(nd); |
| |
| List<List<Exprent>> lstLists = new ArrayList<List<Exprent>>(); |
| |
| if (!nd.exprents.isEmpty()) { |
| lstLists.add(nd.exprents); |
| } |
| |
| if (nd.succs.size() == 1) { |
| DirectNode ndsucc = nd.succs.get(0); |
| if (ndsucc.type == DirectNode.NODE_TAIL && !ndsucc.exprents.isEmpty()) { |
| lstLists.add(nd.succs.get(0).exprents); |
| nd = ndsucc; |
| } |
| } |
| |
| for (int i = 0; i < lstLists.size(); i++) { |
| List<Exprent> lst = lstLists.get(i); |
| |
| int index = 0; |
| while (index < lst.size()) { |
| Exprent next = null; |
| if (index == lst.size() - 1) { |
| if (i < lstLists.size() - 1) { |
| next = lstLists.get(i + 1).get(0); |
| } |
| } |
| else { |
| next = lst.get(index + 1); |
| } |
| |
| int[] ret = iterateExprent(lst, index, next, mapVarValues, ssa); |
| |
| //System.out.println("***************** \r\n"+root.toJava()); |
| |
| if (ret[0] >= 0) { |
| index = ret[0]; |
| } |
| else { |
| index++; |
| } |
| res |= (ret[1] == 1); |
| } |
| } |
| |
| for (DirectNode ndx : nd.succs) { |
| stack.add(ndx); |
| stackMaps.add(new HashMap<VarVersionPaar, Exprent>(mapVarValues)); |
| } |
| |
| // make sure the 3 special exprent lists in a loop (init, condition, increment) are not empty |
| // change loop type if necessary |
| if (nd.exprents.isEmpty() && |
| (nd.type == DirectNode.NODE_INIT || nd.type == DirectNode.NODE_CONDITION || nd.type == DirectNode.NODE_INCREMENT)) { |
| nd.exprents.add(null); |
| |
| if (nd.statement.type == Statement.TYPE_DO) { |
| DoStatement loop = (DoStatement)nd.statement; |
| |
| if (loop.getLooptype() == DoStatement.LOOP_FOR && |
| loop.getInitExprent() == null && |
| loop.getIncExprent() == null) { // "downgrade" loop to 'while' |
| loop.setLooptype(DoStatement.LOOP_WHILE); |
| } |
| } |
| } |
| } |
| |
| return res; |
| } |
| |
| |
| private static Exprent isReplaceableVar(Exprent exprent, HashMap<VarVersionPaar, Exprent> mapVarValues, SSAUConstructorSparseEx ssau) { |
| |
| Exprent dest = null; |
| |
| if (exprent.type == Exprent.EXPRENT_VAR) { |
| VarExprent var = (VarExprent)exprent; |
| dest = mapVarValues.get(new VarVersionPaar(var)); |
| } |
| |
| return dest; |
| } |
| |
| private static void replaceSingleVar(Exprent parent, VarExprent var, Exprent dest, SSAUConstructorSparseEx ssau) { |
| |
| parent.replaceExprent(var, dest); |
| |
| // live sets |
| SFormsFastMapDirect livemap = ssau.getLiveVarVersionsMap(new VarVersionPaar(var)); |
| HashSet<VarVersionPaar> setVars = getAllVersions(dest); |
| |
| for (VarVersionPaar varpaar : setVars) { |
| VarVersionNode node = ssau.getSsuversions().nodes.getWithKey(varpaar); |
| |
| for (Iterator<Entry<Integer, FastSparseSet<Integer>>> itent = node.live.entryList().iterator(); itent.hasNext(); ) { |
| Entry<Integer, FastSparseSet<Integer>> ent = itent.next(); |
| |
| Integer key = ent.getKey(); |
| |
| if (!livemap.containsKey(key)) { |
| itent.remove(); |
| } |
| else { |
| FastSparseSet<Integer> set = ent.getValue(); |
| |
| set.complement(livemap.get(key)); |
| if (set.isEmpty()) { |
| itent.remove(); |
| } |
| } |
| } |
| } |
| } |
| |
| private int[] iterateExprent(List<Exprent> lstExprents, int index, Exprent next, HashMap<VarVersionPaar, |
| Exprent> mapVarValues, SSAUConstructorSparseEx ssau) { |
| |
| Exprent exprent = lstExprents.get(index); |
| |
| int changed = 0; |
| |
| for (Exprent expr : exprent.getAllExprents()) { |
| while (true) { |
| Object[] arr = iterateChildExprent(expr, exprent, next, mapVarValues, ssau); |
| Exprent retexpr = (Exprent)arr[0]; |
| changed |= (Boolean)arr[1] ? 1 : 0; |
| |
| boolean isReplaceable = (Boolean)arr[2]; |
| if (retexpr != null) { |
| if (isReplaceable) { |
| replaceSingleVar(exprent, (VarExprent)expr, retexpr, ssau); |
| expr = retexpr; |
| } |
| else { |
| exprent.replaceExprent(expr, retexpr); |
| } |
| changed = 1; |
| } |
| |
| if (!isReplaceable) { |
| break; |
| } |
| } |
| } |
| |
| // no var on the highest level, so no replacing |
| |
| VarExprent left = null; |
| Exprent right = null; |
| |
| if (exprent.type == Exprent.EXPRENT_ASSIGNMENT) { |
| AssignmentExprent as = (AssignmentExprent)exprent; |
| if (as.getLeft().type == Exprent.EXPRENT_VAR) { |
| left = (VarExprent)as.getLeft(); |
| right = as.getRight(); |
| } |
| } |
| |
| if (left == null) { |
| return new int[]{-1, changed}; |
| } |
| |
| VarVersionPaar leftpaar = new VarVersionPaar(left); |
| |
| List<VarVersionNode> usedVers = new ArrayList<VarVersionNode>(); |
| boolean notdom = getUsedVersions(ssau, leftpaar, usedVers); |
| |
| if (!notdom && usedVers.isEmpty()) { |
| if (left.isStack() && (right.type == Exprent.EXPRENT_INVOCATION || |
| right.type == Exprent.EXPRENT_ASSIGNMENT || right.type == Exprent.EXPRENT_NEW)) { |
| if (right.type == Exprent.EXPRENT_NEW) { |
| // new Object(); permitted |
| NewExprent nexpr = (NewExprent)right; |
| if (nexpr.isAnonymous() || nexpr.getNewtype().arraydim > 0 |
| || nexpr.getNewtype().type != CodeConstants.TYPE_OBJECT) { |
| return new int[]{-1, changed}; |
| } |
| } |
| |
| lstExprents.set(index, right); |
| return new int[]{index + 1, 1}; |
| } |
| else if (right.type == Exprent.EXPRENT_VAR) { |
| lstExprents.remove(index); |
| return new int[]{index, 1}; |
| } |
| else { |
| return new int[]{-1, changed}; |
| } |
| } |
| |
| int useflags = right.getExprentUse(); |
| |
| // stack variables only |
| if (!left.isStack() && |
| (right.type != Exprent.EXPRENT_VAR || ((VarExprent)right).isStack())) { // special case catch(... ex) |
| return new int[]{-1, changed}; |
| } |
| |
| if ((useflags & Exprent.MULTIPLE_USES) == 0 && (notdom || usedVers.size() > 1)) { |
| return new int[]{-1, changed}; |
| } |
| |
| HashMap<Integer, HashSet<VarVersionPaar>> mapVars = getAllVarVersions(leftpaar, right, ssau); |
| |
| boolean isSelfReference = mapVars.containsKey(leftpaar.var); |
| if (isSelfReference && notdom) { |
| return new int[]{-1, changed}; |
| } |
| |
| HashSet<VarVersionPaar> setNextVars = next == null ? null : getAllVersions(next); |
| |
| // FIXME: fix the entire method! |
| if (right.type != Exprent.EXPRENT_CONST && |
| right.type != Exprent.EXPRENT_VAR && |
| setNextVars != null && |
| mapVars.containsKey(leftpaar.var)) { |
| for (VarVersionNode usedvar : usedVers) { |
| if (!setNextVars.contains(new VarVersionPaar(usedvar.var, usedvar.version))) { |
| return new int[]{-1, changed}; |
| } |
| } |
| } |
| |
| mapVars.remove(leftpaar.var); |
| |
| boolean vernotreplaced = false; |
| boolean verreplaced = false; |
| |
| |
| HashSet<VarVersionPaar> setTempUsedVers = new HashSet<VarVersionPaar>(); |
| |
| for (VarVersionNode usedvar : usedVers) { |
| VarVersionPaar usedver = new VarVersionPaar(usedvar.var, usedvar.version); |
| if (isVersionToBeReplaced(usedver, mapVars, ssau, leftpaar) && |
| (right.type == Exprent.EXPRENT_CONST || right.type == Exprent.EXPRENT_VAR || right.type == Exprent.EXPRENT_FIELD |
| || setNextVars == null || setNextVars.contains(usedver))) { |
| |
| setTempUsedVers.add(usedver); |
| verreplaced = true; |
| } |
| else { |
| vernotreplaced = true; |
| } |
| } |
| |
| if (isSelfReference && vernotreplaced) { |
| return new int[]{-1, changed}; |
| } |
| else { |
| for (VarVersionPaar usedver : setTempUsedVers) { |
| Exprent copy = right.copy(); |
| if (right.type == Exprent.EXPRENT_FIELD && ssau.getMapFieldVars().containsKey(right.id)) { |
| ssau.getMapFieldVars().put(copy.id, ssau.getMapFieldVars().get(right.id)); |
| } |
| |
| mapVarValues.put(usedver, copy); |
| } |
| } |
| |
| if (!notdom && !vernotreplaced) { |
| // remove assignment |
| lstExprents.remove(index); |
| return new int[]{index, 1}; |
| } |
| else if (verreplaced) { |
| return new int[]{index + 1, changed}; |
| } |
| else { |
| return new int[]{-1, changed}; |
| } |
| } |
| |
| private static HashSet<VarVersionPaar> getAllVersions(Exprent exprent) { |
| |
| HashSet<VarVersionPaar> res = new HashSet<VarVersionPaar>(); |
| |
| List<Exprent> listTemp = new ArrayList<Exprent>(exprent.getAllExprents(true)); |
| listTemp.add(exprent); |
| |
| for (Exprent expr : listTemp) { |
| if (expr.type == Exprent.EXPRENT_VAR) { |
| VarExprent var = (VarExprent)expr; |
| res.add(new VarVersionPaar(var)); |
| } |
| } |
| |
| return res; |
| } |
| |
| private static Object[] iterateChildExprent(Exprent exprent, |
| Exprent parent, |
| Exprent next, |
| HashMap<VarVersionPaar, Exprent> mapVarValues, |
| SSAUConstructorSparseEx ssau) { |
| |
| boolean changed = false; |
| |
| for (Exprent expr : exprent.getAllExprents()) { |
| while (true) { |
| Object[] arr = iterateChildExprent(expr, parent, next, mapVarValues, ssau); |
| Exprent retexpr = (Exprent)arr[0]; |
| changed |= (Boolean)arr[1]; |
| |
| boolean isReplaceable = (Boolean)arr[2]; |
| if (retexpr != null) { |
| if (isReplaceable) { |
| replaceSingleVar(exprent, (VarExprent)expr, retexpr, ssau); |
| expr = retexpr; |
| } |
| else { |
| exprent.replaceExprent(expr, retexpr); |
| } |
| changed = true; |
| } |
| |
| if (!isReplaceable) { |
| break; |
| } |
| } |
| } |
| |
| Exprent dest = isReplaceableVar(exprent, mapVarValues, ssau); |
| if (dest != null) { |
| return new Object[]{dest, true, true}; |
| } |
| |
| |
| VarExprent left = null; |
| Exprent right = null; |
| |
| if (exprent.type == Exprent.EXPRENT_ASSIGNMENT) { |
| AssignmentExprent as = (AssignmentExprent)exprent; |
| if (as.getLeft().type == Exprent.EXPRENT_VAR) { |
| left = (VarExprent)as.getLeft(); |
| right = as.getRight(); |
| } |
| } |
| |
| if (left == null) { |
| return new Object[]{null, changed, false}; |
| } |
| |
| boolean isHeadSynchronized = false; |
| if (next == null && parent.type == Exprent.EXPRENT_MONITOR) { |
| MonitorExprent monexpr = (MonitorExprent)parent; |
| if (monexpr.getMontype() == MonitorExprent.MONITOR_ENTER && exprent.equals(monexpr.getValue())) { |
| isHeadSynchronized = true; |
| } |
| } |
| |
| // stack variable or synchronized head exprent |
| if (!left.isStack() && !isHeadSynchronized) { |
| return new Object[]{null, changed, false}; |
| } |
| |
| VarVersionPaar leftpaar = new VarVersionPaar(left); |
| |
| List<VarVersionNode> usedVers = new ArrayList<VarVersionNode>(); |
| boolean notdom = getUsedVersions(ssau, leftpaar, usedVers); |
| |
| if (!notdom && usedVers.isEmpty()) { |
| return new Object[]{right, changed, false}; |
| } |
| |
| // stack variables only |
| if (!left.isStack()) { |
| return new Object[]{null, changed, false}; |
| } |
| |
| int useflags = right.getExprentUse(); |
| |
| if ((useflags & Exprent.BOTH_FLAGS) != Exprent.BOTH_FLAGS) { |
| return new Object[]{null, changed, false}; |
| } |
| |
| HashMap<Integer, HashSet<VarVersionPaar>> mapVars = getAllVarVersions(leftpaar, right, ssau); |
| |
| if (mapVars.containsKey(leftpaar.var) && notdom) { |
| return new Object[]{null, changed, false}; |
| } |
| |
| |
| mapVars.remove(leftpaar.var); |
| |
| HashSet<VarVersionPaar> setAllowedVars = getAllVersions(parent); |
| if (next != null) { |
| setAllowedVars.addAll(getAllVersions(next)); |
| } |
| |
| boolean vernotreplaced = false; |
| |
| HashSet<VarVersionPaar> setTempUsedVers = new HashSet<VarVersionPaar>(); |
| |
| for (VarVersionNode usedvar : usedVers) { |
| VarVersionPaar usedver = new VarVersionPaar(usedvar.var, usedvar.version); |
| if (isVersionToBeReplaced(usedver, mapVars, ssau, leftpaar) && |
| (right.type == Exprent.EXPRENT_VAR || setAllowedVars.contains(usedver))) { |
| |
| setTempUsedVers.add(usedver); |
| } |
| else { |
| vernotreplaced = true; |
| } |
| } |
| |
| if (!notdom && !vernotreplaced) { |
| |
| for (VarVersionPaar usedver : setTempUsedVers) { |
| Exprent copy = right.copy(); |
| if (right.type == Exprent.EXPRENT_FIELD && ssau.getMapFieldVars().containsKey(right.id)) { |
| ssau.getMapFieldVars().put(copy.id, ssau.getMapFieldVars().get(right.id)); |
| } |
| |
| mapVarValues.put(usedver, copy); |
| } |
| |
| // remove assignment |
| return new Object[]{right, changed, false}; |
| } |
| |
| return new Object[]{null, changed, false}; |
| } |
| |
| private static boolean getUsedVersions(SSAUConstructorSparseEx ssa, VarVersionPaar var, List<VarVersionNode> res) { |
| |
| VarVersionsGraph ssuversions = ssa.getSsuversions(); |
| VarVersionNode varnode = ssuversions.nodes.getWithKey(var); |
| |
| HashSet<VarVersionNode> setVisited = new HashSet<VarVersionNode>(); |
| |
| HashSet<VarVersionNode> setNotDoms = new HashSet<VarVersionNode>(); |
| |
| LinkedList<VarVersionNode> stack = new LinkedList<VarVersionNode>(); |
| stack.add(varnode); |
| |
| while (!stack.isEmpty()) { |
| |
| VarVersionNode nd = stack.remove(0); |
| setVisited.add(nd); |
| |
| if (nd != varnode && (nd.flags & VarVersionNode.FLAG_PHANTOM_FINEXIT) == 0) { |
| res.add(nd); |
| } |
| |
| for (VarVersionEdge edge : nd.succs) { |
| VarVersionNode succ = edge.dest; |
| |
| if (!setVisited.contains(edge.dest)) { |
| |
| boolean isDominated = true; |
| for (VarVersionEdge prededge : succ.preds) { |
| if (!setVisited.contains(prededge.source)) { |
| isDominated = false; |
| break; |
| } |
| } |
| |
| if (isDominated) { |
| stack.add(succ); |
| } |
| else { |
| setNotDoms.add(succ); |
| } |
| } |
| } |
| } |
| |
| setNotDoms.removeAll(setVisited); |
| |
| return !setNotDoms.isEmpty(); |
| } |
| |
| private static boolean isVersionToBeReplaced(VarVersionPaar usedvar, |
| HashMap<Integer, HashSet<VarVersionPaar>> mapVars, |
| SSAUConstructorSparseEx ssau, |
| VarVersionPaar leftpaar) { |
| |
| VarVersionsGraph ssuversions = ssau.getSsuversions(); |
| |
| SFormsFastMapDirect mapLiveVars = ssau.getLiveVarVersionsMap(usedvar); |
| if (mapLiveVars == null) { |
| // dummy version, predecessor of a phi node |
| return false; |
| } |
| |
| // compare protected ranges |
| if (!InterpreterUtil.equalObjects(ssau.getMapVersionFirstRange().get(leftpaar), |
| ssau.getMapVersionFirstRange().get(usedvar))) { |
| return false; |
| } |
| |
| for (Entry<Integer, HashSet<VarVersionPaar>> ent : mapVars.entrySet()) { |
| FastSparseSet<Integer> liveverset = mapLiveVars.get(ent.getKey()); |
| if (liveverset == null) { |
| return false; |
| } |
| |
| HashSet<VarVersionNode> domset = new HashSet<VarVersionNode>(); |
| for (VarVersionPaar verpaar : ent.getValue()) { |
| domset.add(ssuversions.nodes.getWithKey(verpaar)); |
| } |
| |
| boolean isdom = false; |
| |
| for (Integer livever : liveverset) { |
| VarVersionNode node = ssuversions.nodes.getWithKey(new VarVersionPaar(ent.getKey().intValue(), livever.intValue())); |
| |
| if (ssuversions.isDominatorSet(node, domset)) { |
| isdom = true; |
| break; |
| } |
| } |
| |
| if (!isdom) { |
| return false; |
| } |
| } |
| |
| return true; |
| } |
| |
| private static HashMap<Integer, HashSet<VarVersionPaar>> getAllVarVersions(VarVersionPaar leftvar, |
| Exprent exprent, |
| SSAUConstructorSparseEx ssau) { |
| |
| HashMap<Integer, HashSet<VarVersionPaar>> map = new HashMap<Integer, HashSet<VarVersionPaar>>(); |
| SFormsFastMapDirect mapLiveVars = ssau.getLiveVarVersionsMap(leftvar); |
| |
| List<Exprent> lst = exprent.getAllExprents(true); |
| lst.add(exprent); |
| |
| for (Exprent expr : lst) { |
| if (expr.type == Exprent.EXPRENT_VAR) { |
| int varindex = ((VarExprent)expr).getIndex(); |
| if (leftvar.var != varindex) { |
| if (mapLiveVars.containsKey(varindex)) { |
| HashSet<VarVersionPaar> verset = new HashSet<VarVersionPaar>(); |
| for (Integer vers : mapLiveVars.get(varindex)) { |
| verset.add(new VarVersionPaar(varindex, vers.intValue())); |
| } |
| map.put(varindex, verset); |
| } |
| else { |
| throw new RuntimeException("inkonsistent live map!"); |
| } |
| } |
| else { |
| map.put(varindex, null); |
| } |
| } |
| else if (expr.type == Exprent.EXPRENT_FIELD) { |
| if (ssau.getMapFieldVars().containsKey(expr.id)) { |
| int varindex = ssau.getMapFieldVars().get(expr.id); |
| if (mapLiveVars.containsKey(varindex)) { |
| HashSet<VarVersionPaar> verset = new HashSet<VarVersionPaar>(); |
| for (Integer vers : mapLiveVars.get(varindex)) { |
| verset.add(new VarVersionPaar(varindex, vers.intValue())); |
| } |
| map.put(varindex, verset); |
| } |
| } |
| } |
| } |
| |
| return map; |
| } |
| } |