Home | History | Annotate | Download | only in peephole
      1 /*
      2  * ProGuard -- shrinking, optimization, obfuscation, and preverification
      3  *             of Java bytecode.
      4  *
      5  * Copyright (c) 2002-2013 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.*;
     26 import proguard.classfile.instruction.*;
     27 import proguard.classfile.util.SimplifiedVisitor;
     28 import proguard.optimize.info.ExceptionInstructionChecker;
     29 
     30 /**
     31  * This AttributeVisitor removes exception handlers that are unreachable in the
     32  * code attributes that it visits.
     33  *
     34  * @author Eric Lafortune
     35  */
     36 public class UnreachableExceptionRemover
     37 extends      SimplifiedVisitor
     38 implements   AttributeVisitor,
     39              ExceptionInfoVisitor
     40 {
     41     private final ExceptionInfoVisitor extraExceptionInfoVisitor;
     42 
     43 
     44     private final ExceptionInstructionChecker exceptionInstructionChecker = new ExceptionInstructionChecker();
     45 
     46 
     47     /**
     48      * Creates a new UnreachableExceptionRemover.
     49      */
     50     public UnreachableExceptionRemover()
     51     {
     52         this(null);
     53     }
     54 
     55 
     56     /**
     57      * Creates a new UnreachableExceptionRemover.
     58      * @param extraExceptionInfoVisitor an optional extra visitor for all
     59      *                                  removed exceptions.
     60      */
     61     public UnreachableExceptionRemover(ExceptionInfoVisitor extraExceptionInfoVisitor)
     62     {
     63         this.extraExceptionInfoVisitor = extraExceptionInfoVisitor;
     64     }
     65 
     66 
     67     // Implementations for AttributeVisitor.
     68 
     69     public void visitAnyAttribute(Clazz clazz, Attribute attribute) {}
     70 
     71 
     72     public void visitCodeAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute)
     73     {
     74         // Go over the exception table.
     75         codeAttribute.exceptionsAccept(clazz, method, this);
     76 
     77         // Remove exceptions with empty code blocks.
     78         codeAttribute.u2exceptionTableLength =
     79             removeEmptyExceptions(codeAttribute.exceptionTable,
     80                                   codeAttribute.u2exceptionTableLength);
     81     }
     82 
     83 
     84     // Implementations for ExceptionInfoVisitor.
     85 
     86     public void visitExceptionInfo(Clazz clazz, Method method, CodeAttribute codeAttribute, ExceptionInfo exceptionInfo)
     87     {
     88         if (!mayThrowExceptions(clazz,
     89                                 method,
     90                                 codeAttribute,
     91                                 exceptionInfo.u2startPC,
     92                                 exceptionInfo.u2endPC))
     93         {
     94             // Make the code block empty.
     95             exceptionInfo.u2endPC = exceptionInfo.u2startPC;
     96 
     97             if (extraExceptionInfoVisitor != null)
     98             {
     99                 extraExceptionInfoVisitor.visitExceptionInfo(clazz, method, codeAttribute, exceptionInfo);
    100             }
    101         }
    102     }
    103 
    104 
    105     // Small utility methods.
    106 
    107     /**
    108      * Returns whether the specified block of code may throw exceptions.
    109      */
    110     private boolean mayThrowExceptions(Clazz         clazz,
    111                                        Method        method,
    112                                        CodeAttribute codeAttribute,
    113                                        int           startOffset,
    114                                        int           endOffset)
    115     {
    116         byte[] code = codeAttribute.code;
    117 
    118         // Go over all instructions.
    119         int offset = startOffset;
    120         while (offset < endOffset)
    121         {
    122             // Get the current instruction.
    123             Instruction instruction = InstructionFactory.create(code, offset);
    124 
    125             // Check if it may be throwing exceptions.
    126             if (exceptionInstructionChecker.mayThrowExceptions(clazz,
    127                                                                method,
    128                                                                codeAttribute,
    129                                                                offset,
    130                                                                instruction))
    131             {
    132                 return true;
    133             }
    134 
    135             // Go to the next instruction.
    136             offset += instruction.length(offset);
    137         }
    138 
    139         return false;
    140     }
    141 
    142 
    143     /**
    144      * Returns the given list of exceptions, without the ones that have empty
    145      * code blocks.
    146      */
    147     private int removeEmptyExceptions(ExceptionInfo[] exceptionInfos,
    148                                       int             exceptionInfoCount)
    149     {
    150         // Overwrite all empty exceptions.
    151         int newIndex = 0;
    152         for (int index = 0; index < exceptionInfoCount; index++)
    153         {
    154             ExceptionInfo exceptionInfo = exceptionInfos[index];
    155             if (exceptionInfo.u2startPC < exceptionInfo.u2endPC)
    156             {
    157                 exceptionInfos[newIndex++] = exceptionInfo;
    158             }
    159         }
    160 
    161         return newIndex;
    162     }
    163 }
    164