1/* 2 * ProGuard -- shrinking, optimization, obfuscation, and preverification 3 * of Java bytecode. 4 * 5 * Copyright (c) 2002-2014 Eric Lafortune (eric@graphics.cornell.edu) 6 * 7 * This program is free software; you can redistribute it and/or modify it 8 * under the terms of the GNU General Public License as published by the Free 9 * Software Foundation; either version 2 of the License, or (at your option) 10 * any later version. 11 * 12 * This program is distributed in the hope that it will be useful, but WITHOUT 13 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 14 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 15 * more details. 16 * 17 * You should have received a copy of the GNU General Public License along 18 * with this program; if not, write to the Free Software Foundation, Inc., 19 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 20 */ 21package proguard.optimize.peephole; 22 23import proguard.classfile.*; 24import proguard.classfile.attribute.*; 25import proguard.classfile.attribute.visitor.AttributeVisitor; 26import proguard.classfile.editor.CodeAttributeEditor; 27import proguard.classfile.instruction.Instruction; 28import proguard.classfile.instruction.visitor.InstructionVisitor; 29import proguard.classfile.util.SimplifiedVisitor; 30 31/** 32 * This InstructionVisitor deletes blocks of code that can never be reached by 33 * regular calls or branches. 34 * 35 * @author Eric Lafortune 36 */ 37public class UnreachableCodeRemover 38extends SimplifiedVisitor 39implements AttributeVisitor, 40 InstructionVisitor 41{ 42 //* 43 private static final boolean DEBUG = false; 44 /*/ 45 private static boolean DEBUG = true; 46 //*/ 47 48 private final InstructionVisitor extraInstructionVisitor; 49 50 private final ReachableCodeMarker reachableCodeMarker = new ReachableCodeMarker(); 51 private final CodeAttributeEditor codeAttributeEditor = new CodeAttributeEditor(); 52 53 54 /** 55 * Creates a new UnreachableCodeRemover. 56 */ 57 public UnreachableCodeRemover() 58 { 59 this(null); 60 } 61 62 63 /** 64 * Creates a new UnreachableCodeRemover. 65 * @param extraInstructionVisitor an optional extra visitor for all 66 * deleted instructions. 67 */ 68 public UnreachableCodeRemover(InstructionVisitor extraInstructionVisitor) 69 { 70 this.extraInstructionVisitor = extraInstructionVisitor; 71 } 72 73 74 // Implementations for AttributeVisitor. 75 76 public void visitAnyAttribute(Clazz clazz, Attribute attribute) {} 77 78 79 public void visitCodeAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute) 80 { 81// DEBUG = 82// clazz.getName().equals("abc/Def") && 83// method.getName(clazz).equals("abc"); 84 85 // TODO: Remove this when the code has stabilized. 86 // Catch any unexpected exceptions from the actual visiting method. 87 try 88 { 89 // Process the code. 90 visitCodeAttribute0(clazz, method, codeAttribute); 91 } 92 catch (RuntimeException ex) 93 { 94 System.err.println("Unexpected error while removing unreachable code:"); 95 System.err.println(" Class = ["+clazz.getName()+"]"); 96 System.err.println(" Method = ["+method.getName(clazz)+method.getDescriptor(clazz)+"]"); 97 System.err.println(" Exception = ["+ex.getClass().getName()+"] ("+ex.getMessage()+")"); 98 99 throw ex; 100 } 101 } 102 103 104 public void visitCodeAttribute0(Clazz clazz, Method method, CodeAttribute codeAttribute) 105 { 106 if (DEBUG) 107 { 108 System.out.println("UnreachableCodeRemover: "+clazz.getName()+"."+method.getName(clazz)+method.getDescriptor(clazz)); 109 } 110 111 reachableCodeMarker.visitCodeAttribute(clazz, method, codeAttribute); 112 113 codeAttributeEditor.reset(codeAttribute.u4codeLength); 114 115 codeAttribute.instructionsAccept(clazz, method, this); 116 117 codeAttributeEditor.visitCodeAttribute(clazz, method, codeAttribute); 118 } 119 120 121 // Implementations for InstructionVisitor. 122 123 public void visitAnyInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, Instruction instruction) 124 { 125 if (DEBUG) 126 { 127 System.out.println(" "+(reachableCodeMarker.isReachable(offset) ? "+" : "-")+" "+instruction.toString(offset)); 128 } 129 130 // Is this instruction unreachable? 131 if (!reachableCodeMarker.isReachable(offset)) 132 { 133 // Then delete it. 134 codeAttributeEditor.deleteInstruction(offset); 135 136 // Visit the instruction, if required. 137 if (extraInstructionVisitor != null) 138 { 139 instruction.accept(clazz, method, codeAttribute, offset, extraInstructionVisitor); 140 } 141 } 142 } 143} 144