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.*;
     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     /**
     45      * Creates a new UnreachableExceptionRemover.
     46      */
     47     public UnreachableExceptionRemover()
     48     {
     49         this(null);
     50     }
     51 
     52 
     53     /**
     54      * Creates a new UnreachableExceptionRemover.
     55      * @param extraExceptionInfoVisitor an optional extra visitor for all
     56      *                                  removed exceptions.
     57      */
     58     public UnreachableExceptionRemover(ExceptionInfoVisitor extraExceptionInfoVisitor)
     59     {
     60         this.extraExceptionInfoVisitor = extraExceptionInfoVisitor;
     61     }
     62 
     63 
     64     // Implementations for AttributeVisitor.
     65 
     66     public void visitAnyAttribute(Clazz clazz, Attribute attribute) {}
     67 
     68 
     69     public void visitCodeAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute)
     70     {
     71         // Go over the exception table.
     72         codeAttribute.exceptionsAccept(clazz, method, this);
     73 
     74         // Remove exceptions with empty code blocks.
     75         codeAttribute.u2exceptionTableLength =
     76             removeEmptyExceptions(codeAttribute.exceptionTable,
     77                                   codeAttribute.u2exceptionTableLength);
     78     }
     79 
     80 
     81     // Implementations for ExceptionInfoVisitor.
     82 
     83     public void visitExceptionInfo(Clazz clazz, Method method, CodeAttribute codeAttribute, ExceptionInfo exceptionInfo)
     84     {
     85         if (!mayThrowExceptions(clazz,
     86                                 method,
     87                                 codeAttribute,
     88                                 exceptionInfo.u2startPC,
     89                                 exceptionInfo.u2endPC))
     90         {
     91             // Make the code block empty.
     92             exceptionInfo.u2endPC = exceptionInfo.u2startPC;
     93 
     94             if (extraExceptionInfoVisitor != null)
     95             {
     96                 extraExceptionInfoVisitor.visitExceptionInfo(clazz, method, codeAttribute, exceptionInfo);
     97             }
     98         }
     99     }
    100 
    101 
    102     // Small utility methods.
    103 
    104     /**
    105      * Returns whether the specified block of code may throw exceptions.
    106      */
    107     private boolean mayThrowExceptions(Clazz         clazz,
    108                                        Method        method,
    109                                        CodeAttribute codeAttribute,
    110                                        int           startOffset,
    111                                        int           endOffset)
    112     {
    113         byte[] code = codeAttribute.code;
    114 
    115         // Go over all instructions.
    116         int offset = startOffset;
    117         while (offset < endOffset)
    118         {
    119             // Get the current instruction.
    120             Instruction instruction = InstructionFactory.create(code, offset);
    121 
    122             // Check if it may be throwing exceptions.
    123             if (instruction.mayThrowExceptions())
    124             {
    125                 return true;
    126             }
    127 
    128             // Go to the next instruction.
    129             offset += instruction.length(offset);
    130         }
    131 
    132         return false;
    133     }
    134 
    135 
    136     /**
    137      * Returns the given list of exceptions, without the ones that have empty
    138      * code blocks.
    139      */
    140     private int removeEmptyExceptions(ExceptionInfo[] exceptionInfos,
    141                                       int             exceptionInfoCount)
    142     {
    143         // Overwrite all empty exceptions.
    144         int newIndex = 0;
    145         for (int index = 0; index < exceptionInfoCount; index++)
    146         {
    147             ExceptionInfo exceptionInfo = exceptionInfos[index];
    148             if (exceptionInfo.u2startPC < exceptionInfo.u2endPC)
    149             {
    150                 exceptionInfos[newIndex++] = exceptionInfo;
    151             }
    152         }
    153 
    154         return newIndex;
    155     }
    156 }
    157