From 076e4393f25bf1ad1ff1bd2853153e2b595dd90b Mon Sep 17 00:00:00 2001 From: Roman Shevchenko Date: Thu, 28 Aug 2014 21:34:14 +0400 Subject: java-decompiler: post-import cleanup (formatting and copyright) --- .../java/decompiler/code/cfg/BasicBlock.java | 499 +++--- .../java/decompiler/code/cfg/ControlFlowGraph.java | 1722 ++++++++++---------- .../decompiler/code/cfg/ExceptionRangeCFG.java | 229 +-- 3 files changed, 1221 insertions(+), 1229 deletions(-) (limited to 'src/org/jetbrains/java/decompiler/code/cfg') diff --git a/src/org/jetbrains/java/decompiler/code/cfg/BasicBlock.java b/src/org/jetbrains/java/decompiler/code/cfg/BasicBlock.java index 917da08..f8bf793 100644 --- a/src/org/jetbrains/java/decompiler/code/cfg/BasicBlock.java +++ b/src/org/jetbrains/java/decompiler/code/cfg/BasicBlock.java @@ -1,265 +1,266 @@ /* - * 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.List; - import org.jetbrains.java.decompiler.code.Instruction; import org.jetbrains.java.decompiler.code.InstructionSequence; import org.jetbrains.java.decompiler.code.SimpleInstructionSequence; import org.jetbrains.java.decompiler.main.DecompilerContext; import org.jetbrains.java.decompiler.modules.decompiler.decompose.IGraphNode; +import java.util.ArrayList; +import java.util.List; + public class BasicBlock implements IGraphNode { - // ***************************************************************************** - // public fields - // ***************************************************************************** - - public int id = 0; - - public int mark = 0; - - // ***************************************************************************** - // private fields - // ***************************************************************************** - - private InstructionSequence seq = new SimpleInstructionSequence(); - - private List preds = new ArrayList(); - - private List succs = new ArrayList(); - - private List instrOldOffsets = new ArrayList(); - - private List predExceptions = new ArrayList(); - - private List succExceptions = new ArrayList(); - - - - public BasicBlock() {} - - public BasicBlock(int id) { - this.id = id; - } - - // ***************************************************************************** - // public methods - // ***************************************************************************** - - public Object clone() { - - BasicBlock block = new BasicBlock(); - block.id = id; - block.setSeq(seq.clone()); - block.setInstrOldOffsets(new ArrayList(instrOldOffsets)); - - return block; - } - - public void free() { - preds.clear(); - succs.clear(); - instrOldOffsets.clear(); - succExceptions.clear(); - seq = new SimpleInstructionSequence(); - } - - public Instruction getInstruction(int index) { - return seq.getInstr(index); - } - - public Instruction getLastInstruction() { - if(seq.isEmpty()) { - return null; - } else { - return seq.getLastInstr(); - } - } - - public int size() { - return seq.length(); - } - - public void addPredecessor(BasicBlock block) { - preds.add(block); - } - - public void removePredecessor(BasicBlock block) { - while(preds.remove(block)); - } - - public void addSuccessor(BasicBlock block) { - succs.add(block); - block.addPredecessor(this); - } - - public void removeSuccessor(BasicBlock block) { - while(succs.remove(block)); - block.removePredecessor(this); - } - - // FIXME: unify block comparisons: id or direkt equality - public void replaceSuccessor(BasicBlock oldBlock, BasicBlock newBlock) { - for(int i=0;i getInstrOldOffsets() { - return instrOldOffsets; - } - - public void setInstrOldOffsets(List instrInds) { - this.instrOldOffsets = instrInds; - } - - public List getPredecessors() { - List lst = new ArrayList(preds); - lst.addAll(predExceptions); - return lst; - } - - public List getPreds() { - return preds; - } - - public void setPreds(List preds) { - this.preds = preds; - } - - public InstructionSequence getSeq() { - return seq; - } - - public void setSeq(InstructionSequence seq) { - this.seq = seq; - } - - public List getSuccs() { - return succs; - } - - public void setSuccs(List succs) { - this.succs = succs; - } - - - public List getSuccExceptions() { - return succExceptions; - } - - - public void setSuccExceptions(List succExceptions) { - this.succExceptions = succExceptions; - } - - public List getPredExceptions() { - return predExceptions; - } - - public void setPredExceptions(List predExceptions) { - this.predExceptions = predExceptions; - } - - + // ***************************************************************************** + // public fields + // ***************************************************************************** + + public int id = 0; + + public int mark = 0; + + // ***************************************************************************** + // private fields + // ***************************************************************************** + + private InstructionSequence seq = new SimpleInstructionSequence(); + + private List preds = new ArrayList(); + + private List succs = new ArrayList(); + + private List instrOldOffsets = new ArrayList(); + + private List predExceptions = new ArrayList(); + + private List succExceptions = new ArrayList(); + + + public BasicBlock() { + } + + public BasicBlock(int id) { + this.id = id; + } + + // ***************************************************************************** + // public methods + // ***************************************************************************** + + public Object clone() { + + BasicBlock block = new BasicBlock(); + block.id = id; + block.setSeq(seq.clone()); + block.setInstrOldOffsets(new ArrayList(instrOldOffsets)); + + return block; + } + + public void free() { + preds.clear(); + succs.clear(); + instrOldOffsets.clear(); + succExceptions.clear(); + seq = new SimpleInstructionSequence(); + } + + public Instruction getInstruction(int index) { + return seq.getInstr(index); + } + + public Instruction getLastInstruction() { + if (seq.isEmpty()) { + return null; + } + else { + return seq.getLastInstr(); + } + } + + public int size() { + return seq.length(); + } + + public void addPredecessor(BasicBlock block) { + preds.add(block); + } + + public void removePredecessor(BasicBlock block) { + while (preds.remove(block)) ; + } + + public void addSuccessor(BasicBlock block) { + succs.add(block); + block.addPredecessor(this); + } + + public void removeSuccessor(BasicBlock block) { + while (succs.remove(block)) ; + block.removePredecessor(this); + } + + // FIXME: unify block comparisons: id or direkt equality + public void replaceSuccessor(BasicBlock oldBlock, BasicBlock newBlock) { + for (int i = 0; i < succs.size(); i++) { + if (succs.get(i).id == oldBlock.id) { + succs.set(i, newBlock); + oldBlock.removePredecessor(this); + newBlock.addPredecessor(this); + } + } + + for (int i = 0; i < succExceptions.size(); i++) { + if (succExceptions.get(i).id == oldBlock.id) { + succExceptions.set(i, newBlock); + oldBlock.removePredecessorException(this); + newBlock.addPredecessorException(this); + } + } + } + + public void addPredecessorException(BasicBlock block) { + predExceptions.add(block); + } + + public void removePredecessorException(BasicBlock block) { + while (predExceptions.remove(block)) ; + } + + public void addSuccessorException(BasicBlock block) { + if (!succExceptions.contains(block)) { + succExceptions.add(block); + block.addPredecessorException(this); + } + } + + public void removeSuccessorException(BasicBlock block) { + while (succExceptions.remove(block)) ; + block.removePredecessorException(this); + } + + public String toString() { + return toString(0); + } + + public String toString(int indent) { + + String new_line_separator = DecompilerContext.getNewLineSeparator(); + + return id + ":" + new_line_separator + seq.toString(indent); + } + + public String toStringOldIndices() { + + String new_line_separator = DecompilerContext.getNewLineSeparator(); + + StringBuffer buf = new StringBuffer(); + + for (int i = 0; i < seq.length(); i++) { + if (i < instrOldOffsets.size()) { + buf.append(instrOldOffsets.get(i)); + } + else { + buf.append("-1"); + } + buf.append(": "); + buf.append(seq.getInstr(i).toString()); + buf.append(new_line_separator); + } + + return buf.toString(); + } + + public boolean isSuccessor(BasicBlock block) { + for (BasicBlock succ : succs) { + if (succ.id == block.id) { + return true; + } + } + return false; + } + + public boolean isPredecessor(BasicBlock block) { + for (int i = 0; i < preds.size(); i++) { + if (preds.get(i).id == block.id) { + return true; + } + } + return false; + } + + // ***************************************************************************** + // getter and setter methods + // ***************************************************************************** + + public List getInstrOldOffsets() { + return instrOldOffsets; + } + + public void setInstrOldOffsets(List instrInds) { + this.instrOldOffsets = instrInds; + } + + public List getPredecessors() { + List lst = new ArrayList(preds); + lst.addAll(predExceptions); + return lst; + } + + public List getPreds() { + return preds; + } + + public void setPreds(List preds) { + this.preds = preds; + } + + public InstructionSequence getSeq() { + return seq; + } + + public void setSeq(InstructionSequence seq) { + this.seq = seq; + } + + public List getSuccs() { + return succs; + } + + public void setSuccs(List succs) { + this.succs = succs; + } + + + public List getSuccExceptions() { + return succExceptions; + } + + + public void setSuccExceptions(List succExceptions) { + this.succExceptions = succExceptions; + } + + public List getPredExceptions() { + return predExceptions; + } + + public void setPredExceptions(List predExceptions) { + this.predExceptions = predExceptions; + } } diff --git a/src/org/jetbrains/java/decompiler/code/cfg/ControlFlowGraph.java b/src/org/jetbrains/java/decompiler/code/cfg/ControlFlowGraph.java index 824e8af..6b0624f 100644 --- a/src/org/jetbrains/java/decompiler/code/cfg/ControlFlowGraph.java +++ b/src/org/jetbrains/java/decompiler/code/cfg/ControlFlowGraph.java @@ -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,846 +26,852 @@ 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; - - // ***************************************************************************** - // private fields - // ***************************************************************************** - - private VBStyleCollection blocks; - - private BasicBlock first; - - private BasicBlock last; - - private List exceptions; - - private HashMap subroutines; - - private HashSet finallyExits = new HashSet(); - - // ***************************************************************************** - // constructors - // ***************************************************************************** - - public ControlFlowGraph(InstructionSequence seq) { - buildBlocks(seq); - } - - - // ***************************************************************************** - // public methods - // ***************************************************************************** - - public void free() { - - for(BasicBlock block: blocks) { - block.free(); - } - - blocks.clear(); - first = null; - last = null; - exceptions.clear(); - finallyExits.clear(); - } - - public void removeMarkers() { - for(BasicBlock block: blocks) { - block.mark = 0; - } - } - - public String toString() { - - String new_line_separator = DecompilerContext.getNewLineSeparator(); - - StringBuffer buf = new StringBuffer(); - - for(BasicBlock block: blocks) { - buf.append("----- Block "+block.id+" -----" + new_line_separator); - buf.append(block.toString()); - buf.append("----- Edges -----" + new_line_separator); - - List suc = block.getSuccs(); - for(int j=0;j>>>>>>>(regular) Block "+((BasicBlock)suc.get(j)).id+new_line_separator); - } - suc = block.getSuccExceptions(); - for(int j=0;j>>>>>>>(exception) Block "+handler.id+"\t"+"ERROR: range not found!"+new_line_separator); - } else { - List 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); - } - } - } - } - buf.append("----- ----- -----" + new_line_separator); - - } - - return buf.toString(); - - } - - public void inlineJsr(StructMethod mt) { - processJsr(); - removeJsr(mt); - - removeMarkers(); - - DeadCodeHelper.removeEmptyBlocks(this); - } - - public void removeBlock(BasicBlock block) { - - while(block.getSuccs().size()>0) { - block.removeSuccessor((BasicBlock)block.getSuccs().get(0)); - } - - while(block.getSuccExceptions().size()>0) { - block.removeSuccessorException((BasicBlock)block.getSuccExceptions().get(0)); - } - - while(block.getPreds().size()>0) { - ((BasicBlock)block.getPreds().get(0)).removeSuccessor(block); - } - - while(block.getPredExceptions().size()>0) { - ((BasicBlock)block.getPredExceptions().get(0)).removeSuccessorException(block); - } - - last.removePredecessor(block); - - blocks.removeWithKey(block.id); - - for(int i=exceptions.size()-1;i>=0;i--) { - ExceptionRangeCFG range = (ExceptionRangeCFG)exceptions.get(i); - if(range.getHandler() == block) { - exceptions.remove(i); - } else { - List lstRange = range.getProtectedRange(); - lstRange.remove(block); - - if(lstRange.isEmpty()) { - exceptions.remove(i); - } - } - } - - Iterator> it = subroutines.entrySet().iterator(); - while(it.hasNext()) { - Entry ent = it.next(); - if(ent.getKey() == block || ent.getValue() == block) { - it.remove(); - } - } - - } - - public ExceptionRangeCFG getExceptionRange(BasicBlock handler, BasicBlock block) { - - //List ranges = new ArrayList(); - - for(int i=exceptions.size()-1;i>=0;i--) { - ExceptionRangeCFG range = exceptions.get(i); - if(range.getHandler() == handler && range.getProtectedRange().contains(block)) { - return range; - //ranges.add(range); - } - } - - return null; - //return ranges.isEmpty() ? null : ranges; - } - -// public String getExceptionsUniqueString(BasicBlock handler, BasicBlock block) { -// -// List ranges = getExceptionRange(handler, block); -// -// if(ranges == null) { -// return null; -// } else { -// Set setExceptionStrings = new HashSet(); -// for(ExceptionRangeCFG range : ranges) { -// setExceptionStrings.add(range.getExceptionType()); -// } -// -// String ret = ""; -// for(String exception : setExceptionStrings) { -// ret += exception; -// } -// -// return ret; -// } -// } - - - // ***************************************************************************** - // private methods - // ***************************************************************************** - - private void buildBlocks(InstructionSequence instrseq) { - - short[] states = findStartInstructions(instrseq); - - HashMap mapInstrBlocks = new HashMap(); - VBStyleCollection colBlocks = createBasicBlocks(states, instrseq, mapInstrBlocks); - - blocks = colBlocks; - - connectBlocks(colBlocks, mapInstrBlocks); - - setExceptionEdges(instrseq, mapInstrBlocks); - - setSubroutineEdges(); - - setFirstAndLastBlocks(); - } - - private short[] findStartInstructions(InstructionSequence seq) { - - int len = seq.length(); - short[] inststates = new short[len]; - - HashSet excSet = new HashSet(); - - 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=0;j--) { - inststates[dests[j]] = 1; - } - inststates[swinstr.getDefaultdest()] = 1; - if(i+1 < len) { - inststates[i+1] = 1; - } - } - } - - // first instruction - inststates[0] = 1; - - return inststates; - } - - - private VBStyleCollection createBasicBlocks(short[] startblock, InstructionSequence instrseq, - HashMap mapInstrBlocks) { - - VBStyleCollection col = new VBStyleCollection(); - - InstructionSequence currseq = null; - ArrayList lstOffs = null; - - int len = startblock.length; - short counter = 0; - int blockoffset = 0; - - BasicBlock currentBlock = null; - for(int i=0;i(); - - currentBlock.setSeq(currseq); - currentBlock.setInstrOldOffsets(lstOffs); - col.addWithKey(currentBlock, currentBlock.id); - - blockoffset = instrseq.getOffset(i); - } - - startblock[i] = counter; - mapInstrBlocks.put(i, currentBlock); - - currseq.addInstruction(instrseq.getInstr(i), instrseq.getOffset(i)-blockoffset); - lstOffs.add(instrseq.getOffset(i)); - } - - last_id = counter; - - return col; - } - - - private void connectBlocks(List lstbb, HashMap mapInstrBlocks) { - - for(int i=0;i instrBlocks) { - - exceptions = new ArrayList(); - - Map mapRanges = new HashMap(); - - for(ExceptionHandler handler : instrseq.getExceptionTable().getHandlers()) { - - BasicBlock from = instrBlocks.get(handler.from_instr); - BasicBlock to = instrBlocks.get(handler.to_instr); - BasicBlock handle = instrBlocks.get(handler.handler_instr); - - String key = from.id + ":" + to.id + ":" + handle.id; - - if(mapRanges.containsKey(key)) { - ExceptionRangeCFG range = mapRanges.get(key); - range.addExceptionType(handler.exceptionClass); - } else { - - List protectedRange = new ArrayList(); - for(int j=from.id;j subroutines = new HashMap(); - - for(BasicBlock block : blocks) { - - if(block.getSeq().getLastInstr().opcode == CodeConstants.opc_jsr) { - - LinkedList stack = new LinkedList(); - LinkedList> stackJsrStacks = new LinkedList>(); - - HashSet setVisited = new HashSet(); - - stack.add(block); - stackJsrStacks.add(new LinkedList()); - - while(!stack.isEmpty()) { - - BasicBlock node = stack.removeFirst(); - LinkedList jsrstack = stackJsrStacks.removeFirst(); - - setVisited.add(node); - - switch(node.getSeq().getLastInstr().opcode) { - case CodeConstants.opc_jsr: - jsrstack.add(node); - break; - case CodeConstants.opc_ret: - 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)) { - node.addSuccessor(exit); - } - jsrstack.removeLast(); - subroutines.put(enter, exit); - } else { - throw new RuntimeException("ERROR: last instruction jsr"); - } - } - - if(!jsrstack.isEmpty()) { - for(BasicBlock succ : node.getSuccs()) { - if(!setVisited.contains(succ)) { - stack.add(succ); - stackJsrStacks.add(new LinkedList(jsrstack)); - } - } - } - } - } - } - - this.subroutines = subroutines; - } - - private void processJsr() { - - while(processJsrRanges()!=0); - } - - private int processJsrRanges() { - - List lstJsrAll = new ArrayList(); - - // get all jsr ranges - for(Entry ent : subroutines.entrySet()){ - BasicBlock jsr = ent.getKey(); - BasicBlock ret = ent.getValue(); - - lstJsrAll.add(new Object[]{jsr, getJsrRange(jsr, ret), ret}); - } - - // sort ranges - // FIXME: better sort order - List lstJsr = new ArrayList(); - for(Object[] arr : lstJsrAll) { - int i=0; - for(;i)arrJsr[1]).contains(arr[0])) { - break; - } - } - - lstJsr.add(i, arr); - } - - // find the first intersection - for(int i=0;i set = (HashSet)arr[1]; - - for(int j=i+1;j set1 = (HashSet)arr1[1]; - - if(!set.contains(arr1[0]) && !set1.contains(arr[0])) { // rang 0 doesn't contain entry 1 and vice versa - HashSet setc = new HashSet(set); - setc.retainAll(set1); - - if(!setc.isEmpty()) { - splitJsrRange((BasicBlock)arr[0], (BasicBlock)arr[2], setc); - return 1; - } - } - } - } - - return 0; - } - - private HashSet getJsrRange(BasicBlock jsr, BasicBlock ret) { - - HashSet blocks = new HashSet(); - - LinkedList lstNodes = new LinkedList(); - lstNodes.add(jsr); - - BasicBlock dom = jsr.getSuccs().get(0); - - while(!lstNodes.isEmpty()) { - - BasicBlock node = lstNodes.remove(0); - - for(int j=0;j<2;j++) { - List lst; - if(j==0) { - if(node.getLastInstruction().opcode == CodeConstants.opc_ret) { - if(node.getSuccs().contains(ret)) { - continue; - } - } - lst = node.getSuccs(); - } else { - if(node == jsr) { - continue; - } - lst = node.getSuccExceptions(); - } - - CHILD: - for(int i=lst.size()-1;i>=0;i--) { - - BasicBlock child = lst.get(i); - if(!blocks.contains(child)) { - - if(node != jsr) { - for(int k=0;k common_blocks) { - - LinkedList lstNodes = new LinkedList(); - HashMap mapNewNodes = new HashMap(); - - lstNodes.add(jsr); - mapNewNodes.put(jsr.id, jsr); - - while(!lstNodes.isEmpty()) { - - BasicBlock node = lstNodes.remove(0); - - for(int j=0;j<2;j++) { - List lst; - if(j==0) { - if(node.getLastInstruction().opcode == CodeConstants.opc_ret) { - if(node.getSuccs().contains(ret)) { - continue; - } - } - lst = node.getSuccs(); - } else { - if(node == jsr) { - continue; - } - lst = node.getSuccExceptions(); - } - - - for(int i=lst.size()-1;i>=0;i--) { - - BasicBlock child = (BasicBlock)lst.get(i); - Integer childid = child.id; - - if(mapNewNodes.containsKey(childid)) { - node.replaceSuccessor(child, (BasicBlock)mapNewNodes.get(childid)); - } 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 && - child.getSuccs().contains(ret)) { - copy.addSuccessor(ret); - child.removeSuccessor(ret); - } else { - for(int k=0;k common_blocks, HashMap mapNewNodes) { - - for(int i=exceptions.size()-1;i>=0;i--) { - - ExceptionRangeCFG range = (ExceptionRangeCFG)exceptions.get(i); - List lstRange = range.getProtectedRange(); - - HashSet setBoth = new HashSet(common_blocks); - setBoth.retainAll(lstRange); - - if(setBoth.size()>0) { - List lstNewRange; - - if(setBoth.size()==lstRange.size()) { - lstNewRange = new ArrayList(); - ExceptionRangeCFG newRange = new ExceptionRangeCFG(lstNewRange, - (BasicBlock)mapNewNodes.get(range.getHandler().id),range.getExceptionTypes()); - exceptions.add(newRange); - } else { - lstNewRange = lstRange; - } - - for(BasicBlock block : setBoth) { - lstNewRange.add(mapNewNodes.get(block.id)); - } - } - } - - } - - private void removeJsr(StructMethod mt) { - removeJsrInstructions(mt.getClassStruct().getPool(), first, DataPoint.getInitialDataPoint(mt)); - } - - private void removeJsrInstructions(ConstantPool pool, BasicBlock block, DataPoint data) { - - ListStack stack = data.getStack(); - - InstructionSequence seq = block.getSeq(); - for(int i=0;i(data.getLocalVariables())); - point.getStack().push(new VarType(CodeConstants.TYPE_OBJECT, 0, null)); - - removeJsrInstructions(pool, suc, point); - } - } - - } - - private void setFirstAndLastBlocks() { - - first = blocks.get(0); - - last = new BasicBlock(); - last.id = ++last_id; - last.setSeq(new SimpleInstructionSequence()); - - for(BasicBlock block: blocks) { - if(block.getSuccs().isEmpty()) { - last.addPredecessor(block); - } - } - } - - public List getReversePostOrder() { - - LinkedList res = new LinkedList(); - addToReversePostOrderListIterative(first, res); - - return res; - } - - private void addToReversePostOrderListIterative(BasicBlock root, List lst) { - - LinkedList stackNode = new LinkedList(); - LinkedList stackIndex = new LinkedList(); - - HashSet setVisited = new HashSet(); - - stackNode.add(root); - stackIndex.add(0); - - while(!stackNode.isEmpty()) { - - BasicBlock node = stackNode.getLast(); - int index = stackIndex.removeLast(); - - setVisited.add(node); - - List lstSuccs = new ArrayList(node.getSuccs()); - lstSuccs.addAll(node.getSuccExceptions()); - - for(;index getBlocks() { - return blocks; - } - - public void setBlocks(VBStyleCollection blocks) { - this.blocks = blocks; - } - - public BasicBlock getFirst() { - return first; - } - - public void setFirst(BasicBlock first) { - this.first = first; - } - - public List getEndBlocks() { - return last.getPreds(); - } - - public List getExceptions() { - return exceptions; - } - - public void setExceptions(List exceptions) { - this.exceptions = exceptions; - } - - - public BasicBlock getLast() { - return last; - } - - - public void setLast(BasicBlock last) { - this.last = last; - } - - - public HashMap getSubroutines() { - return subroutines; - } - - - public void setSubroutines(HashMap subroutines) { - this.subroutines = subroutines; - } - - - public HashSet getFinallyExits() { - return finallyExits; - } - - - public void setFinallyExits(HashSet finallyExits) { - this.finallyExits = finallyExits; - } + public int last_id = 0; + + // ***************************************************************************** + // private fields + // ***************************************************************************** + + private VBStyleCollection blocks; + + private BasicBlock first; + + private BasicBlock last; + + private List exceptions; + + private HashMap subroutines; + + private HashSet finallyExits = new HashSet(); + + // ***************************************************************************** + // constructors + // ***************************************************************************** + + public ControlFlowGraph(InstructionSequence seq) { + buildBlocks(seq); + } + + + // ***************************************************************************** + // public methods + // ***************************************************************************** + + public void free() { + + for (BasicBlock block : blocks) { + block.free(); + } + + blocks.clear(); + first = null; + last = null; + exceptions.clear(); + finallyExits.clear(); + } + + public void removeMarkers() { + for (BasicBlock block : blocks) { + block.mark = 0; + } + } + + public String toString() { + + String new_line_separator = DecompilerContext.getNewLineSeparator(); + + StringBuffer buf = new StringBuffer(); + + for (BasicBlock block : blocks) { + buf.append("----- Block " + block.id + " -----" + new_line_separator); + buf.append(block.toString()); + buf.append("----- Edges -----" + new_line_separator); + + List suc = block.getSuccs(); + 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++) { + 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 { + List 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); + } + } + } + } + buf.append("----- ----- -----" + new_line_separator); + } + + return buf.toString(); + } + + public void inlineJsr(StructMethod mt) { + processJsr(); + removeJsr(mt); + + removeMarkers(); + + DeadCodeHelper.removeEmptyBlocks(this); + } + + public void removeBlock(BasicBlock block) { + + while (block.getSuccs().size() > 0) { + block.removeSuccessor((BasicBlock)block.getSuccs().get(0)); + } + + while (block.getSuccExceptions().size() > 0) { + block.removeSuccessorException((BasicBlock)block.getSuccExceptions().get(0)); + } + + while (block.getPreds().size() > 0) { + ((BasicBlock)block.getPreds().get(0)).removeSuccessor(block); + } + + while (block.getPredExceptions().size() > 0) { + ((BasicBlock)block.getPredExceptions().get(0)).removeSuccessorException(block); + } + + last.removePredecessor(block); + + blocks.removeWithKey(block.id); + + for (int i = exceptions.size() - 1; i >= 0; i--) { + ExceptionRangeCFG range = (ExceptionRangeCFG)exceptions.get(i); + if (range.getHandler() == block) { + exceptions.remove(i); + } + else { + List lstRange = range.getProtectedRange(); + lstRange.remove(block); + + if (lstRange.isEmpty()) { + exceptions.remove(i); + } + } + } + + Iterator> it = subroutines.entrySet().iterator(); + while (it.hasNext()) { + Entry ent = it.next(); + if (ent.getKey() == block || ent.getValue() == block) { + it.remove(); + } + } + } + + public ExceptionRangeCFG getExceptionRange(BasicBlock handler, BasicBlock block) { + + //List ranges = new ArrayList(); + + for (int i = exceptions.size() - 1; i >= 0; i--) { + ExceptionRangeCFG range = exceptions.get(i); + if (range.getHandler() == handler && range.getProtectedRange().contains(block)) { + return range; + //ranges.add(range); + } + } + + return null; + //return ranges.isEmpty() ? null : ranges; + } + + // public String getExceptionsUniqueString(BasicBlock handler, BasicBlock block) { + // + // List ranges = getExceptionRange(handler, block); + // + // if(ranges == null) { + // return null; + // } else { + // Set setExceptionStrings = new HashSet(); + // for(ExceptionRangeCFG range : ranges) { + // setExceptionStrings.add(range.getExceptionType()); + // } + // + // String ret = ""; + // for(String exception : setExceptionStrings) { + // ret += exception; + // } + // + // return ret; + // } + // } + + + // ***************************************************************************** + // private methods + // ***************************************************************************** + + private void buildBlocks(InstructionSequence instrseq) { + + short[] states = findStartInstructions(instrseq); + + HashMap mapInstrBlocks = new HashMap(); + VBStyleCollection colBlocks = createBasicBlocks(states, instrseq, mapInstrBlocks); + + blocks = colBlocks; + + connectBlocks(colBlocks, mapInstrBlocks); + + setExceptionEdges(instrseq, mapInstrBlocks); + + setSubroutineEdges(); + + setFirstAndLastBlocks(); + } + + private short[] findStartInstructions(InstructionSequence seq) { + + int len = seq.length(); + short[] inststates = new short[len]; + + HashSet excSet = new HashSet(); + + 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++) { + + // exception blocks + if (excSet.contains(new Integer(i))) { + inststates[i] = 1; + } + + Instruction instr = seq.getInstr(i); + switch (instr.group) { + case GROUP_JUMP: + inststates[((JumpInstruction)instr).destination] = 1; + case GROUP_RETURN: + 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--) { + inststates[dests[j]] = 1; + } + inststates[swinstr.getDefaultdest()] = 1; + if (i + 1 < len) { + inststates[i + 1] = 1; + } + } + } + + // first instruction + inststates[0] = 1; + + return inststates; + } + + + private VBStyleCollection createBasicBlocks(short[] startblock, InstructionSequence instrseq, + HashMap mapInstrBlocks) { + + VBStyleCollection col = new VBStyleCollection(); + + InstructionSequence currseq = null; + ArrayList lstOffs = null; + + int len = startblock.length; + short counter = 0; + int blockoffset = 0; + + BasicBlock currentBlock = null; + for (int i = 0; i < len; i++) { + + if (startblock[i] == 1) { + currentBlock = new BasicBlock(); + currentBlock.id = ++counter; + + currseq = new SimpleInstructionSequence(); + lstOffs = new ArrayList(); + + currentBlock.setSeq(currseq); + currentBlock.setInstrOldOffsets(lstOffs); + col.addWithKey(currentBlock, currentBlock.id); + + blockoffset = instrseq.getOffset(i); + } + + startblock[i] = counter; + mapInstrBlocks.put(i, currentBlock); + + currseq.addInstruction(instrseq.getInstr(i), instrseq.getOffset(i) - blockoffset); + lstOffs.add(instrseq.getOffset(i)); + } + + last_id = counter; + + return col; + } + + + private void connectBlocks(List lstbb, HashMap mapInstrBlocks) { + + for (int i = 0; i < lstbb.size(); i++) { + + BasicBlock block = lstbb.get(i); + Instruction instr = block.getLastInstruction(); + + boolean fallthrough = instr.canFallthrough(); + BasicBlock bTemp; + + switch (instr.group) { + case GROUP_JUMP: + int dest = ((JumpInstruction)instr).destination; + bTemp = mapInstrBlocks.get(dest); + block.addSuccessor(bTemp); + + break; + case GROUP_SWITCH: + SwitchInstruction sinstr = (SwitchInstruction)instr; + int[] dests = sinstr.getDestinations(); + + bTemp = mapInstrBlocks.get(((SwitchInstruction)instr).getDefaultdest()); + block.addSuccessor(bTemp); + 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); + block.addSuccessor(defaultBlock); + } + } + } + + private void setExceptionEdges(InstructionSequence instrseq, HashMap instrBlocks) { + + exceptions = new ArrayList(); + + Map mapRanges = new HashMap(); + + for (ExceptionHandler handler : instrseq.getExceptionTable().getHandlers()) { + + BasicBlock from = instrBlocks.get(handler.from_instr); + BasicBlock to = instrBlocks.get(handler.to_instr); + BasicBlock handle = instrBlocks.get(handler.handler_instr); + + String key = from.id + ":" + to.id + ":" + handle.id; + + if (mapRanges.containsKey(key)) { + ExceptionRangeCFG range = mapRanges.get(key); + range.addExceptionType(handler.exceptionClass); + } + else { + + List protectedRange = new ArrayList(); + 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})); + mapRanges.put(key, range); + + exceptions.add(range); + } + } + } + + private void setSubroutineEdges() { + + final HashMap subroutines = new HashMap(); + + for (BasicBlock block : blocks) { + + if (block.getSeq().getLastInstr().opcode == CodeConstants.opc_jsr) { + + LinkedList stack = new LinkedList(); + LinkedList> stackJsrStacks = new LinkedList>(); + + HashSet setVisited = new HashSet(); + + stack.add(block); + stackJsrStacks.add(new LinkedList()); + + while (!stack.isEmpty()) { + + BasicBlock node = stack.removeFirst(); + LinkedList jsrstack = stackJsrStacks.removeFirst(); + + setVisited.add(node); + + switch (node.getSeq().getLastInstr().opcode) { + case CodeConstants.opc_jsr: + jsrstack.add(node); + break; + case CodeConstants.opc_ret: + 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)) { + node.addSuccessor(exit); + } + jsrstack.removeLast(); + subroutines.put(enter, exit); + } + else { + throw new RuntimeException("ERROR: last instruction jsr"); + } + } + + if (!jsrstack.isEmpty()) { + for (BasicBlock succ : node.getSuccs()) { + if (!setVisited.contains(succ)) { + stack.add(succ); + stackJsrStacks.add(new LinkedList(jsrstack)); + } + } + } + } + } + } + + this.subroutines = subroutines; + } + + private void processJsr() { + + while (processJsrRanges() != 0) ; + } + + private int processJsrRanges() { + + List lstJsrAll = new ArrayList(); + + // get all jsr ranges + for (Entry ent : subroutines.entrySet()) { + BasicBlock jsr = ent.getKey(); + BasicBlock ret = ent.getValue(); + + lstJsrAll.add(new Object[]{jsr, getJsrRange(jsr, ret), ret}); + } + + // sort ranges + // FIXME: better sort order + List lstJsr = new ArrayList(); + for (Object[] arr : lstJsrAll) { + int i = 0; + for (; i < lstJsr.size(); i++) { + Object[] arrJsr = lstJsr.get(i); + + if (((HashSet)arrJsr[1]).contains(arr[0])) { + break; + } + } + + lstJsr.add(i, arr); + } + + // find the first intersection + for (int i = 0; i < lstJsr.size(); i++) { + Object[] arr = (Object[])lstJsr.get(i); + HashSet set = (HashSet)arr[1]; + + for (int j = i + 1; j < lstJsr.size(); j++) { + Object[] arr1 = (Object[])lstJsr.get(j); + HashSet set1 = (HashSet)arr1[1]; + + if (!set.contains(arr1[0]) && !set1.contains(arr[0])) { // rang 0 doesn't contain entry 1 and vice versa + HashSet setc = new HashSet(set); + setc.retainAll(set1); + + if (!setc.isEmpty()) { + splitJsrRange((BasicBlock)arr[0], (BasicBlock)arr[2], setc); + return 1; + } + } + } + } + + return 0; + } + + private HashSet getJsrRange(BasicBlock jsr, BasicBlock ret) { + + HashSet blocks = new HashSet(); + + LinkedList lstNodes = new LinkedList(); + lstNodes.add(jsr); + + BasicBlock dom = jsr.getSuccs().get(0); + + while (!lstNodes.isEmpty()) { + + BasicBlock node = lstNodes.remove(0); + + for (int j = 0; j < 2; j++) { + List lst; + if (j == 0) { + if (node.getLastInstruction().opcode == CodeConstants.opc_ret) { + if (node.getSuccs().contains(ret)) { + continue; + } + } + lst = node.getSuccs(); + } + else { + if (node == jsr) { + continue; + } + lst = node.getSuccExceptions(); + } + + CHILD: + for (int i = lst.size() - 1; i >= 0; i--) { + + BasicBlock child = lst.get(i); + 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)) { + continue CHILD; + } + } + + 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) { + blocks.add(child); + } + + lstNodes.add(child); + } + } + } + } + + return blocks; + } + + private void splitJsrRange(BasicBlock jsr, BasicBlock ret, HashSet common_blocks) { + + LinkedList lstNodes = new LinkedList(); + HashMap mapNewNodes = new HashMap(); + + lstNodes.add(jsr); + mapNewNodes.put(jsr.id, jsr); + + while (!lstNodes.isEmpty()) { + + BasicBlock node = lstNodes.remove(0); + + for (int j = 0; j < 2; j++) { + List lst; + if (j == 0) { + if (node.getLastInstruction().opcode == CodeConstants.opc_ret) { + if (node.getSuccs().contains(ret)) { + continue; + } + } + lst = node.getSuccs(); + } + else { + if (node == jsr) { + continue; + } + lst = node.getSuccExceptions(); + } + + + for (int i = lst.size() - 1; i >= 0; i--) { + + BasicBlock child = (BasicBlock)lst.get(i); + Integer childid = child.id; + + if (mapNewNodes.containsKey(childid)) { + node.replaceSuccessor(child, (BasicBlock)mapNewNodes.get(childid)); + } + 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 && + child.getSuccs().contains(ret)) { + copy.addSuccessor(ret); + child.removeSuccessor(ret); + } + 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++) { + copy.addSuccessorException((BasicBlock)child.getSuccExceptions().get(k)); + } + + lstNodes.add(copy); + mapNewNodes.put(childid, copy); + + if (last.getPreds().contains(child)) { + last.addPredecessor(copy); + } + + node.replaceSuccessor(child, copy); + blocks.addWithKey(copy, copy.id); + } + else { + // stop at the first fixed node + //lstNodes.add(child); + mapNewNodes.put(childid, child); + } + } + } + } + + // note: subroutines won't be copied! + splitJsrExceptionRanges(common_blocks, mapNewNodes); + } + + private void splitJsrExceptionRanges(HashSet common_blocks, HashMap mapNewNodes) { + + for (int i = exceptions.size() - 1; i >= 0; i--) { + + ExceptionRangeCFG range = (ExceptionRangeCFG)exceptions.get(i); + List lstRange = range.getProtectedRange(); + + HashSet setBoth = new HashSet(common_blocks); + setBoth.retainAll(lstRange); + + if (setBoth.size() > 0) { + List lstNewRange; + + if (setBoth.size() == lstRange.size()) { + lstNewRange = new ArrayList(); + ExceptionRangeCFG newRange = new ExceptionRangeCFG(lstNewRange, + (BasicBlock)mapNewNodes.get(range.getHandler().id), range.getExceptionTypes()); + exceptions.add(newRange); + } + else { + lstNewRange = lstRange; + } + + for (BasicBlock block : setBoth) { + lstNewRange.add(mapNewNodes.get(block.id)); + } + } + } + } + + private void removeJsr(StructMethod mt) { + removeJsrInstructions(mt.getClassStruct().getPool(), first, DataPoint.getInitialDataPoint(mt)); + } + + private void removeJsrInstructions(ConstantPool pool, BasicBlock block, DataPoint data) { + + ListStack stack = data.getStack(); + + InstructionSequence seq = block.getSeq(); + 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) { + var = stack.getByOffset(-1); + } + + InstructionImpact.stepTypes(data, instr, pool); + + switch (instr.opcode) { + case CodeConstants.opc_jsr: + case CodeConstants.opc_ret: + seq.removeInstruction(i); + i--; + break; + case CodeConstants.opc_astore: + case CodeConstants.opc_pop: + if (var.type == CodeConstants.TYPE_ADDRESS) { + seq.removeInstruction(i); + i--; + } + } + } + + block.mark = 1; + + for (int i = 0; i < block.getSuccs().size(); i++) { + BasicBlock suc = (BasicBlock)block.getSuccs().get(i); + if (suc.mark != 1) { + removeJsrInstructions(pool, suc, data.copy()); + } + } + + for (int i = 0; i < block.getSuccExceptions().size(); i++) { + BasicBlock suc = (BasicBlock)block.getSuccExceptions().get(i); + if (suc.mark != 1) { + + DataPoint point = new DataPoint(); + point.setLocalVariables(new ArrayList(data.getLocalVariables())); + point.getStack().push(new VarType(CodeConstants.TYPE_OBJECT, 0, null)); + + removeJsrInstructions(pool, suc, point); + } + } + } + + private void setFirstAndLastBlocks() { + + first = blocks.get(0); + + last = new BasicBlock(); + last.id = ++last_id; + last.setSeq(new SimpleInstructionSequence()); + + for (BasicBlock block : blocks) { + if (block.getSuccs().isEmpty()) { + last.addPredecessor(block); + } + } + } + + public List getReversePostOrder() { + + LinkedList res = new LinkedList(); + addToReversePostOrderListIterative(first, res); + + return res; + } + + private void addToReversePostOrderListIterative(BasicBlock root, List lst) { + + LinkedList stackNode = new LinkedList(); + LinkedList stackIndex = new LinkedList(); + + HashSet setVisited = new HashSet(); + + stackNode.add(root); + stackIndex.add(0); + + while (!stackNode.isEmpty()) { + + BasicBlock node = stackNode.getLast(); + int index = stackIndex.removeLast(); + + setVisited.add(node); + + List lstSuccs = new ArrayList(node.getSuccs()); + lstSuccs.addAll(node.getSuccExceptions()); + + for (; index < lstSuccs.size(); index++) { + BasicBlock succ = lstSuccs.get(index); + + if (!setVisited.contains(succ)) { + stackIndex.add(index + 1); + + stackNode.add(succ); + stackIndex.add(0); + + break; + } + } + + if (index == lstSuccs.size()) { + lst.add(0, node); + + stackNode.removeLast(); + } + } + } + + + // ***************************************************************************** + // getter and setter methods + // ***************************************************************************** + + public VBStyleCollection getBlocks() { + return blocks; + } + + public void setBlocks(VBStyleCollection blocks) { + this.blocks = blocks; + } + + public BasicBlock getFirst() { + return first; + } + + public void setFirst(BasicBlock first) { + this.first = first; + } + + public List getEndBlocks() { + return last.getPreds(); + } + + public List getExceptions() { + return exceptions; + } + + public void setExceptions(List exceptions) { + this.exceptions = exceptions; + } + + + public BasicBlock getLast() { + return last; + } + + + public void setLast(BasicBlock last) { + this.last = last; + } + + + public HashMap getSubroutines() { + return subroutines; + } + + + public void setSubroutines(HashMap subroutines) { + this.subroutines = subroutines; + } + + + public HashSet getFinallyExits() { + return finallyExits; + } + + public void setFinallyExits(HashSet finallyExits) { + this.finallyExits = finallyExits; + } } diff --git a/src/org/jetbrains/java/decompiler/code/cfg/ExceptionRangeCFG.java b/src/org/jetbrains/java/decompiler/code/cfg/ExceptionRangeCFG.java index 53f4a77..7d83ef6 100644 --- a/src/org/jetbrains/java/decompiler/code/cfg/ExceptionRangeCFG.java +++ b/src/org/jetbrains/java/decompiler/code/cfg/ExceptionRangeCFG.java @@ -1,128 +1,129 @@ /* - * 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 org.jetbrains.java.decompiler.main.DecompilerContext; + import java.util.ArrayList; import java.util.HashSet; import java.util.List; import java.util.Set; -import org.jetbrains.java.decompiler.main.DecompilerContext; - public class ExceptionRangeCFG { - - private List protectedRange = new ArrayList(); // FIXME: replace with set - - private BasicBlock handler; - - private List exceptionTypes; - - public ExceptionRangeCFG(List protectedRange, BasicBlock handler, List exceptionType) { - this.protectedRange = protectedRange; - this.handler = handler; - - if(exceptionType != null) { - this.exceptionTypes = new ArrayList(exceptionType); - } - } - - public boolean isCircular() { - return protectedRange.contains(handler); - } - - public String toString() { - - String new_line_separator = DecompilerContext.getNewLineSeparator(); - - StringBuffer buf = new StringBuffer(); - - buf.append("exceptionType:"); - for(String exception_type : exceptionTypes) { - buf.append(" "+exception_type); - } - buf.append(new_line_separator); - - buf.append("handler: "+handler.id+new_line_separator); - buf.append("range: "); - for(int i=0;i getProtectedRange() { - return protectedRange; - } - - public void setProtectedRange(List protectedRange) { - this.protectedRange = protectedRange; - } - - public List getExceptionTypes() { - return this.exceptionTypes; - } - - public void addExceptionType(String exceptionType) { - - if(this.exceptionTypes == null) { - return; - } - - if(exceptionType == null) { - this.exceptionTypes = null; - } else { - this.exceptionTypes.add(exceptionType); - } - } - - public String getUniqueExceptionsString() { - - if(exceptionTypes == null) { - return null; - } - - Set setExceptionStrings = new HashSet(); - - for(String exceptionType : exceptionTypes) { // normalize order - setExceptionStrings.add(exceptionType); - } - - String ret = ""; - for(String exception : setExceptionStrings) { - if(!ret.isEmpty()) { - ret += ":"; - } - ret += exception; - } - - return ret; - } - - -// public void setExceptionType(String exceptionType) { -// this.exceptionType = exceptionType; -// } - + + private List protectedRange = new ArrayList(); // FIXME: replace with set + + private BasicBlock handler; + + private List exceptionTypes; + + public ExceptionRangeCFG(List protectedRange, BasicBlock handler, List exceptionType) { + this.protectedRange = protectedRange; + this.handler = handler; + + if (exceptionType != null) { + this.exceptionTypes = new ArrayList(exceptionType); + } + } + + public boolean isCircular() { + return protectedRange.contains(handler); + } + + public String toString() { + + String new_line_separator = DecompilerContext.getNewLineSeparator(); + + StringBuffer buf = new StringBuffer(); + + buf.append("exceptionType:"); + for (String exception_type : exceptionTypes) { + buf.append(" " + exception_type); + } + buf.append(new_line_separator); + + buf.append("handler: " + handler.id + new_line_separator); + buf.append("range: "); + for (int i = 0; i < protectedRange.size(); i++) { + buf.append(protectedRange.get(i).id + " "); + } + buf.append(new_line_separator); + + return buf.toString(); + } + + public BasicBlock getHandler() { + return handler; + } + + public void setHandler(BasicBlock handler) { + this.handler = handler; + } + + public List getProtectedRange() { + return protectedRange; + } + + public void setProtectedRange(List protectedRange) { + this.protectedRange = protectedRange; + } + + public List getExceptionTypes() { + return this.exceptionTypes; + } + + public void addExceptionType(String exceptionType) { + + if (this.exceptionTypes == null) { + return; + } + + if (exceptionType == null) { + this.exceptionTypes = null; + } + else { + this.exceptionTypes.add(exceptionType); + } + } + + public String getUniqueExceptionsString() { + + if (exceptionTypes == null) { + return null; + } + + Set setExceptionStrings = new HashSet(); + + for (String exceptionType : exceptionTypes) { // normalize order + setExceptionStrings.add(exceptionType); + } + + String ret = ""; + for (String exception : setExceptionStrings) { + if (!ret.isEmpty()) { + ret += ":"; + } + ret += exception; + } + + return ret; + } + + + // public void setExceptionType(String exceptionType) { + // this.exceptionType = exceptionType; + // } } -- cgit v1.2.3