Home | History | Annotate | Download | only in peephole
      1 /*
      2  * ProGuard -- shrinking, optimization, obfuscation, and preverification
      3  *             of Java bytecode.
      4  *
      5  * Copyright (c) 2002-2014 Eric Lafortune (eric (at) 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  */
     21 package proguard.optimize.peephole;
     22 
     23 import proguard.classfile.*;
     24 import proguard.classfile.attribute.*;
     25 import proguard.classfile.attribute.visitor.AttributeVisitor;
     26 import proguard.classfile.editor.CodeAttributeEditor;
     27 import proguard.classfile.instruction.Instruction;
     28 import proguard.classfile.instruction.visitor.InstructionVisitor;
     29 import 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  */
     37 public class UnreachableCodeRemover
     38 extends      SimplifiedVisitor
     39 implements   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