diff options
author | Roman Shevchenko <roman.shevchenko@jetbrains.com> | 2014-08-28 21:34:14 +0400 |
---|---|---|
committer | Roman Shevchenko <roman.shevchenko@jetbrains.com> | 2014-08-28 21:34:19 +0400 |
commit | 076e4393f25bf1ad1ff1bd2853153e2b595dd90b (patch) | |
tree | f1a17a12ea762525b5efbc0778b0945d906c68c9 /src/org/jetbrains/java/decompiler/modules/code | |
parent | 663631f0456fcc245dd835889f86541d75161c53 (diff) | |
download | fernflower-076e4393f25bf1ad1ff1bd2853153e2b595dd90b.tar fernflower-076e4393f25bf1ad1ff1bd2853153e2b595dd90b.tar.gz fernflower-076e4393f25bf1ad1ff1bd2853153e2b595dd90b.tar.lz fernflower-076e4393f25bf1ad1ff1bd2853153e2b595dd90b.tar.xz fernflower-076e4393f25bf1ad1ff1bd2853153e2b595dd90b.zip |
java-decompiler: post-import cleanup (formatting and copyright)
Diffstat (limited to 'src/org/jetbrains/java/decompiler/modules/code')
-rw-r--r-- | src/org/jetbrains/java/decompiler/modules/code/DeadCodeHelper.java | 839 |
1 files changed, 420 insertions, 419 deletions
diff --git a/src/org/jetbrains/java/decompiler/modules/code/DeadCodeHelper.java b/src/org/jetbrains/java/decompiler/modules/code/DeadCodeHelper.java index 4d39e68..386f6ae 100644 --- a/src/org/jetbrains/java/decompiler/modules/code/DeadCodeHelper.java +++ b/src/org/jetbrains/java/decompiler/modules/code/DeadCodeHelper.java @@ -1,24 +1,20 @@ /* - * 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.modules.code; -import java.util.ArrayList; -import java.util.HashSet; -import java.util.LinkedList; -import java.util.List; - import org.jetbrains.java.decompiler.code.CodeConstants; import org.jetbrains.java.decompiler.code.Instruction; import org.jetbrains.java.decompiler.code.InstructionSequence; @@ -28,411 +24,416 @@ import org.jetbrains.java.decompiler.code.cfg.ExceptionRangeCFG; import org.jetbrains.java.decompiler.main.DecompilerContext; import org.jetbrains.java.decompiler.main.extern.IFernflowerPreferences; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.LinkedList; +import java.util.List; + public class DeadCodeHelper { - public static void removeDeadBlocks(ControlFlowGraph graph) { - - LinkedList<BasicBlock> stack = new LinkedList<BasicBlock>(); - HashSet<BasicBlock> setStacked = new HashSet<BasicBlock>(); - - stack.add(graph.getFirst()); - setStacked.add(graph.getFirst()); - - while(!stack.isEmpty()) { - BasicBlock block = stack.removeFirst(); - - List<BasicBlock> lstSuccs = new ArrayList<BasicBlock>(block.getSuccs()); - lstSuccs.addAll(block.getSuccExceptions()); - - for(BasicBlock succ : lstSuccs) { - if(!setStacked.contains(succ)) { - stack.add(succ); - setStacked.add(succ); - } - } - } - - HashSet<BasicBlock> setAllBlocks = new HashSet<BasicBlock>(graph.getBlocks()); - setAllBlocks.removeAll(setStacked); - - for(BasicBlock block : setAllBlocks) { - graph.removeBlock(block); - } - } - - public static void removeEmptyBlocks(ControlFlowGraph graph) { - - List<BasicBlock> blocks = graph.getBlocks(); - - boolean cont; - do { - cont = false; - - for(int i=blocks.size()-1;i>=0;i--) { - BasicBlock block = (BasicBlock)blocks.get(i); - - if(removeEmptyBlock(graph, block, false)) { - cont = true; - break; - } - } - - } while(cont); - } - - private static boolean removeEmptyBlock(ControlFlowGraph graph, BasicBlock block, boolean merging) { - - boolean deletedRanges = false; - - if(block.getSeq().isEmpty()) { - - if(block.getSuccs().size() > 1) { - if(block.getPreds().size()>1) { - // ambiguous block - throw new RuntimeException("ERROR: empty block with multiple predecessors and successors found"); - } else if(!merging) { - throw new RuntimeException("ERROR: empty block with multiple successors found"); - } - } - - HashSet<BasicBlock> setExits = new HashSet<BasicBlock>(graph.getLast().getPreds()); - - if(block.getPredExceptions().isEmpty() && - (!setExits.contains(block) || block.getPreds().size() == 1)) { - - if(setExits.contains(block)) { - BasicBlock pred = block.getPreds().get(0); - - // FIXME: flag in the basic block - if(pred.getSuccs().size() != 1 || (!pred.getSeq().isEmpty() - && pred.getSeq().getLastInstr().group == CodeConstants.GROUP_SWITCH)) { - return false; - } - } - - HashSet<BasicBlock> setPreds = new HashSet<BasicBlock>(block.getPreds()); - HashSet<BasicBlock> setSuccs = new HashSet<BasicBlock>(block.getSuccs()); - - // collect common exception ranges of predecessors and successors - HashSet<BasicBlock> setCommonExceptionHandlers = null; - for(int i = 0; i < 2; ++i) { - for(BasicBlock pred : i == 0 ? setPreds : setSuccs) { - if(setCommonExceptionHandlers == null) { - setCommonExceptionHandlers = new HashSet<BasicBlock>(pred.getSuccExceptions()); - } else { - setCommonExceptionHandlers.retainAll(pred.getSuccExceptions()); - } - } - } - - // check the block to be in each of the common ranges - if(setCommonExceptionHandlers != null && !setCommonExceptionHandlers.isEmpty()) { - for(BasicBlock handler : setCommonExceptionHandlers) { - if(!block.getSuccExceptions().contains(handler)) { - return false; - } - } - } - - // remove ranges consisting of this one block - List<ExceptionRangeCFG> lstRanges = graph.getExceptions(); - for(int i=lstRanges.size()-1;i>=0;i--) { - ExceptionRangeCFG range = lstRanges.get(i); - List<BasicBlock> lst = range.getProtectedRange(); - - if(lst.size() == 1 && lst.get(0) == block) { - if(DecompilerContext.getOption(IFernflowerPreferences.REMOVE_EMPTY_RANGES)) { - block.removeSuccessorException(range.getHandler()); - lstRanges.remove(i); - - deletedRanges = true; - } else { - return false; - } - } - } - - - // connect remaining nodes - if(merging) { - BasicBlock pred = block.getPreds().get(0); - pred.removeSuccessor(block); - - List<BasicBlock> lstSuccs = new ArrayList<BasicBlock>(block.getSuccs()); - for(BasicBlock succ : lstSuccs) { - block.removeSuccessor(succ); - pred.addSuccessor(succ); - } - - } else { - for(BasicBlock pred : setPreds) { - for(BasicBlock succ : setSuccs) { - pred.replaceSuccessor(block, succ); - } - } - } - - // finally exit edges - HashSet<BasicBlock> setFinallyExits = graph.getFinallyExits(); - if(setFinallyExits.contains(block)) { - setFinallyExits.remove(block); - setFinallyExits.add(setPreds.iterator().next()); - } - - // replace first if necessary - if(graph.getFirst() == block) { - if(setSuccs.size() != 1) { - throw new RuntimeException("multiple or no entry blocks!"); - } else { - graph.setFirst(setSuccs.iterator().next()); - } - } - - // remove this block - graph.removeBlock(block); - - if(deletedRanges) { - DeadCodeHelper.removeDeadBlocks(graph); - } - } - } - - return deletedRanges; - } - - - public static boolean isDominator(ControlFlowGraph graph, BasicBlock block, BasicBlock dom) { - - HashSet<BasicBlock> marked = new HashSet<BasicBlock>(); - - if(block == dom) { - return true; - } - - LinkedList<BasicBlock> lstNodes = new LinkedList<BasicBlock>(); - lstNodes.add(block); - - while(!lstNodes.isEmpty()) { - - BasicBlock node = (BasicBlock)lstNodes.remove(0); - if(marked.contains(node)) { - continue; - } else { - marked.add(node); - } - - if(node == graph.getFirst()) { - return false; - } - - for(int i=0;i<node.getPreds().size();i++) { - BasicBlock pred = (BasicBlock)node.getPreds().get(i); - if(!marked.contains(pred) && pred != dom) { - lstNodes.add(pred); - } - } - - for(int i=0;i<node.getPredExceptions().size();i++) { - BasicBlock pred = (BasicBlock)node.getPredExceptions().get(i); - if(!marked.contains(pred) && pred != dom) { - lstNodes.add(pred); - } - } - } - - return true; - } - - public static void removeGotos(ControlFlowGraph graph) { - - for(BasicBlock block : graph.getBlocks()) { - Instruction instr = block.getLastInstruction(); - - if(instr!=null && instr.opcode == CodeConstants.opc_goto) { - block.getSeq().removeInstruction(block.getSeq().length()-1); - } - } - - DeadCodeHelper.removeEmptyBlocks(graph); - } - - public static void connectDummyExitBlock(ControlFlowGraph graph) { - - BasicBlock exit = graph.getLast(); - for(BasicBlock block : new HashSet<BasicBlock>(exit.getPreds())) { - exit.removePredecessor(block); - block.addSuccessor(exit); - } - } - - public static void incorporateValueReturns(ControlFlowGraph graph) { - - for(BasicBlock block: graph.getBlocks()) { - InstructionSequence seq = block.getSeq(); - - int len = seq.length(); - if(len > 0 && len < 3) { - - boolean ok = false; - - if(seq.getLastInstr().opcode >= CodeConstants.opc_ireturn && seq.getLastInstr().opcode <= CodeConstants.opc_return) { - if(len == 1) { - ok = true; - } else if(seq.getLastInstr().opcode != CodeConstants.opc_return){ - switch(seq.getInstr(0).opcode) { - case CodeConstants.opc_iload: - case CodeConstants.opc_lload: - case CodeConstants.opc_fload: - case CodeConstants.opc_dload: - case CodeConstants.opc_aload: - case CodeConstants.opc_aconst_null: - case CodeConstants.opc_bipush: - case CodeConstants.opc_sipush: - case CodeConstants.opc_lconst_0: - case CodeConstants.opc_lconst_1: - case CodeConstants.opc_fconst_0: - case CodeConstants.opc_fconst_1: - case CodeConstants.opc_fconst_2: - case CodeConstants.opc_dconst_0: - case CodeConstants.opc_dconst_1: - case CodeConstants.opc_ldc: - case CodeConstants.opc_ldc_w: - case CodeConstants.opc_ldc2_w: - ok = true; - } - } - } - - if(ok) { - - if(!block.getPreds().isEmpty()) { - - HashSet<BasicBlock> setPredHandlersUnion = new HashSet<BasicBlock>(); - HashSet<BasicBlock> setPredHandlersIntersection = new HashSet<BasicBlock>(); - - boolean firstpred = true; - for(BasicBlock pred : block.getPreds()) { - if(firstpred) { - setPredHandlersIntersection.addAll(pred.getSuccExceptions()); - firstpred = false; - } else { - setPredHandlersIntersection.retainAll(pred.getSuccExceptions()); - } - - setPredHandlersUnion.addAll(pred.getSuccExceptions()); - } - - // add exception ranges from predecessors - setPredHandlersIntersection.removeAll(block.getSuccExceptions()); - BasicBlock predecessor = block.getPreds().get(0); - - for(BasicBlock handler : setPredHandlersIntersection) { - ExceptionRangeCFG range = graph.getExceptionRange(handler, predecessor); - - range.getProtectedRange().add(block); - block.addSuccessorException(handler); - } - - // remove redundant ranges - HashSet<BasicBlock> setRangesToBeRemoved = new HashSet<BasicBlock>(block.getSuccExceptions()); - setRangesToBeRemoved.removeAll(setPredHandlersUnion); - - for(BasicBlock handler : setRangesToBeRemoved) { - ExceptionRangeCFG range = graph.getExceptionRange(handler, block); - - if(range.getProtectedRange().size() > 1) { - range.getProtectedRange().remove(block); - block.removeSuccessorException(handler); - } - } - } - - - if(block.getPreds().size() == 1 && block.getPredExceptions().isEmpty()) { - - BasicBlock bpred = block.getPreds().get(0); - if(bpred.getSuccs().size() == 1) { - - // add exception ranges of predecessor - for(BasicBlock succ : bpred.getSuccExceptions()) { - if(!block.getSuccExceptions().contains(succ)) { - ExceptionRangeCFG range = graph.getExceptionRange(succ, bpred); - - range.getProtectedRange().add(block); - block.addSuccessorException(succ); - } - } - - // remove superfluous ranges from successors - for(BasicBlock succ : new HashSet<BasicBlock>(block.getSuccExceptions())) { - if(!bpred.getSuccExceptions().contains(succ)) { - ExceptionRangeCFG range = graph.getExceptionRange(succ, block); - - if(range.getProtectedRange().size() > 1) { - range.getProtectedRange().remove(block); - block.removeSuccessorException(succ); - } - } - } - } - } - - } - } - - } - - } - - - public static void mergeBasicBlocks(ControlFlowGraph graph) { - - for(;;) { - - boolean merged = false; - - for(BasicBlock block: graph.getBlocks()) { - - InstructionSequence seq = block.getSeq(); - - if(block.getSuccs().size() == 1) { - BasicBlock next = block.getSuccs().get(0); - - if(next != graph.getLast() && (seq.isEmpty() || seq.getLastInstr().group != CodeConstants.GROUP_SWITCH)) { - - if(next.getPreds().size() == 1 && next.getPredExceptions().isEmpty() - && next != graph.getFirst()) { - // TODO: implement a dummy start block - boolean sameRanges = true; - for(ExceptionRangeCFG range : graph.getExceptions()) { - if(range.getProtectedRange().contains(block) ^ - range.getProtectedRange().contains(next)) { - sameRanges = false; - break; - } - } - - if(sameRanges) { - seq.addSequence(next.getSeq()); - next.getSeq().clear(); - - removeEmptyBlock(graph, next, true); - - merged = true; - break; - } - } - } - } - - } - - if(!merged) { - break; - } - } - - } - - + public static void removeDeadBlocks(ControlFlowGraph graph) { + + LinkedList<BasicBlock> stack = new LinkedList<BasicBlock>(); + HashSet<BasicBlock> setStacked = new HashSet<BasicBlock>(); + + stack.add(graph.getFirst()); + setStacked.add(graph.getFirst()); + + while (!stack.isEmpty()) { + BasicBlock block = stack.removeFirst(); + + List<BasicBlock> lstSuccs = new ArrayList<BasicBlock>(block.getSuccs()); + lstSuccs.addAll(block.getSuccExceptions()); + + for (BasicBlock succ : lstSuccs) { + if (!setStacked.contains(succ)) { + stack.add(succ); + setStacked.add(succ); + } + } + } + + HashSet<BasicBlock> setAllBlocks = new HashSet<BasicBlock>(graph.getBlocks()); + setAllBlocks.removeAll(setStacked); + + for (BasicBlock block : setAllBlocks) { + graph.removeBlock(block); + } + } + + public static void removeEmptyBlocks(ControlFlowGraph graph) { + + List<BasicBlock> blocks = graph.getBlocks(); + + boolean cont; + do { + cont = false; + + for (int i = blocks.size() - 1; i >= 0; i--) { + BasicBlock block = (BasicBlock)blocks.get(i); + + if (removeEmptyBlock(graph, block, false)) { + cont = true; + break; + } + } + } + while (cont); + } + + private static boolean removeEmptyBlock(ControlFlowGraph graph, BasicBlock block, boolean merging) { + + boolean deletedRanges = false; + + if (block.getSeq().isEmpty()) { + + if (block.getSuccs().size() > 1) { + if (block.getPreds().size() > 1) { + // ambiguous block + throw new RuntimeException("ERROR: empty block with multiple predecessors and successors found"); + } + else if (!merging) { + throw new RuntimeException("ERROR: empty block with multiple successors found"); + } + } + + HashSet<BasicBlock> setExits = new HashSet<BasicBlock>(graph.getLast().getPreds()); + + if (block.getPredExceptions().isEmpty() && + (!setExits.contains(block) || block.getPreds().size() == 1)) { + + if (setExits.contains(block)) { + BasicBlock pred = block.getPreds().get(0); + + // FIXME: flag in the basic block + if (pred.getSuccs().size() != 1 || (!pred.getSeq().isEmpty() + && pred.getSeq().getLastInstr().group == CodeConstants.GROUP_SWITCH)) { + return false; + } + } + + HashSet<BasicBlock> setPreds = new HashSet<BasicBlock>(block.getPreds()); + HashSet<BasicBlock> setSuccs = new HashSet<BasicBlock>(block.getSuccs()); + + // collect common exception ranges of predecessors and successors + HashSet<BasicBlock> setCommonExceptionHandlers = null; + for (int i = 0; i < 2; ++i) { + for (BasicBlock pred : i == 0 ? setPreds : setSuccs) { + if (setCommonExceptionHandlers == null) { + setCommonExceptionHandlers = new HashSet<BasicBlock>(pred.getSuccExceptions()); + } + else { + setCommonExceptionHandlers.retainAll(pred.getSuccExceptions()); + } + } + } + + // check the block to be in each of the common ranges + if (setCommonExceptionHandlers != null && !setCommonExceptionHandlers.isEmpty()) { + for (BasicBlock handler : setCommonExceptionHandlers) { + if (!block.getSuccExceptions().contains(handler)) { + return false; + } + } + } + + // remove ranges consisting of this one block + List<ExceptionRangeCFG> lstRanges = graph.getExceptions(); + for (int i = lstRanges.size() - 1; i >= 0; i--) { + ExceptionRangeCFG range = lstRanges.get(i); + List<BasicBlock> lst = range.getProtectedRange(); + + if (lst.size() == 1 && lst.get(0) == block) { + if (DecompilerContext.getOption(IFernflowerPreferences.REMOVE_EMPTY_RANGES)) { + block.removeSuccessorException(range.getHandler()); + lstRanges.remove(i); + + deletedRanges = true; + } + else { + return false; + } + } + } + + + // connect remaining nodes + if (merging) { + BasicBlock pred = block.getPreds().get(0); + pred.removeSuccessor(block); + + List<BasicBlock> lstSuccs = new ArrayList<BasicBlock>(block.getSuccs()); + for (BasicBlock succ : lstSuccs) { + block.removeSuccessor(succ); + pred.addSuccessor(succ); + } + } + else { + for (BasicBlock pred : setPreds) { + for (BasicBlock succ : setSuccs) { + pred.replaceSuccessor(block, succ); + } + } + } + + // finally exit edges + HashSet<BasicBlock> setFinallyExits = graph.getFinallyExits(); + if (setFinallyExits.contains(block)) { + setFinallyExits.remove(block); + setFinallyExits.add(setPreds.iterator().next()); + } + + // replace first if necessary + if (graph.getFirst() == block) { + if (setSuccs.size() != 1) { + throw new RuntimeException("multiple or no entry blocks!"); + } + else { + graph.setFirst(setSuccs.iterator().next()); + } + } + + // remove this block + graph.removeBlock(block); + + if (deletedRanges) { + DeadCodeHelper.removeDeadBlocks(graph); + } + } + } + + return deletedRanges; + } + + + public static boolean isDominator(ControlFlowGraph graph, BasicBlock block, BasicBlock dom) { + + HashSet<BasicBlock> marked = new HashSet<BasicBlock>(); + + if (block == dom) { + return true; + } + + LinkedList<BasicBlock> lstNodes = new LinkedList<BasicBlock>(); + lstNodes.add(block); + + while (!lstNodes.isEmpty()) { + + BasicBlock node = (BasicBlock)lstNodes.remove(0); + if (marked.contains(node)) { + continue; + } + else { + marked.add(node); + } + + if (node == graph.getFirst()) { + return false; + } + + for (int i = 0; i < node.getPreds().size(); i++) { + BasicBlock pred = (BasicBlock)node.getPreds().get(i); + if (!marked.contains(pred) && pred != dom) { + lstNodes.add(pred); + } + } + + for (int i = 0; i < node.getPredExceptions().size(); i++) { + BasicBlock pred = (BasicBlock)node.getPredExceptions().get(i); + if (!marked.contains(pred) && pred != dom) { + lstNodes.add(pred); + } + } + } + + return true; + } + + public static void removeGotos(ControlFlowGraph graph) { + + for (BasicBlock block : graph.getBlocks()) { + Instruction instr = block.getLastInstruction(); + + if (instr != null && instr.opcode == CodeConstants.opc_goto) { + block.getSeq().removeInstruction(block.getSeq().length() - 1); + } + } + + DeadCodeHelper.removeEmptyBlocks(graph); + } + + public static void connectDummyExitBlock(ControlFlowGraph graph) { + + BasicBlock exit = graph.getLast(); + for (BasicBlock block : new HashSet<BasicBlock>(exit.getPreds())) { + exit.removePredecessor(block); + block.addSuccessor(exit); + } + } + + public static void incorporateValueReturns(ControlFlowGraph graph) { + + for (BasicBlock block : graph.getBlocks()) { + InstructionSequence seq = block.getSeq(); + + int len = seq.length(); + if (len > 0 && len < 3) { + + boolean ok = false; + + if (seq.getLastInstr().opcode >= CodeConstants.opc_ireturn && seq.getLastInstr().opcode <= CodeConstants.opc_return) { + if (len == 1) { + ok = true; + } + else if (seq.getLastInstr().opcode != CodeConstants.opc_return) { + switch (seq.getInstr(0).opcode) { + case CodeConstants.opc_iload: + case CodeConstants.opc_lload: + case CodeConstants.opc_fload: + case CodeConstants.opc_dload: + case CodeConstants.opc_aload: + case CodeConstants.opc_aconst_null: + case CodeConstants.opc_bipush: + case CodeConstants.opc_sipush: + case CodeConstants.opc_lconst_0: + case CodeConstants.opc_lconst_1: + case CodeConstants.opc_fconst_0: + case CodeConstants.opc_fconst_1: + case CodeConstants.opc_fconst_2: + case CodeConstants.opc_dconst_0: + case CodeConstants.opc_dconst_1: + case CodeConstants.opc_ldc: + case CodeConstants.opc_ldc_w: + case CodeConstants.opc_ldc2_w: + ok = true; + } + } + } + + if (ok) { + + if (!block.getPreds().isEmpty()) { + + HashSet<BasicBlock> setPredHandlersUnion = new HashSet<BasicBlock>(); + HashSet<BasicBlock> setPredHandlersIntersection = new HashSet<BasicBlock>(); + + boolean firstpred = true; + for (BasicBlock pred : block.getPreds()) { + if (firstpred) { + setPredHandlersIntersection.addAll(pred.getSuccExceptions()); + firstpred = false; + } + else { + setPredHandlersIntersection.retainAll(pred.getSuccExceptions()); + } + + setPredHandlersUnion.addAll(pred.getSuccExceptions()); + } + + // add exception ranges from predecessors + setPredHandlersIntersection.removeAll(block.getSuccExceptions()); + BasicBlock predecessor = block.getPreds().get(0); + + for (BasicBlock handler : setPredHandlersIntersection) { + ExceptionRangeCFG range = graph.getExceptionRange(handler, predecessor); + + range.getProtectedRange().add(block); + block.addSuccessorException(handler); + } + + // remove redundant ranges + HashSet<BasicBlock> setRangesToBeRemoved = new HashSet<BasicBlock>(block.getSuccExceptions()); + setRangesToBeRemoved.removeAll(setPredHandlersUnion); + + for (BasicBlock handler : setRangesToBeRemoved) { + ExceptionRangeCFG range = graph.getExceptionRange(handler, block); + + if (range.getProtectedRange().size() > 1) { + range.getProtectedRange().remove(block); + block.removeSuccessorException(handler); + } + } + } + + + if (block.getPreds().size() == 1 && block.getPredExceptions().isEmpty()) { + + BasicBlock bpred = block.getPreds().get(0); + if (bpred.getSuccs().size() == 1) { + + // add exception ranges of predecessor + for (BasicBlock succ : bpred.getSuccExceptions()) { + if (!block.getSuccExceptions().contains(succ)) { + ExceptionRangeCFG range = graph.getExceptionRange(succ, bpred); + + range.getProtectedRange().add(block); + block.addSuccessorException(succ); + } + } + + // remove superfluous ranges from successors + for (BasicBlock succ : new HashSet<BasicBlock>(block.getSuccExceptions())) { + if (!bpred.getSuccExceptions().contains(succ)) { + ExceptionRangeCFG range = graph.getExceptionRange(succ, block); + + if (range.getProtectedRange().size() > 1) { + range.getProtectedRange().remove(block); + block.removeSuccessorException(succ); + } + } + } + } + } + } + } + } + } + + + public static void mergeBasicBlocks(ControlFlowGraph graph) { + + for (; ; ) { + + boolean merged = false; + + for (BasicBlock block : graph.getBlocks()) { + + InstructionSequence seq = block.getSeq(); + + if (block.getSuccs().size() == 1) { + BasicBlock next = block.getSuccs().get(0); + + if (next != graph.getLast() && (seq.isEmpty() || seq.getLastInstr().group != CodeConstants.GROUP_SWITCH)) { + + if (next.getPreds().size() == 1 && next.getPredExceptions().isEmpty() + && next != graph.getFirst()) { + // TODO: implement a dummy start block + boolean sameRanges = true; + for (ExceptionRangeCFG range : graph.getExceptions()) { + if (range.getProtectedRange().contains(block) ^ + range.getProtectedRange().contains(next)) { + sameRanges = false; + break; + } + } + + if (sameRanges) { + seq.addSequence(next.getSeq()); + next.getSeq().clear(); + + removeEmptyBlock(graph, next, true); + + merged = true; + break; + } + } + } + } + } + + if (!merged) { + break; + } + } + } } |