Home | History | Annotate | Download | only in editor
      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.classfile.editor;
     22 
     23 import proguard.classfile.*;
     24 import proguard.classfile.attribute.*;
     25 import proguard.classfile.attribute.visitor.AttributeVisitor;
     26 import proguard.classfile.constant.*;
     27 import proguard.classfile.constant.visitor.ConstantVisitor;
     28 import proguard.classfile.util.SimplifiedVisitor;
     29 import proguard.classfile.visitor.ClassVisitor;
     30 
     31 import java.util.Arrays;
     32 
     33 
     34 /**
     35  * This ClassVisitor removes NameAndType constant pool entries that are not
     36  * used.
     37  *
     38  * @author Eric Lafortune
     39  */
     40 public class NameAndTypeShrinker
     41 extends      SimplifiedVisitor
     42 implements   ClassVisitor,
     43              ConstantVisitor,
     44              AttributeVisitor
     45 {
     46     // A visitor info flag to indicate the NameAndType constant pool entry is being used.
     47     private static final Object USED = new Object();
     48 
     49     private       int[]                constantIndexMap;
     50     private final ConstantPoolRemapper constantPoolRemapper = new ConstantPoolRemapper();
     51 
     52 
     53     // Implementations for ClassVisitor.
     54 
     55     public void visitProgramClass(ProgramClass programClass)
     56     {
     57         // Mark the NameAndType entries referenced by all other constant pool
     58         // entries.
     59         programClass.constantPoolEntriesAccept(this);
     60 
     61         // Mark the NameAndType entries referenced by all EnclosingMethod
     62         // attributes.
     63         programClass.attributesAccept(this);
     64 
     65         // Shift the used constant pool entries together, filling out the
     66         // index map.
     67         int newConstantPoolCount =
     68             shrinkConstantPool(programClass.constantPool,
     69                                programClass.u2constantPoolCount);
     70 
     71         // Remap the references to the constant pool if it has shrunk.
     72         if (newConstantPoolCount < programClass.u2constantPoolCount)
     73         {
     74             programClass.u2constantPoolCount = newConstantPoolCount;
     75 
     76             // Remap all constant pool references.
     77             constantPoolRemapper.setConstantIndexMap(constantIndexMap);
     78             constantPoolRemapper.visitProgramClass(programClass);
     79         }
     80     }
     81 
     82 
     83     // Implementations for ConstantVisitor.
     84 
     85     public void visitAnyConstant(Clazz clazz, Constant constant) {}
     86 
     87 
     88     public void visitInvokeDynamicConstant(Clazz clazz, InvokeDynamicConstant invokeDynamicConstant)
     89     {
     90         markNameAndTypeConstant(clazz, invokeDynamicConstant.u2nameAndTypeIndex);
     91     }
     92 
     93 
     94     public void visitAnyRefConstant(Clazz clazz, RefConstant refConstant)
     95     {
     96         markNameAndTypeConstant(clazz, refConstant.u2nameAndTypeIndex);
     97     }
     98 
     99 
    100     // Implementations for AttributeVisitor.
    101 
    102     public void visitAnyAttribute(Clazz clazz, Attribute attribute) {}
    103 
    104 
    105     public void visitEnclosingMethodAttribute(Clazz clazz, EnclosingMethodAttribute enclosingMethodAttribute)
    106     {
    107         if (enclosingMethodAttribute.u2nameAndTypeIndex != 0)
    108         {
    109             markNameAndTypeConstant(clazz, enclosingMethodAttribute.u2nameAndTypeIndex);
    110         }
    111     }
    112 
    113 
    114     // Small utility methods.
    115 
    116     /**
    117      * Marks the given UTF-8 constant pool entry of the given class.
    118      */
    119     private void markNameAndTypeConstant(Clazz clazz, int index)
    120     {
    121          markAsUsed((NameAndTypeConstant)((ProgramClass)clazz).getConstant(index));
    122     }
    123 
    124 
    125     /**
    126      * Marks the given VisitorAccepter as being used.
    127      * In this context, the VisitorAccepter will be a NameAndTypeConstant object.
    128      */
    129     private void markAsUsed(VisitorAccepter visitorAccepter)
    130     {
    131         visitorAccepter.setVisitorInfo(USED);
    132     }
    133 
    134 
    135     /**
    136      * Returns whether the given VisitorAccepter has been marked as being used.
    137      * In this context, the VisitorAccepter will be a NameAndTypeConstant object.
    138      */
    139     private boolean isUsed(VisitorAccepter visitorAccepter)
    140     {
    141         return visitorAccepter.getVisitorInfo() == USED;
    142     }
    143 
    144 
    145     /**
    146      * Removes all NameAndType entries that are not marked as being used
    147      * from the given constant pool.
    148      * @return the new number of entries.
    149      */
    150     private int shrinkConstantPool(Constant[] constantPool, int length)
    151     {
    152         // Create a new index map, if necessary.
    153         if (constantIndexMap == null ||
    154             constantIndexMap.length < length)
    155         {
    156             constantIndexMap = new int[length];
    157         }
    158 
    159         int     counter = 1;
    160         boolean isUsed  = false;
    161 
    162         // Shift the used constant pool entries together.
    163         for (int index = 1; index < length; index++)
    164         {
    165             Constant constant = constantPool[index];
    166 
    167             // Is the constant being used? Don't update the flag if this is the
    168             // second half of a long entry.
    169             if (constant != null)
    170             {
    171                 isUsed = constant.getTag() != ClassConstants.CONSTANT_NameAndType ||
    172                          isUsed(constant);
    173             }
    174 
    175             if (isUsed)
    176             {
    177                 // Remember the new index.
    178                 constantIndexMap[index] = counter;
    179 
    180                 // Shift the constant pool entry.
    181                 constantPool[counter++] = constant;
    182             }
    183             else
    184             {
    185                 // Remember an invalid index.
    186                 constantIndexMap[index] = -1;
    187             }
    188         }
    189 
    190         // Clear the remaining constant pool elements.
    191         Arrays.fill(constantPool, counter, length, null);
    192 
    193         return counter;
    194     }
    195 }
    196