|
|
|
@ -1,37 +1,21 @@ |
|
|
|
|
/* |
|
|
|
|
* Fernflower - The Analytical Java Decompiler |
|
|
|
|
* http://www.reversed-java.com
|
|
|
|
|
* Copyright 2000-2014 JetBrains s.r.o. |
|
|
|
|
* |
|
|
|
|
* (C) 2008 - 2010, Stiver |
|
|
|
|
* 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 |
|
|
|
|
* |
|
|
|
|
* This software is NEITHER public domain NOR free software |
|
|
|
|
* as per GNU License. See license.txt for more details. |
|
|
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
|
* |
|
|
|
|
* This software is distributed WITHOUT ANY WARRANTY; without |
|
|
|
|
* even the implied warranty of MERCHANTABILITY or FITNESS FOR |
|
|
|
|
* A PARTICULAR PURPOSE. |
|
|
|
|
* 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.code.cfg; |
|
|
|
|
|
|
|
|
|
import java.util.ArrayList; |
|
|
|
|
import java.util.Arrays; |
|
|
|
|
import java.util.HashMap; |
|
|
|
|
import java.util.HashSet; |
|
|
|
|
import java.util.Iterator; |
|
|
|
|
import java.util.LinkedList; |
|
|
|
|
import java.util.List; |
|
|
|
|
import java.util.Map; |
|
|
|
|
import java.util.Map.Entry; |
|
|
|
|
import java.util.Set; |
|
|
|
|
|
|
|
|
|
import org.jetbrains.java.decompiler.code.CodeConstants; |
|
|
|
|
import org.jetbrains.java.decompiler.code.ExceptionHandler; |
|
|
|
|
import org.jetbrains.java.decompiler.code.Instruction; |
|
|
|
|
import org.jetbrains.java.decompiler.code.InstructionSequence; |
|
|
|
|
import org.jetbrains.java.decompiler.code.JumpInstruction; |
|
|
|
|
import org.jetbrains.java.decompiler.code.SimpleInstructionSequence; |
|
|
|
|
import org.jetbrains.java.decompiler.code.SwitchInstruction; |
|
|
|
|
import org.jetbrains.java.decompiler.code.*; |
|
|
|
|
import org.jetbrains.java.decompiler.code.interpreter.InstructionImpact; |
|
|
|
|
import org.jetbrains.java.decompiler.main.DecompilerContext; |
|
|
|
|
import org.jetbrains.java.decompiler.modules.code.DeadCodeHelper; |
|
|
|
@ -42,6 +26,9 @@ import org.jetbrains.java.decompiler.struct.gen.VarType; |
|
|
|
|
import org.jetbrains.java.decompiler.util.ListStack; |
|
|
|
|
import org.jetbrains.java.decompiler.util.VBStyleCollection; |
|
|
|
|
|
|
|
|
|
import java.util.*; |
|
|
|
|
import java.util.Map.Entry; |
|
|
|
|
|
|
|
|
|
public class ControlFlowGraph implements CodeConstants { |
|
|
|
|
|
|
|
|
|
public int last_id = 0; |
|
|
|
@ -77,7 +64,7 @@ public class ControlFlowGraph implements CodeConstants { |
|
|
|
|
|
|
|
|
|
public void free() { |
|
|
|
|
|
|
|
|
|
for(BasicBlock block: blocks) { |
|
|
|
|
for (BasicBlock block : blocks) { |
|
|
|
|
block.free(); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -89,7 +76,7 @@ public class ControlFlowGraph implements CodeConstants { |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
public void removeMarkers() { |
|
|
|
|
for(BasicBlock block: blocks) { |
|
|
|
|
for (BasicBlock block : blocks) { |
|
|
|
|
block.mark = 0; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
@ -100,39 +87,39 @@ public class ControlFlowGraph implements CodeConstants { |
|
|
|
|
|
|
|
|
|
StringBuffer buf = new StringBuffer(); |
|
|
|
|
|
|
|
|
|
for(BasicBlock block: blocks) { |
|
|
|
|
buf.append("----- Block "+block.id+" -----" + new_line_separator); |
|
|
|
|
for (BasicBlock block : blocks) { |
|
|
|
|
buf.append("----- Block " + block.id + " -----" + new_line_separator); |
|
|
|
|
buf.append(block.toString()); |
|
|
|
|
buf.append("----- Edges -----" + new_line_separator); |
|
|
|
|
|
|
|
|
|
List<BasicBlock> suc = block.getSuccs(); |
|
|
|
|
for(int j=0;j<suc.size();j++) { |
|
|
|
|
buf.append(">>>>>>>>(regular) Block "+((BasicBlock)suc.get(j)).id+new_line_separator); |
|
|
|
|
for (int j = 0; j < suc.size(); j++) { |
|
|
|
|
buf.append(">>>>>>>>(regular) Block " + ((BasicBlock)suc.get(j)).id + new_line_separator); |
|
|
|
|
} |
|
|
|
|
suc = block.getSuccExceptions(); |
|
|
|
|
for(int j=0;j<suc.size();j++) { |
|
|
|
|
for (int j = 0; j < suc.size(); j++) { |
|
|
|
|
BasicBlock handler = (BasicBlock)suc.get(j); |
|
|
|
|
ExceptionRangeCFG range = getExceptionRange(handler, block); |
|
|
|
|
|
|
|
|
|
if(range == null) { |
|
|
|
|
buf.append(">>>>>>>>(exception) Block "+handler.id+"\t"+"ERROR: range not found!"+new_line_separator); |
|
|
|
|
} else { |
|
|
|
|
if (range == null) { |
|
|
|
|
buf.append(">>>>>>>>(exception) Block " + handler.id + "\t" + "ERROR: range not found!" + new_line_separator); |
|
|
|
|
} |
|
|
|
|
else { |
|
|
|
|
List<String> exceptionTypes = range.getExceptionTypes(); |
|
|
|
|
if(exceptionTypes == null) { |
|
|
|
|
buf.append(">>>>>>>>(exception) Block "+handler.id+"\t"+"NULL"+new_line_separator); |
|
|
|
|
} else { |
|
|
|
|
for(String exceptionType : exceptionTypes) { |
|
|
|
|
buf.append(">>>>>>>>(exception) Block "+handler.id+"\t"+exceptionType+new_line_separator); |
|
|
|
|
if (exceptionTypes == null) { |
|
|
|
|
buf.append(">>>>>>>>(exception) Block " + handler.id + "\t" + "NULL" + new_line_separator); |
|
|
|
|
} |
|
|
|
|
else { |
|
|
|
|
for (String exceptionType : exceptionTypes) { |
|
|
|
|
buf.append(">>>>>>>>(exception) Block " + handler.id + "\t" + exceptionType + new_line_separator); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
buf.append("----- ----- -----" + new_line_separator); |
|
|
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
return buf.toString(); |
|
|
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
public void inlineJsr(StructMethod mt) { |
|
|
|
@ -146,19 +133,19 @@ public class ControlFlowGraph implements CodeConstants { |
|
|
|
|
|
|
|
|
|
public void removeBlock(BasicBlock block) { |
|
|
|
|
|
|
|
|
|
while(block.getSuccs().size()>0) { |
|
|
|
|
while (block.getSuccs().size() > 0) { |
|
|
|
|
block.removeSuccessor((BasicBlock)block.getSuccs().get(0)); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
while(block.getSuccExceptions().size()>0) { |
|
|
|
|
while (block.getSuccExceptions().size() > 0) { |
|
|
|
|
block.removeSuccessorException((BasicBlock)block.getSuccExceptions().get(0)); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
while(block.getPreds().size()>0) { |
|
|
|
|
while (block.getPreds().size() > 0) { |
|
|
|
|
((BasicBlock)block.getPreds().get(0)).removeSuccessor(block); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
while(block.getPredExceptions().size()>0) { |
|
|
|
|
while (block.getPredExceptions().size() > 0) { |
|
|
|
|
((BasicBlock)block.getPredExceptions().get(0)).removeSuccessorException(block); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -166,37 +153,37 @@ public class ControlFlowGraph implements CodeConstants { |
|
|
|
|
|
|
|
|
|
blocks.removeWithKey(block.id); |
|
|
|
|
|
|
|
|
|
for(int i=exceptions.size()-1;i>=0;i--) { |
|
|
|
|
for (int i = exceptions.size() - 1; i >= 0; i--) { |
|
|
|
|
ExceptionRangeCFG range = (ExceptionRangeCFG)exceptions.get(i); |
|
|
|
|
if(range.getHandler() == block) { |
|
|
|
|
if (range.getHandler() == block) { |
|
|
|
|
exceptions.remove(i); |
|
|
|
|
} else { |
|
|
|
|
} |
|
|
|
|
else { |
|
|
|
|
List<BasicBlock> lstRange = range.getProtectedRange(); |
|
|
|
|
lstRange.remove(block); |
|
|
|
|
|
|
|
|
|
if(lstRange.isEmpty()) { |
|
|
|
|
if (lstRange.isEmpty()) { |
|
|
|
|
exceptions.remove(i); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
Iterator<Entry<BasicBlock, BasicBlock>> it = subroutines.entrySet().iterator(); |
|
|
|
|
while(it.hasNext()) { |
|
|
|
|
while (it.hasNext()) { |
|
|
|
|
Entry<BasicBlock, BasicBlock> ent = it.next(); |
|
|
|
|
if(ent.getKey() == block || ent.getValue() == block) { |
|
|
|
|
if (ent.getKey() == block || ent.getValue() == block) { |
|
|
|
|
it.remove(); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
public ExceptionRangeCFG getExceptionRange(BasicBlock handler, BasicBlock block) { |
|
|
|
|
|
|
|
|
|
//List<ExceptionRangeCFG> ranges = new ArrayList<ExceptionRangeCFG>();
|
|
|
|
|
|
|
|
|
|
for(int i=exceptions.size()-1;i>=0;i--) { |
|
|
|
|
for (int i = exceptions.size() - 1; i >= 0; i--) { |
|
|
|
|
ExceptionRangeCFG range = exceptions.get(i); |
|
|
|
|
if(range.getHandler() == handler && range.getProtectedRange().contains(block)) { |
|
|
|
|
if (range.getHandler() == handler && range.getProtectedRange().contains(block)) { |
|
|
|
|
return range; |
|
|
|
|
//ranges.add(range);
|
|
|
|
|
} |
|
|
|
@ -206,26 +193,26 @@ public class ControlFlowGraph implements CodeConstants { |
|
|
|
|
//return ranges.isEmpty() ? null : ranges;
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// public String getExceptionsUniqueString(BasicBlock handler, BasicBlock block) {
|
|
|
|
|
//
|
|
|
|
|
// List<ExceptionRangeCFG> ranges = getExceptionRange(handler, block);
|
|
|
|
|
//
|
|
|
|
|
// if(ranges == null) {
|
|
|
|
|
// return null;
|
|
|
|
|
// } else {
|
|
|
|
|
// Set<String> setExceptionStrings = new HashSet<String>();
|
|
|
|
|
// for(ExceptionRangeCFG range : ranges) {
|
|
|
|
|
// setExceptionStrings.add(range.getExceptionType());
|
|
|
|
|
// }
|
|
|
|
|
//
|
|
|
|
|
// String ret = "";
|
|
|
|
|
// for(String exception : setExceptionStrings) {
|
|
|
|
|
// ret += exception;
|
|
|
|
|
// }
|
|
|
|
|
//
|
|
|
|
|
// return ret;
|
|
|
|
|
// }
|
|
|
|
|
// }
|
|
|
|
|
// public String getExceptionsUniqueString(BasicBlock handler, BasicBlock block) {
|
|
|
|
|
//
|
|
|
|
|
// List<ExceptionRangeCFG> ranges = getExceptionRange(handler, block);
|
|
|
|
|
//
|
|
|
|
|
// if(ranges == null) {
|
|
|
|
|
// return null;
|
|
|
|
|
// } else {
|
|
|
|
|
// Set<String> setExceptionStrings = new HashSet<String>();
|
|
|
|
|
// for(ExceptionRangeCFG range : ranges) {
|
|
|
|
|
// setExceptionStrings.add(range.getExceptionType());
|
|
|
|
|
// }
|
|
|
|
|
//
|
|
|
|
|
// String ret = "";
|
|
|
|
|
// for(String exception : setExceptionStrings) {
|
|
|
|
|
// ret += exception;
|
|
|
|
|
// }
|
|
|
|
|
//
|
|
|
|
|
// return ret;
|
|
|
|
|
// }
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// *****************************************************************************
|
|
|
|
@ -257,38 +244,38 @@ public class ControlFlowGraph implements CodeConstants { |
|
|
|
|
|
|
|
|
|
HashSet<Integer> excSet = new HashSet<Integer>(); |
|
|
|
|
|
|
|
|
|
for(ExceptionHandler handler : seq.getExceptionTable().getHandlers()) { |
|
|
|
|
for (ExceptionHandler handler : seq.getExceptionTable().getHandlers()) { |
|
|
|
|
excSet.add(handler.from_instr); |
|
|
|
|
excSet.add(handler.to_instr); |
|
|
|
|
excSet.add(handler.handler_instr); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
for(int i=0;i<len;i++) { |
|
|
|
|
for (int i = 0; i < len; i++) { |
|
|
|
|
|
|
|
|
|
// exception blocks
|
|
|
|
|
if(excSet.contains(new Integer(i))) { |
|
|
|
|
if (excSet.contains(new Integer(i))) { |
|
|
|
|
inststates[i] = 1; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
Instruction instr = seq.getInstr(i); |
|
|
|
|
switch(instr.group){ |
|
|
|
|
switch (instr.group) { |
|
|
|
|
case GROUP_JUMP: |
|
|
|
|
inststates[((JumpInstruction)instr).destination] = 1; |
|
|
|
|
case GROUP_RETURN: |
|
|
|
|
if(i+1 < len) { |
|
|
|
|
inststates[i+1] = 1; |
|
|
|
|
if (i + 1 < len) { |
|
|
|
|
inststates[i + 1] = 1; |
|
|
|
|
} |
|
|
|
|
break; |
|
|
|
|
case GROUP_SWITCH: |
|
|
|
|
SwitchInstruction swinstr = (SwitchInstruction)instr; |
|
|
|
|
int[] dests = swinstr.getDestinations(); |
|
|
|
|
for(int j=dests.length-1;j>=0;j--) { |
|
|
|
|
for (int j = dests.length - 1; j >= 0; j--) { |
|
|
|
|
inststates[dests[j]] = 1; |
|
|
|
|
} |
|
|
|
|
inststates[swinstr.getDefaultdest()] = 1; |
|
|
|
|
if(i+1 < len) { |
|
|
|
|
inststates[i+1] = 1; |
|
|
|
|
if (i + 1 < len) { |
|
|
|
|
inststates[i + 1] = 1; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
@ -313,7 +300,7 @@ public class ControlFlowGraph implements CodeConstants { |
|
|
|
|
int blockoffset = 0; |
|
|
|
|
|
|
|
|
|
BasicBlock currentBlock = null; |
|
|
|
|
for(int i=0;i<len;i++) { |
|
|
|
|
for (int i = 0; i < len; i++) { |
|
|
|
|
|
|
|
|
|
if (startblock[i] == 1) { |
|
|
|
|
currentBlock = new BasicBlock(); |
|
|
|
@ -332,7 +319,7 @@ public class ControlFlowGraph implements CodeConstants { |
|
|
|
|
startblock[i] = counter; |
|
|
|
|
mapInstrBlocks.put(i, currentBlock); |
|
|
|
|
|
|
|
|
|
currseq.addInstruction(instrseq.getInstr(i), instrseq.getOffset(i)-blockoffset); |
|
|
|
|
currseq.addInstruction(instrseq.getInstr(i), instrseq.getOffset(i) - blockoffset); |
|
|
|
|
lstOffs.add(instrseq.getOffset(i)); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -344,7 +331,7 @@ public class ControlFlowGraph implements CodeConstants { |
|
|
|
|
|
|
|
|
|
private void connectBlocks(List<BasicBlock> lstbb, HashMap<Integer, BasicBlock> mapInstrBlocks) { |
|
|
|
|
|
|
|
|
|
for(int i=0;i<lstbb.size();i++) { |
|
|
|
|
for (int i = 0; i < lstbb.size(); i++) { |
|
|
|
|
|
|
|
|
|
BasicBlock block = lstbb.get(i); |
|
|
|
|
Instruction instr = block.getLastInstruction(); |
|
|
|
@ -352,7 +339,7 @@ public class ControlFlowGraph implements CodeConstants { |
|
|
|
|
boolean fallthrough = instr.canFallthrough(); |
|
|
|
|
BasicBlock bTemp; |
|
|
|
|
|
|
|
|
|
switch(instr.group) { |
|
|
|
|
switch (instr.group) { |
|
|
|
|
case GROUP_JUMP: |
|
|
|
|
int dest = ((JumpInstruction)instr).destination; |
|
|
|
|
bTemp = mapInstrBlocks.get(dest); |
|
|
|
@ -365,18 +352,17 @@ public class ControlFlowGraph implements CodeConstants { |
|
|
|
|
|
|
|
|
|
bTemp = mapInstrBlocks.get(((SwitchInstruction)instr).getDefaultdest()); |
|
|
|
|
block.addSuccessor(bTemp); |
|
|
|
|
for(int j=0;j<dests.length;j++) { |
|
|
|
|
for (int j = 0; j < dests.length; j++) { |
|
|
|
|
bTemp = mapInstrBlocks.get(dests[j]); |
|
|
|
|
block.addSuccessor(bTemp); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if(fallthrough && i<lstbb.size()-1) { |
|
|
|
|
BasicBlock defaultBlock = lstbb.get(i+1); |
|
|
|
|
if (fallthrough && i < lstbb.size() - 1) { |
|
|
|
|
BasicBlock defaultBlock = lstbb.get(i + 1); |
|
|
|
|
block.addSuccessor(defaultBlock); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
private void setExceptionEdges(InstructionSequence instrseq, HashMap<Integer, BasicBlock> instrBlocks) { |
|
|
|
@ -385,7 +371,7 @@ public class ControlFlowGraph implements CodeConstants { |
|
|
|
|
|
|
|
|
|
Map<String, ExceptionRangeCFG> mapRanges = new HashMap<String, ExceptionRangeCFG>(); |
|
|
|
|
|
|
|
|
|
for(ExceptionHandler handler : instrseq.getExceptionTable().getHandlers()) { |
|
|
|
|
for (ExceptionHandler handler : instrseq.getExceptionTable().getHandlers()) { |
|
|
|
|
|
|
|
|
|
BasicBlock from = instrBlocks.get(handler.from_instr); |
|
|
|
|
BasicBlock to = instrBlocks.get(handler.to_instr); |
|
|
|
@ -393,19 +379,22 @@ public class ControlFlowGraph implements CodeConstants { |
|
|
|
|
|
|
|
|
|
String key = from.id + ":" + to.id + ":" + handle.id; |
|
|
|
|
|
|
|
|
|
if(mapRanges.containsKey(key)) { |
|
|
|
|
if (mapRanges.containsKey(key)) { |
|
|
|
|
ExceptionRangeCFG range = mapRanges.get(key); |
|
|
|
|
range.addExceptionType(handler.exceptionClass); |
|
|
|
|
} else { |
|
|
|
|
} |
|
|
|
|
else { |
|
|
|
|
|
|
|
|
|
List<BasicBlock> protectedRange = new ArrayList<BasicBlock>(); |
|
|
|
|
for(int j=from.id;j<to.id;j++) { |
|
|
|
|
for (int j = from.id; j < to.id; j++) { |
|
|
|
|
BasicBlock block = blocks.getWithKey(j); |
|
|
|
|
protectedRange.add(block); |
|
|
|
|
block.addSuccessorException(handle); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
ExceptionRangeCFG range = new ExceptionRangeCFG(protectedRange, handle, handler.exceptionClass == null ? null : Arrays.asList(new String[]{handler.exceptionClass})); |
|
|
|
|
ExceptionRangeCFG range = new ExceptionRangeCFG(protectedRange, handle, handler.exceptionClass == null |
|
|
|
|
? null |
|
|
|
|
: Arrays.asList(new String[]{handler.exceptionClass})); |
|
|
|
|
mapRanges.put(key, range); |
|
|
|
|
|
|
|
|
|
exceptions.add(range); |
|
|
|
@ -417,9 +406,9 @@ public class ControlFlowGraph implements CodeConstants { |
|
|
|
|
|
|
|
|
|
final HashMap<BasicBlock, BasicBlock> subroutines = new HashMap<BasicBlock, BasicBlock>(); |
|
|
|
|
|
|
|
|
|
for(BasicBlock block : blocks) { |
|
|
|
|
for (BasicBlock block : blocks) { |
|
|
|
|
|
|
|
|
|
if(block.getSeq().getLastInstr().opcode == CodeConstants.opc_jsr) { |
|
|
|
|
if (block.getSeq().getLastInstr().opcode == CodeConstants.opc_jsr) { |
|
|
|
|
|
|
|
|
|
LinkedList<BasicBlock> stack = new LinkedList<BasicBlock>(); |
|
|
|
|
LinkedList<LinkedList<BasicBlock>> stackJsrStacks = new LinkedList<LinkedList<BasicBlock>>(); |
|
|
|
@ -429,14 +418,14 @@ public class ControlFlowGraph implements CodeConstants { |
|
|
|
|
stack.add(block); |
|
|
|
|
stackJsrStacks.add(new LinkedList<BasicBlock>()); |
|
|
|
|
|
|
|
|
|
while(!stack.isEmpty()) { |
|
|
|
|
while (!stack.isEmpty()) { |
|
|
|
|
|
|
|
|
|
BasicBlock node = stack.removeFirst(); |
|
|
|
|
LinkedList<BasicBlock> jsrstack = stackJsrStacks.removeFirst(); |
|
|
|
|
|
|
|
|
|
setVisited.add(node); |
|
|
|
|
|
|
|
|
|
switch(node.getSeq().getLastInstr().opcode) { |
|
|
|
|
switch (node.getSeq().getLastInstr().opcode) { |
|
|
|
|
case CodeConstants.opc_jsr: |
|
|
|
|
jsrstack.add(node); |
|
|
|
|
break; |
|
|
|
@ -444,20 +433,21 @@ public class ControlFlowGraph implements CodeConstants { |
|
|
|
|
BasicBlock enter = jsrstack.getLast(); |
|
|
|
|
BasicBlock exit = blocks.getWithKey(enter.id + 1); // FIXME: find successor in a better way
|
|
|
|
|
|
|
|
|
|
if(exit!=null) { |
|
|
|
|
if(!node.isSuccessor(exit)) { |
|
|
|
|
if (exit != null) { |
|
|
|
|
if (!node.isSuccessor(exit)) { |
|
|
|
|
node.addSuccessor(exit); |
|
|
|
|
} |
|
|
|
|
jsrstack.removeLast(); |
|
|
|
|
subroutines.put(enter, exit); |
|
|
|
|
} else { |
|
|
|
|
} |
|
|
|
|
else { |
|
|
|
|
throw new RuntimeException("ERROR: last instruction jsr"); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if(!jsrstack.isEmpty()) { |
|
|
|
|
for(BasicBlock succ : node.getSuccs()) { |
|
|
|
|
if(!setVisited.contains(succ)) { |
|
|
|
|
if (!jsrstack.isEmpty()) { |
|
|
|
|
for (BasicBlock succ : node.getSuccs()) { |
|
|
|
|
if (!setVisited.contains(succ)) { |
|
|
|
|
stack.add(succ); |
|
|
|
|
stackJsrStacks.add(new LinkedList<BasicBlock>(jsrstack)); |
|
|
|
|
} |
|
|
|
@ -472,7 +462,7 @@ public class ControlFlowGraph implements CodeConstants { |
|
|
|
|
|
|
|
|
|
private void processJsr() { |
|
|
|
|
|
|
|
|
|
while(processJsrRanges()!=0); |
|
|
|
|
while (processJsrRanges() != 0) ; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
private int processJsrRanges() { |
|
|
|
@ -480,7 +470,7 @@ public class ControlFlowGraph implements CodeConstants { |
|
|
|
|
List<Object[]> lstJsrAll = new ArrayList<Object[]>(); |
|
|
|
|
|
|
|
|
|
// get all jsr ranges
|
|
|
|
|
for(Entry<BasicBlock, BasicBlock> ent : subroutines.entrySet()){ |
|
|
|
|
for (Entry<BasicBlock, BasicBlock> ent : subroutines.entrySet()) { |
|
|
|
|
BasicBlock jsr = ent.getKey(); |
|
|
|
|
BasicBlock ret = ent.getValue(); |
|
|
|
|
|
|
|
|
@ -490,12 +480,12 @@ public class ControlFlowGraph implements CodeConstants { |
|
|
|
|
// sort ranges
|
|
|
|
|
// FIXME: better sort order
|
|
|
|
|
List<Object[]> lstJsr = new ArrayList<Object[]>(); |
|
|
|
|
for(Object[] arr : lstJsrAll) { |
|
|
|
|
int i=0; |
|
|
|
|
for(;i<lstJsr.size();i++) { |
|
|
|
|
for (Object[] arr : lstJsrAll) { |
|
|
|
|
int i = 0; |
|
|
|
|
for (; i < lstJsr.size(); i++) { |
|
|
|
|
Object[] arrJsr = lstJsr.get(i); |
|
|
|
|
|
|
|
|
|
if(((HashSet<BasicBlock>)arrJsr[1]).contains(arr[0])) { |
|
|
|
|
if (((HashSet<BasicBlock>)arrJsr[1]).contains(arr[0])) { |
|
|
|
|
break; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
@ -504,19 +494,19 @@ public class ControlFlowGraph implements CodeConstants { |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// find the first intersection
|
|
|
|
|
for(int i=0;i<lstJsr.size();i++) { |
|
|
|
|
for (int i = 0; i < lstJsr.size(); i++) { |
|
|
|
|
Object[] arr = (Object[])lstJsr.get(i); |
|
|
|
|
HashSet<BasicBlock> set = (HashSet<BasicBlock>)arr[1]; |
|
|
|
|
|
|
|
|
|
for(int j=i+1;j<lstJsr.size();j++) { |
|
|
|
|
for (int j = i + 1; j < lstJsr.size(); j++) { |
|
|
|
|
Object[] arr1 = (Object[])lstJsr.get(j); |
|
|
|
|
HashSet<BasicBlock> set1 = (HashSet<BasicBlock>)arr1[1]; |
|
|
|
|
|
|
|
|
|
if(!set.contains(arr1[0]) && !set1.contains(arr[0])) { // rang 0 doesn't contain entry 1 and vice versa
|
|
|
|
|
if (!set.contains(arr1[0]) && !set1.contains(arr[0])) { // rang 0 doesn't contain entry 1 and vice versa
|
|
|
|
|
HashSet<BasicBlock> setc = new HashSet<BasicBlock>(set); |
|
|
|
|
setc.retainAll(set1); |
|
|
|
|
|
|
|
|
|
if(!setc.isEmpty()) { |
|
|
|
|
if (!setc.isEmpty()) { |
|
|
|
|
splitJsrRange((BasicBlock)arr[0], (BasicBlock)arr[2], setc); |
|
|
|
|
return 1; |
|
|
|
|
} |
|
|
|
@ -536,48 +526,49 @@ public class ControlFlowGraph implements CodeConstants { |
|
|
|
|
|
|
|
|
|
BasicBlock dom = jsr.getSuccs().get(0); |
|
|
|
|
|
|
|
|
|
while(!lstNodes.isEmpty()) { |
|
|
|
|
while (!lstNodes.isEmpty()) { |
|
|
|
|
|
|
|
|
|
BasicBlock node = lstNodes.remove(0); |
|
|
|
|
|
|
|
|
|
for(int j=0;j<2;j++) { |
|
|
|
|
for (int j = 0; j < 2; j++) { |
|
|
|
|
List<BasicBlock> lst; |
|
|
|
|
if(j==0) { |
|
|
|
|
if(node.getLastInstruction().opcode == CodeConstants.opc_ret) { |
|
|
|
|
if(node.getSuccs().contains(ret)) { |
|
|
|
|
if (j == 0) { |
|
|
|
|
if (node.getLastInstruction().opcode == CodeConstants.opc_ret) { |
|
|
|
|
if (node.getSuccs().contains(ret)) { |
|
|
|
|
continue; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
lst = node.getSuccs(); |
|
|
|
|
} else { |
|
|
|
|
if(node == jsr) { |
|
|
|
|
} |
|
|
|
|
else { |
|
|
|
|
if (node == jsr) { |
|
|
|
|
continue; |
|
|
|
|
} |
|
|
|
|
lst = node.getSuccExceptions(); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
CHILD: |
|
|
|
|
for(int i=lst.size()-1;i>=0;i--) { |
|
|
|
|
for (int i = lst.size() - 1; i >= 0; i--) { |
|
|
|
|
|
|
|
|
|
BasicBlock child = lst.get(i); |
|
|
|
|
if(!blocks.contains(child)) { |
|
|
|
|
if (!blocks.contains(child)) { |
|
|
|
|
|
|
|
|
|
if(node != jsr) { |
|
|
|
|
for(int k=0;k<child.getPreds().size();k++) { |
|
|
|
|
if(!DeadCodeHelper.isDominator(this, child.getPreds().get(k), dom)) { |
|
|
|
|
if (node != jsr) { |
|
|
|
|
for (int k = 0; k < child.getPreds().size(); k++) { |
|
|
|
|
if (!DeadCodeHelper.isDominator(this, child.getPreds().get(k), dom)) { |
|
|
|
|
continue CHILD; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
for(int k=0;k<child.getPredExceptions().size();k++) { |
|
|
|
|
if(!DeadCodeHelper.isDominator(this, child.getPredExceptions().get(k), dom)) { |
|
|
|
|
for (int k = 0; k < child.getPredExceptions().size(); k++) { |
|
|
|
|
if (!DeadCodeHelper.isDominator(this, child.getPredExceptions().get(k), dom)) { |
|
|
|
|
continue CHILD; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// last block is a dummy one
|
|
|
|
|
if(child!=last) { |
|
|
|
|
if (child != last) { |
|
|
|
|
blocks.add(child); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -598,69 +589,72 @@ public class ControlFlowGraph implements CodeConstants { |
|
|
|
|
lstNodes.add(jsr); |
|
|
|
|
mapNewNodes.put(jsr.id, jsr); |
|
|
|
|
|
|
|
|
|
while(!lstNodes.isEmpty()) { |
|
|
|
|
while (!lstNodes.isEmpty()) { |
|
|
|
|
|
|
|
|
|
BasicBlock node = lstNodes.remove(0); |
|
|
|
|
|
|
|
|
|
for(int j=0;j<2;j++) { |
|
|
|
|
for (int j = 0; j < 2; j++) { |
|
|
|
|
List<BasicBlock> lst; |
|
|
|
|
if(j==0) { |
|
|
|
|
if(node.getLastInstruction().opcode == CodeConstants.opc_ret) { |
|
|
|
|
if(node.getSuccs().contains(ret)) { |
|
|
|
|
if (j == 0) { |
|
|
|
|
if (node.getLastInstruction().opcode == CodeConstants.opc_ret) { |
|
|
|
|
if (node.getSuccs().contains(ret)) { |
|
|
|
|
continue; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
lst = node.getSuccs(); |
|
|
|
|
} else { |
|
|
|
|
if(node == jsr) { |
|
|
|
|
} |
|
|
|
|
else { |
|
|
|
|
if (node == jsr) { |
|
|
|
|
continue; |
|
|
|
|
} |
|
|
|
|
lst = node.getSuccExceptions(); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
for(int i=lst.size()-1;i>=0;i--) { |
|
|
|
|
for (int i = lst.size() - 1; i >= 0; i--) { |
|
|
|
|
|
|
|
|
|
BasicBlock child = (BasicBlock)lst.get(i); |
|
|
|
|
Integer childid = child.id; |
|
|
|
|
|
|
|
|
|
if(mapNewNodes.containsKey(childid)) { |
|
|
|
|
if (mapNewNodes.containsKey(childid)) { |
|
|
|
|
node.replaceSuccessor(child, (BasicBlock)mapNewNodes.get(childid)); |
|
|
|
|
} else if(common_blocks.contains(child)) { |
|
|
|
|
} |
|
|
|
|
else if (common_blocks.contains(child)) { |
|
|
|
|
|
|
|
|
|
// make a copy of the current block
|
|
|
|
|
BasicBlock copy = (BasicBlock)child.clone(); |
|
|
|
|
copy.id = ++last_id; |
|
|
|
|
// copy all successors
|
|
|
|
|
if(copy.getLastInstruction().opcode == CodeConstants.opc_ret && |
|
|
|
|
if (copy.getLastInstruction().opcode == CodeConstants.opc_ret && |
|
|
|
|
child.getSuccs().contains(ret)) { |
|
|
|
|
copy.addSuccessor(ret); |
|
|
|
|
child.removeSuccessor(ret); |
|
|
|
|
} else { |
|
|
|
|
for(int k=0;k<child.getSuccs().size();k++) { |
|
|
|
|
} |
|
|
|
|
else { |
|
|
|
|
for (int k = 0; k < child.getSuccs().size(); k++) { |
|
|
|
|
copy.addSuccessor((BasicBlock)child.getSuccs().get(k)); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
for(int k=0;k<child.getSuccExceptions().size();k++) { |
|
|
|
|
for (int k = 0; k < child.getSuccExceptions().size(); k++) { |
|
|
|
|
copy.addSuccessorException((BasicBlock)child.getSuccExceptions().get(k)); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
lstNodes.add(copy); |
|
|
|
|
mapNewNodes.put(childid, copy); |
|
|
|
|
|
|
|
|
|
if(last.getPreds().contains(child)) { |
|
|
|
|
if (last.getPreds().contains(child)) { |
|
|
|
|
last.addPredecessor(copy); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
node.replaceSuccessor(child, copy); |
|
|
|
|
blocks.addWithKey(copy, copy.id); |
|
|
|
|
} else { |
|
|
|
|
} |
|
|
|
|
else { |
|
|
|
|
// stop at the first fixed node
|
|
|
|
|
//lstNodes.add(child);
|
|
|
|
|
mapNewNodes.put(childid, child); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -670,7 +664,7 @@ public class ControlFlowGraph implements CodeConstants { |
|
|
|
|
|
|
|
|
|
private void splitJsrExceptionRanges(HashSet<BasicBlock> common_blocks, HashMap<Integer, BasicBlock> mapNewNodes) { |
|
|
|
|
|
|
|
|
|
for(int i=exceptions.size()-1;i>=0;i--) { |
|
|
|
|
for (int i = exceptions.size() - 1; i >= 0; i--) { |
|
|
|
|
|
|
|
|
|
ExceptionRangeCFG range = (ExceptionRangeCFG)exceptions.get(i); |
|
|
|
|
List<BasicBlock> lstRange = range.getProtectedRange(); |
|
|
|
@ -678,24 +672,24 @@ public class ControlFlowGraph implements CodeConstants { |
|
|
|
|
HashSet<BasicBlock> setBoth = new HashSet<BasicBlock>(common_blocks); |
|
|
|
|
setBoth.retainAll(lstRange); |
|
|
|
|
|
|
|
|
|
if(setBoth.size()>0) { |
|
|
|
|
if (setBoth.size() > 0) { |
|
|
|
|
List<BasicBlock> lstNewRange; |
|
|
|
|
|
|
|
|
|
if(setBoth.size()==lstRange.size()) { |
|
|
|
|
if (setBoth.size() == lstRange.size()) { |
|
|
|
|
lstNewRange = new ArrayList<BasicBlock>(); |
|
|
|
|
ExceptionRangeCFG newRange = new ExceptionRangeCFG(lstNewRange, |
|
|
|
|
(BasicBlock)mapNewNodes.get(range.getHandler().id),range.getExceptionTypes()); |
|
|
|
|
(BasicBlock)mapNewNodes.get(range.getHandler().id), range.getExceptionTypes()); |
|
|
|
|
exceptions.add(newRange); |
|
|
|
|
} else { |
|
|
|
|
} |
|
|
|
|
else { |
|
|
|
|
lstNewRange = lstRange; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
for(BasicBlock block : setBoth) { |
|
|
|
|
for (BasicBlock block : setBoth) { |
|
|
|
|
lstNewRange.add(mapNewNodes.get(block.id)); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
private void removeJsr(StructMethod mt) { |
|
|
|
@ -707,17 +701,17 @@ public class ControlFlowGraph implements CodeConstants { |
|
|
|
|
ListStack<VarType> stack = data.getStack(); |
|
|
|
|
|
|
|
|
|
InstructionSequence seq = block.getSeq(); |
|
|
|
|
for(int i=0;i<seq.length();i++) { |
|
|
|
|
for (int i = 0; i < seq.length(); i++) { |
|
|
|
|
Instruction instr = seq.getInstr(i); |
|
|
|
|
|
|
|
|
|
VarType var = null; |
|
|
|
|
if(instr.opcode == CodeConstants.opc_astore || instr.opcode == CodeConstants.opc_pop) { |
|
|
|
|
if (instr.opcode == CodeConstants.opc_astore || instr.opcode == CodeConstants.opc_pop) { |
|
|
|
|
var = stack.getByOffset(-1); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
InstructionImpact.stepTypes(data, instr, pool); |
|
|
|
|
|
|
|
|
|
switch(instr.opcode) { |
|
|
|
|
switch (instr.opcode) { |
|
|
|
|
case CodeConstants.opc_jsr: |
|
|
|
|
case CodeConstants.opc_ret: |
|
|
|
|
seq.removeInstruction(i); |
|
|
|
@ -725,26 +719,25 @@ public class ControlFlowGraph implements CodeConstants { |
|
|
|
|
break; |
|
|
|
|
case CodeConstants.opc_astore: |
|
|
|
|
case CodeConstants.opc_pop: |
|
|
|
|
if(var.type == CodeConstants.TYPE_ADDRESS) { |
|
|
|
|
if (var.type == CodeConstants.TYPE_ADDRESS) { |
|
|
|
|
seq.removeInstruction(i); |
|
|
|
|
i--; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
block.mark = 1; |
|
|
|
|
|
|
|
|
|
for(int i=0;i<block.getSuccs().size();i++) { |
|
|
|
|
for (int i = 0; i < block.getSuccs().size(); i++) { |
|
|
|
|
BasicBlock suc = (BasicBlock)block.getSuccs().get(i); |
|
|
|
|
if(suc.mark != 1) { |
|
|
|
|
if (suc.mark != 1) { |
|
|
|
|
removeJsrInstructions(pool, suc, data.copy()); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
for(int i=0;i<block.getSuccExceptions().size();i++) { |
|
|
|
|
for (int i = 0; i < block.getSuccExceptions().size(); i++) { |
|
|
|
|
BasicBlock suc = (BasicBlock)block.getSuccExceptions().get(i); |
|
|
|
|
if(suc.mark != 1) { |
|
|
|
|
if (suc.mark != 1) { |
|
|
|
|
|
|
|
|
|
DataPoint point = new DataPoint(); |
|
|
|
|
point.setLocalVariables(new ArrayList<VarType>(data.getLocalVariables())); |
|
|
|
@ -753,7 +746,6 @@ public class ControlFlowGraph implements CodeConstants { |
|
|
|
|
removeJsrInstructions(pool, suc, point); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
private void setFirstAndLastBlocks() { |
|
|
|
@ -764,8 +756,8 @@ public class ControlFlowGraph implements CodeConstants { |
|
|
|
|
last.id = ++last_id; |
|
|
|
|
last.setSeq(new SimpleInstructionSequence()); |
|
|
|
|
|
|
|
|
|
for(BasicBlock block: blocks) { |
|
|
|
|
if(block.getSuccs().isEmpty()) { |
|
|
|
|
for (BasicBlock block : blocks) { |
|
|
|
|
if (block.getSuccs().isEmpty()) { |
|
|
|
|
last.addPredecessor(block); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
@ -789,7 +781,7 @@ public class ControlFlowGraph implements CodeConstants { |
|
|
|
|
stackNode.add(root); |
|
|
|
|
stackIndex.add(0); |
|
|
|
|
|
|
|
|
|
while(!stackNode.isEmpty()) { |
|
|
|
|
while (!stackNode.isEmpty()) { |
|
|
|
|
|
|
|
|
|
BasicBlock node = stackNode.getLast(); |
|
|
|
|
int index = stackIndex.removeLast(); |
|
|
|
@ -799,11 +791,11 @@ public class ControlFlowGraph implements CodeConstants { |
|
|
|
|
List<BasicBlock> lstSuccs = new ArrayList<BasicBlock>(node.getSuccs()); |
|
|
|
|
lstSuccs.addAll(node.getSuccExceptions()); |
|
|
|
|
|
|
|
|
|
for(;index<lstSuccs.size();index++) { |
|
|
|
|
for (; index < lstSuccs.size(); index++) { |
|
|
|
|
BasicBlock succ = lstSuccs.get(index); |
|
|
|
|
|
|
|
|
|
if(!setVisited.contains(succ)) { |
|
|
|
|
stackIndex.add(index+1); |
|
|
|
|
if (!setVisited.contains(succ)) { |
|
|
|
|
stackIndex.add(index + 1); |
|
|
|
|
|
|
|
|
|
stackNode.add(succ); |
|
|
|
|
stackIndex.add(0); |
|
|
|
@ -812,13 +804,12 @@ public class ControlFlowGraph implements CodeConstants { |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if(index == lstSuccs.size()) { |
|
|
|
|
if (index == lstSuccs.size()) { |
|
|
|
|
lst.add(0, node); |
|
|
|
|
|
|
|
|
|
stackNode.removeLast(); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
@ -883,5 +874,4 @@ public class ControlFlowGraph implements CodeConstants { |
|
|
|
|
public void setFinallyExits(HashSet<BasicBlock> finallyExits) { |
|
|
|
|
this.finallyExits = finallyExits; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
} |
|
|
|
|