Home | History | Annotate | Download | only in editor
      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.classfile.editor;
     22 
     23 import proguard.classfile.*;
     24 import proguard.classfile.constant.*;
     25 import proguard.classfile.constant.visitor.ConstantVisitor;
     26 import proguard.classfile.util.SimplifiedVisitor;
     27 
     28 
     29 /**
     30  * This class is a <code>Comparable</code> wrapper of <code>Constant</code>
     31  * objects. It can store an index, in order to identify the constant   pool
     32  * entry after it has been sorted. The comparison is primarily based   on the
     33  * types of the constant pool entries, and secondarily on the contents of
     34  * the constant pool entries.
     35  *
     36  * @author Eric Lafortune
     37  */
     38 class      ComparableConstant
     39 extends    SimplifiedVisitor
     40 implements Comparable, ConstantVisitor
     41 {
     42     private static final int[] PRIORITIES = new int[19];
     43     static
     44     {
     45         PRIORITIES[ClassConstants.CONSTANT_Integer]            = 0; // Possibly byte index (ldc).
     46         PRIORITIES[ClassConstants.CONSTANT_Float]              = 1;
     47         PRIORITIES[ClassConstants.CONSTANT_String]             = 2;
     48         PRIORITIES[ClassConstants.CONSTANT_Class]              = 3;
     49         PRIORITIES[ClassConstants.CONSTANT_Long]               = 4; // Always wide index (ldc2_w).
     50         PRIORITIES[ClassConstants.CONSTANT_Double]             = 5; // Always wide index (ldc2_w).
     51         PRIORITIES[ClassConstants.CONSTANT_Fieldref]           = 6; // Always wide index (getfield,...).
     52         PRIORITIES[ClassConstants.CONSTANT_Methodref]          = 7; // Always wide index (invokespecial,...).
     53         PRIORITIES[ClassConstants.CONSTANT_InterfaceMethodref] = 8; // Always wide index (invokeinterface).
     54         PRIORITIES[ClassConstants.CONSTANT_InvokeDynamic]      = 9; // Always wide index (invokedynamic).
     55         PRIORITIES[ClassConstants.CONSTANT_MethodHandle]       = 10;
     56         PRIORITIES[ClassConstants.CONSTANT_NameAndType]        = 11;
     57         PRIORITIES[ClassConstants.CONSTANT_MethodType]         = 12;
     58         PRIORITIES[ClassConstants.CONSTANT_Utf8]               = 13;
     59     }
     60 
     61     private final Clazz    clazz;
     62     private final int      thisIndex;
     63     private final Constant thisConstant;
     64 
     65     private Constant otherConstant;
     66     private int      result;
     67 
     68 
     69     public ComparableConstant(Clazz clazz, int index, Constant constant)
     70     {
     71         this.clazz        = clazz;
     72         this.thisIndex    = index;
     73         this.thisConstant = constant;
     74     }
     75 
     76 
     77     public int getIndex()
     78     {
     79         return thisIndex;
     80     }
     81 
     82 
     83     public Constant getConstant()
     84     {
     85         return thisConstant;
     86     }
     87 
     88 
     89     // Implementations for Comparable.
     90 
     91     public int compareTo(Object other)
     92     {
     93         ComparableConstant otherComparableConstant = (ComparableConstant)other;
     94 
     95         otherConstant = otherComparableConstant.thisConstant;
     96 
     97         // Compare based on the original indices, if the actual constant pool
     98         // entries are the same.
     99         if (thisConstant == otherConstant)
    100         {
    101             int otherIndex = otherComparableConstant.thisIndex;
    102 
    103             return thisIndex <  otherIndex ? -1 :
    104                    thisIndex == otherIndex ?  0 :
    105                                               1;
    106         }
    107 
    108         // Compare based on the tags, if they are different.
    109         int thisTag  = thisConstant.getTag();
    110         int otherTag = otherConstant.getTag();
    111 
    112         if (thisTag != otherTag)
    113         {
    114             return PRIORITIES[thisTag] < PRIORITIES[otherTag] ? -1 : 1;
    115         }
    116 
    117         // Otherwise compare based on the contents of the Constant objects.
    118         thisConstant.accept(clazz, this);
    119 
    120         return result;
    121     }
    122 
    123 
    124     // Implementations for ConstantVisitor.
    125 
    126     public void visitIntegerConstant(Clazz clazz, IntegerConstant integerConstant)
    127     {
    128         int value      = integerConstant.getValue();
    129         int otherValue = ((IntegerConstant)otherConstant).getValue();
    130         result = value <  otherValue ? -1 :
    131                  value == otherValue ?  0 :
    132                                         1;
    133     }
    134 
    135     public void visitLongConstant(Clazz clazz, LongConstant longConstant)
    136     {
    137         long value      = longConstant.getValue();
    138         long otherValue = ((LongConstant)otherConstant).getValue();
    139         result = value <  otherValue ? -1 :
    140                  value == otherValue ?  0 :
    141                                         1;
    142     }
    143 
    144     public void visitFloatConstant(Clazz clazz, FloatConstant floatConstant)
    145     {
    146         result = Float.compare(floatConstant.getValue(),
    147                                ((FloatConstant)otherConstant).getValue());
    148     }
    149 
    150     public void visitDoubleConstant(Clazz clazz, DoubleConstant doubleConstant)
    151     {
    152         result = Double.compare(doubleConstant.getValue(),
    153                                 ((DoubleConstant)otherConstant).getValue());
    154     }
    155 
    156     public void visitStringConstant(Clazz clazz, StringConstant stringConstant)
    157     {
    158         result = stringConstant.getString(clazz).compareTo(((StringConstant)otherConstant).getString(clazz));
    159     }
    160 
    161     public void visitUtf8Constant(Clazz clazz, Utf8Constant utf8Constant)
    162     {
    163         result = utf8Constant.getString().compareTo(((Utf8Constant)otherConstant).getString());
    164     }
    165 
    166     public void visitInvokeDynamicConstant(Clazz clazz, InvokeDynamicConstant invokeDynamicConstant)
    167     {
    168         InvokeDynamicConstant otherInvokeDynamicConstant = (InvokeDynamicConstant)otherConstant;
    169 
    170         int index      = invokeDynamicConstant.getBootstrapMethodAttributeIndex();
    171         int otherIndex = otherInvokeDynamicConstant.getBootstrapMethodAttributeIndex();
    172 
    173         result = index < otherIndex ? -1 :
    174                  index > otherIndex ?  1 :
    175                  (invokeDynamicConstant.getName(clazz) + ' ' +
    176                   invokeDynamicConstant.getType(clazz))
    177                  .compareTo
    178                  (otherInvokeDynamicConstant.getName(clazz) + ' ' +
    179                   otherInvokeDynamicConstant.getType(clazz));
    180     }
    181 
    182     public void visitMethodHandleConstant(Clazz clazz, MethodHandleConstant methodHandleConstant)
    183     {
    184         MethodHandleConstant otherMethodHandleConstant = (MethodHandleConstant)otherConstant;
    185 
    186         int kind      = methodHandleConstant.getReferenceKind();
    187         int otherKind = methodHandleConstant.getReferenceKind();
    188 
    189         result = kind < otherKind ? -1 :
    190                  kind > otherKind ?  1 :
    191                  (methodHandleConstant.getName(clazz) + ' ' +
    192                   methodHandleConstant.getType(clazz))
    193                  .compareTo
    194                  (otherMethodHandleConstant.getName(clazz) + ' ' +
    195                   otherMethodHandleConstant.getType(clazz));
    196     }
    197 
    198     public void visitAnyRefConstant(Clazz clazz, RefConstant refConstant)
    199     {
    200         RefConstant otherRefConstant = (RefConstant)otherConstant;
    201         result = (refConstant.getClassName(clazz) + ' ' +
    202                   refConstant.getName(clazz)      + ' ' +
    203                   refConstant.getType(clazz))
    204                  .compareTo
    205                  (otherRefConstant.getClassName(clazz) + ' ' +
    206                   otherRefConstant.getName(clazz)      + ' ' +
    207                   otherRefConstant.getType(clazz));
    208     }
    209 
    210     public void visitClassConstant(Clazz clazz, ClassConstant classConstant)
    211     {
    212         result = classConstant.getName(clazz).compareTo(((ClassConstant)otherConstant).getName(clazz));
    213     }
    214 
    215     public void visitMethodTypeConstant(Clazz clazz, MethodTypeConstant MethodTypeConstant)
    216     {
    217         MethodTypeConstant otherMethodTypeConstant = (MethodTypeConstant)otherConstant;
    218         result = MethodTypeConstant.getType(clazz)
    219                  .compareTo
    220                  (otherMethodTypeConstant.getType(clazz));
    221     }
    222 
    223     public void visitNameAndTypeConstant(Clazz clazz, NameAndTypeConstant nameAndTypeConstant)
    224     {
    225         NameAndTypeConstant otherNameAndTypeConstant = (NameAndTypeConstant)otherConstant;
    226         result = (nameAndTypeConstant.getName(clazz) + ' ' +
    227                   nameAndTypeConstant.getType(clazz))
    228                  .compareTo
    229                  (otherNameAndTypeConstant.getName(clazz) + ' ' +
    230                   otherNameAndTypeConstant.getType(clazz));
    231     }
    232 
    233 
    234     // Implementations for Object.
    235 
    236     public boolean equals(Object other)
    237     {
    238         return other != null &&
    239                this.getClass().equals(other.getClass()) &&
    240                this.getConstant().getClass().equals(((ComparableConstant)other).getConstant().getClass()) &&
    241                this.compareTo(other) == 0;
    242     }
    243 
    244 
    245     public int hashCode()
    246     {
    247         return this.getClass().hashCode();
    248     }
    249 }
    250