mirror of
https://git.huckle.dev/Huckles-Minecraft-Archive/jpexs-decompiler.git
synced 2026-06-12 09:31:53 +00:00
improved local register usage detection / try..catch..finally
This commit is contained in:
@@ -1576,47 +1576,6 @@ public class AVM2Code implements Cloneable {
|
||||
}
|
||||
}
|
||||
}
|
||||
/*if ((ip + 8 < code.size())) { //return in finally clause
|
||||
if (ins.definition instanceof SetLocalTypeIns) {
|
||||
if (code.get(ip + 1).definition instanceof PushByteIns) {
|
||||
AVM2Instruction jmp = code.get(ip + 2);
|
||||
if (jmp.definition instanceof JumpIns) {
|
||||
if (jmp.operands[0] == 0) {
|
||||
if (code.get(ip + 3).definition instanceof LabelIns) {
|
||||
if (code.get(ip + 4).definition instanceof PopIns) {
|
||||
if (code.get(ip + 5).definition instanceof LabelIns) {
|
||||
AVM2Instruction gl = code.get(ip + 6);
|
||||
if (gl.definition instanceof GetLocalTypeIns) {
|
||||
if (((GetLocalTypeIns) gl.definition).getRegisterId(gl) == ((SetLocalTypeIns) ins.definition).getRegisterId(ins)) {
|
||||
AVM2Instruction ki = code.get(ip + 7);
|
||||
if (ki.definition instanceof KillIns) {
|
||||
if (ki.operands[0] == ((SetLocalTypeIns) ins.definition).getRegisterId(ins)) {
|
||||
if (code.get(ip + 8).definition instanceof ReturnValueIns) {
|
||||
ip = ip + 8;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}//*/
|
||||
|
||||
/*if ((ip + 2 < code.size()) && (ins.definition instanceof NewCatchIns)) { // Filling local register in catch clause
|
||||
if (code.get(ip + 1).definition instanceof DupIns) {
|
||||
if (code.get(ip + 2).definition instanceof SetLocalTypeIns) {
|
||||
ins.definition.translate(isStatic, classIndex, localRegs, stack, scopeStack, constants, ins, method_info, output, body, abc, localRegNames, fullyQualifiedNames);
|
||||
ip += 3;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}*/
|
||||
if ((ins.definition instanceof SetLocalTypeIns) && (ip + 1 <= end)) { // set_local_x,get_local_x.. no other local_x get
|
||||
|
||||
AVM2Instruction insAfter = code.get(ip + 1);
|
||||
|
||||
@@ -440,135 +440,126 @@ public class AVM2Graph extends Graph {
|
||||
}
|
||||
}
|
||||
|
||||
private void walkLocalRegsUsage(AVM2LocalData localData, Set<Integer> getLocalPos, GraphPart startPart, GraphPart part, Set<GraphPart> visited, int ip, int searchRegId) {
|
||||
if (visited.contains(part) && part != startPart) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (localData.finallyThrowParts.containsValue(part)) {
|
||||
visited.add(part);
|
||||
return;
|
||||
}
|
||||
|
||||
for (int i = ip; i <= part.end; i++) {
|
||||
AVM2Instruction ins = avm2code.code.get(i);
|
||||
if (ins.definition instanceof SetLocalTypeIns) {
|
||||
int regId = ((SetLocalTypeIns) ins.definition).getRegisterId(ins);
|
||||
if (searchRegId == regId) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (ins.definition instanceof GetLocalTypeIns) {
|
||||
int regId = ((GetLocalTypeIns) ins.definition).getRegisterId(ins);
|
||||
if (regId == searchRegId) {
|
||||
getLocalPos.add(i);
|
||||
}
|
||||
}
|
||||
if ((ins.definition instanceof IncLocalIns)
|
||||
|| (ins.definition instanceof IncLocalIIns)
|
||||
|| (ins.definition instanceof IncLocalPIns)
|
||||
|| (ins.definition instanceof DecLocalIns)
|
||||
|| (ins.definition instanceof DecLocalIIns)
|
||||
|| (ins.definition instanceof DecLocalPIns)) {
|
||||
int regId = ins.operands[0];
|
||||
if (regId == searchRegId) {
|
||||
getLocalPos.add(i);
|
||||
}
|
||||
}
|
||||
if ((ins.definition instanceof IncLocalPIns)
|
||||
|| (ins.definition instanceof DecLocalPIns)) {
|
||||
int regId = ins.operands[1];
|
||||
if (regId == searchRegId) {
|
||||
getLocalPos.add(i);
|
||||
}
|
||||
}
|
||||
if (ins.definition instanceof HasNext2Ins) {
|
||||
int regId1 = ins.operands[0];
|
||||
if (regId1 == searchRegId) {
|
||||
getLocalPos.add(i);
|
||||
}
|
||||
int regId2 = ins.operands[1];
|
||||
if (regId2 == searchRegId) {
|
||||
getLocalPos.add(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (visited.contains(part)) {
|
||||
return;
|
||||
}
|
||||
visited.add(part);
|
||||
|
||||
try {
|
||||
//stop on switch
|
||||
if (localData.ignoredSwitches.values().contains(part)) {
|
||||
return;
|
||||
}
|
||||
if (localData.finallyJumps.containsKey(part)) {
|
||||
GraphPart targetPart = localData.finallyJumps.get(part);
|
||||
if (localData.defaultParts.containsValue(targetPart)) {
|
||||
//okay, proceed to finally block
|
||||
} else if (targetPart.nextParts.size() == 1) {
|
||||
//continue or break, definitely not a return, there won't be a register usage
|
||||
walkLocalRegsUsage(localData, getLocalPos, startPart, targetPart.nextParts.get(0), visited, ip, searchRegId);
|
||||
return;
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
}
|
||||
for (GraphPart p : part.nextParts) {
|
||||
walkLocalRegsUsage(localData, getLocalPos, startPart, p, visited, p.start, searchRegId);
|
||||
}
|
||||
} finally {
|
||||
for (GraphPart p : part.throwParts) {
|
||||
walkLocalRegsUsage(localData, getLocalPos, startPart, p, visited, p.start, searchRegId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//TODO: optimize this to make it faster!!!
|
||||
public Map<Integer, Set<Integer>> calculateLocalRegsUsage(AVM2LocalData localData, Set<Integer> ignoredSwitches, String path, Set<GraphPart> allParts) {
|
||||
logger.log(Level.FINE, "--- {0} ---", path);
|
||||
Map<Integer, Set<Integer>> setLocalPosToGetLocalPos = new TreeMap<>();
|
||||
Map<GraphPart, Map<Integer, List<Integer>>> partUnresolvedRegisterToGetLocalPos = new HashMap<>();
|
||||
Map<GraphPart, Map<Integer, Integer>> partRegisterToLastSetLocalPos = new HashMap<>();
|
||||
|
||||
Map<GraphPart, GraphPart> reverseFinallyJumps = new HashMap<>();
|
||||
for (GraphPart p : localData.finallyJumps.keySet()) {
|
||||
reverseFinallyJumps.put(localData.finallyJumps.get(p), p);
|
||||
}
|
||||
|
||||
for (GraphPart p : allParts) {
|
||||
if (p.start < 0) {
|
||||
continue;
|
||||
}
|
||||
Map<Integer, Integer> registerToLastSetLocalPos = new HashMap<>();
|
||||
for (int ip = p.start; ip <= p.end; ip++) {
|
||||
AVM2Instruction ins = avm2code.code.get(ip);
|
||||
if (ins.definition instanceof SetLocalTypeIns) {
|
||||
int regId = ((SetLocalTypeIns) ins.definition).getRegisterId(ins);
|
||||
registerToLastSetLocalPos.put(regId, ip);
|
||||
setLocalPosToGetLocalPos.put(ip, new TreeSet<>());
|
||||
}
|
||||
List<Integer> usedRegs = new ArrayList<>();
|
||||
if (ins.definition instanceof GetLocalTypeIns) {
|
||||
int regId = ((GetLocalTypeIns) ins.definition).getRegisterId(ins);
|
||||
usedRegs.add(regId);
|
||||
}
|
||||
if ((ins.definition instanceof IncLocalIns)
|
||||
|| (ins.definition instanceof IncLocalIIns)
|
||||
|| (ins.definition instanceof IncLocalPIns)
|
||||
|| (ins.definition instanceof DecLocalIns)
|
||||
|| (ins.definition instanceof DecLocalIIns)
|
||||
|| (ins.definition instanceof DecLocalPIns)) {
|
||||
usedRegs.add(ins.operands[0]);
|
||||
}
|
||||
if ((ins.definition instanceof IncLocalPIns)
|
||||
|| (ins.definition instanceof DecLocalPIns)) {
|
||||
usedRegs.add(ins.operands[1]);
|
||||
}
|
||||
if (ins.definition instanceof HasNext2Ins) {
|
||||
usedRegs.add(ins.operands[0]);
|
||||
usedRegs.add(ins.operands[1]);
|
||||
}
|
||||
for (int regId : usedRegs) {
|
||||
if (registerToLastSetLocalPos.containsKey(regId)) {
|
||||
int setLocalPos = registerToLastSetLocalPos.get(regId);
|
||||
setLocalPosToGetLocalPos.get(setLocalPos).add(ip);
|
||||
} else {
|
||||
if (!partUnresolvedRegisterToGetLocalPos.containsKey(p)) {
|
||||
partUnresolvedRegisterToGetLocalPos.put(p, new HashMap<>());
|
||||
}
|
||||
if (!partUnresolvedRegisterToGetLocalPos.get(p).containsKey(regId)) {
|
||||
partUnresolvedRegisterToGetLocalPos.get(p).put(regId, new ArrayList<>());
|
||||
}
|
||||
partUnresolvedRegisterToGetLocalPos.get(p).get(regId).add(ip);
|
||||
}
|
||||
}
|
||||
}
|
||||
partRegisterToLastSetLocalPos.put(p, registerToLastSetLocalPos);
|
||||
}
|
||||
Map<Integer, Integer> setLocalPosToRegisterId = new HashMap<>();
|
||||
|
||||
Set<GraphPart> pSet = new HashSet<>(partUnresolvedRegisterToGetLocalPos.keySet());
|
||||
for (GraphPart p : pSet) {
|
||||
Map<Integer, List<Integer>> unresolvedRegisterToGetLocalPos = partUnresolvedRegisterToGetLocalPos.get(p);
|
||||
Set<GraphPart> visited = new HashSet<>();
|
||||
visited.add(p);
|
||||
if (reverseFinallyJumps.containsKey(p)) {
|
||||
GraphPart q = reverseFinallyJumps.get(p);
|
||||
calculateLocalRegsUsageWalk(reverseFinallyJumps, ignoredSwitches, q, unresolvedRegisterToGetLocalPos, visited, partRegisterToLastSetLocalPos, setLocalPosToGetLocalPos, p);
|
||||
} else {
|
||||
for (GraphPart q : p.refs) {
|
||||
calculateLocalRegsUsageWalk(reverseFinallyJumps, ignoredSwitches, q, unresolvedRegisterToGetLocalPos, visited, partRegisterToLastSetLocalPos, setLocalPosToGetLocalPos, p);
|
||||
}
|
||||
for (int ip = 0; ip < avm2code.code.size(); ip++) {
|
||||
AVM2Instruction ins = avm2code.code.get(ip);
|
||||
if (ins.definition instanceof SetLocalTypeIns) {
|
||||
int regId = ((SetLocalTypeIns) ins.definition).getRegisterId(ins);
|
||||
setLocalPosToGetLocalPos.put(ip, new TreeSet<>());
|
||||
setLocalPosToRegisterId.put(ip, regId);
|
||||
}
|
||||
}
|
||||
|
||||
for (int setLocalPos : setLocalPosToGetLocalPos.keySet()) {
|
||||
AVM2Instruction ins = avm2code.code.get(setLocalPos);
|
||||
int regId = ((SetLocalTypeIns) ins.definition).getRegisterId(ins);
|
||||
logger.log(Level.FINE, "set local reg {0} at pos {1}{2}", new Object[]{regId, setLocalPos, 1});
|
||||
|
||||
for (int getLocalPos : setLocalPosToGetLocalPos.get(setLocalPos)) {
|
||||
logger.log(Level.FINE, "- usage at pos {0}{1}", new Object[]{getLocalPos, 1});
|
||||
}
|
||||
for (int ip : setLocalPosToGetLocalPos.keySet()) {
|
||||
GraphPart part = searchPart(ip + 1, allParts);
|
||||
walkLocalRegsUsage(localData, setLocalPosToGetLocalPos.get(ip), part, part, new HashSet<>(), ip + 1, setLocalPosToRegisterId.get(ip));
|
||||
}
|
||||
|
||||
/*for (int ip : setLocalPosToGetLocalPos.keySet()) {
|
||||
System.err.println("definition at ip " + (ip + 1) + ", regid=" + setLocalPosToRegisterId.get(ip));
|
||||
for (int usageIp : setLocalPosToGetLocalPos.get(ip)) {
|
||||
System.err.println("- used at " + (usageIp + 1));
|
||||
}
|
||||
}*/
|
||||
return setLocalPosToGetLocalPos;
|
||||
}
|
||||
|
||||
public void calculateLocalRegsUsageWalk(Map<GraphPart, GraphPart> reverseFinallyJumps, Set<Integer> ignoredSwitches, GraphPart q,
|
||||
Map<Integer, List<Integer>> unresolvedRegisterToGetLocalPos,
|
||||
Set<GraphPart> visited,
|
||||
Map<GraphPart, Map<Integer, Integer>> partRegisterToLastSetLocalPos,
|
||||
Map<Integer, Set<Integer>> setLocalPosToGetLocalPos, GraphPart next) {
|
||||
if (visited.contains(q)) {
|
||||
return;
|
||||
}
|
||||
if (ignoredSwitches.contains(q.end)) {
|
||||
if (q.nextParts.isEmpty() || !next.equals(q.nextParts.get(0))) { //first is after finally
|
||||
return;
|
||||
}
|
||||
}
|
||||
Set<Integer> regIds = new HashSet<>(unresolvedRegisterToGetLocalPos.keySet());
|
||||
for (int regId : regIds) {
|
||||
if (partRegisterToLastSetLocalPos.containsKey(q)) {
|
||||
if (partRegisterToLastSetLocalPos.get(q).containsKey(regId)) {
|
||||
int lastSetLocalPos = partRegisterToLastSetLocalPos.get(q).get(regId);
|
||||
setLocalPosToGetLocalPos.get(lastSetLocalPos).addAll(unresolvedRegisterToGetLocalPos.get(regId));
|
||||
unresolvedRegisterToGetLocalPos = new HashMap<>(unresolvedRegisterToGetLocalPos);
|
||||
unresolvedRegisterToGetLocalPos.remove(regId);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (unresolvedRegisterToGetLocalPos.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
visited.add(q);
|
||||
|
||||
if (reverseFinallyJumps.containsKey(q)) {
|
||||
GraphPart r = reverseFinallyJumps.get(q);
|
||||
calculateLocalRegsUsageWalk(reverseFinallyJumps, ignoredSwitches, r, unresolvedRegisterToGetLocalPos, visited, partRegisterToLastSetLocalPos, setLocalPosToGetLocalPos, q);
|
||||
} else {
|
||||
for (GraphPart r : q.refs) {
|
||||
calculateLocalRegsUsageWalk(reverseFinallyJumps, ignoredSwitches, r, unresolvedRegisterToGetLocalPos, visited, partRegisterToLastSetLocalPos, setLocalPosToGetLocalPos, q);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static List<GraphTargetItem> translateViaGraph(String path, AVM2Code code, ABC abc, MethodBody body, boolean isStatic, int scriptIndex, int classIndex, HashMap<Integer, GraphTargetItem> localRegs, ScopeStack scopeStack, HashMap<Integer, String> localRegNames, List<DottedChain> fullyQualifiedNames, int staticOperation, HashMap<Integer, Integer> localRegAssigmentIps, HashMap<Integer, List<Integer>> refs, boolean thisHasDefaultToPrimitive) throws InterruptedException {
|
||||
AVM2Graph g = new AVM2Graph(code, abc, body, isStatic, scriptIndex, classIndex, localRegs, scopeStack, localRegNames, fullyQualifiedNames, localRegAssigmentIps, refs);
|
||||
|
||||
@@ -820,7 +811,6 @@ public class AVM2Graph extends Graph {
|
||||
|
||||
stack.clear(); //If the original code (before check()) had "if" in it, there would be something on stack
|
||||
|
||||
|
||||
if (finallyException == null) {
|
||||
List<GraphPart> stopPart2 = new ArrayList<>(stopPart);
|
||||
stopPart2.add(afterPart);
|
||||
@@ -1110,12 +1100,12 @@ public class AVM2Graph extends Graph {
|
||||
defaultPart = defaultPart.nextParts.get(0);
|
||||
}
|
||||
|
||||
ret = new ArrayList<>();
|
||||
ret.addAll(output);
|
||||
Reference<GraphPart> nextRef = new Reference<>(null);
|
||||
Reference<GraphTargetItem> tiRef = new Reference<>(null);
|
||||
SwitchItem sw = handleSwitch(switchedObject, switchStartItem, foundGotos, partCodes, partCodePos, allParts, stack, stopPart, loops, localData, staticOperation, path, caseValuesMap, defaultPart, caseBodyParts, nextRef, tiRef);
|
||||
checkSwitch(localData, sw, otherSide, ret);
|
||||
ret = new ArrayList<>();
|
||||
ret.addAll(output);
|
||||
checkSwitch(localData, sw, otherSide, ret.isEmpty() ? currentRet : ret /*hack :-(*/);
|
||||
ret.add(sw);
|
||||
if (nextRef.getVal() != null) {
|
||||
if (tiRef.getVal() != null) {
|
||||
|
||||
Reference in New Issue
Block a user