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.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                      compare(invokeDynamicConstant.getName(clazz),
    176                              invokeDynamicConstant.getType(clazz),
    177                              otherInvokeDynamicConstant.getName(clazz),
    178                              otherInvokeDynamicConstant.getType(clazz));
    179     }
    180 
    181     public void visitMethodHandleConstant(Clazz clazz, MethodHandleConstant methodHandleConstant)
    182     {
    183         MethodHandleConstant otherMethodHandleConstant = (MethodHandleConstant)otherConstant;
    184 
    185         int kind      = methodHandleConstant.getReferenceKind();
    186         int otherKind = otherMethodHandleConstant.getReferenceKind();
    187 
    188         result = kind < otherKind ? -1 :
    189                  kind > otherKind ?  1 :
    190                      compare(methodHandleConstant.getClassName(clazz),
    191                              methodHandleConstant.getName(clazz),
    192                              methodHandleConstant.getType(clazz),
    193                              otherMethodHandleConstant.getClassName(clazz),
    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 = compare(refConstant.getClassName(clazz),
    202                          refConstant.getName(clazz),
    203                          refConstant.getType(clazz),
    204                          otherRefConstant.getClassName(clazz),
    205                          otherRefConstant.getName(clazz),
    206                          otherRefConstant.getType(clazz));
    207     }
    208 
    209     public void visitClassConstant(Clazz clazz, ClassConstant classConstant)
    210     {
    211         result = classConstant.getName(clazz).compareTo(((ClassConstant)otherConstant).getName(clazz));
    212     }
    213 
    214     public void visitMethodTypeConstant(Clazz clazz, MethodTypeConstant MethodTypeConstant)
    215     {
    216         MethodTypeConstant otherMethodTypeConstant = (MethodTypeConstant)otherConstant;
    217         result = MethodTypeConstant.getType(clazz)
    218                  .compareTo
    219                  (otherMethodTypeConstant.getType(clazz));
    220     }
    221 
    222     public void visitNameAndTypeConstant(Clazz clazz, NameAndTypeConstant nameAndTypeConstant)
    223     {
    224         NameAndTypeConstant otherNameAndTypeConstant = (NameAndTypeConstant)otherConstant;
    225         result = compare(nameAndTypeConstant.getName(clazz),
    226                          nameAndTypeConstant.getType(clazz),
    227                          otherNameAndTypeConstant.getName(clazz),
    228                          otherNameAndTypeConstant.getType(clazz));
    229     }
    230 
    231 
    232     // Implementations for Object.
    233 
    234     public boolean equals(Object other)
    235     {
    236         return other != null &&
    237                this.getClass().equals(other.getClass()) &&
    238                this.getConstant().getClass().equals(((ComparableConstant)other).getConstant().getClass()) &&
    239                this.compareTo(other) == 0;
    240     }
    241 
    242 
    243     public int hashCode()
    244     {
    245         return this.getClass().hashCode();
    246     }
    247 
    248 
    249     // Small utility methods.
    250 
    251     /**
    252      * Compares the given two pairs of strings.
    253      */
    254     private int compare(String string1a, String string1b,
    255                         String string2a, String string2b)
    256     {
    257         int comparison;
    258         return
    259             (comparison = string1a.compareTo(string2a)) != 0 ? comparison :
    260                           string1b.compareTo(string2b);
    261     }
    262 
    263 
    264     /**
    265      * Compares the given two triplets of strings.
    266      */
    267     private int compare(String string1a, String string1b, String string1c,
    268                         String string2a, String string2b, String string2c)
    269     {
    270         int comparison;
    271         return
    272             (comparison = string1a.compareTo(string2a)) != 0 ? comparison :
    273             (comparison = string1b.compareTo(string2b)) != 0 ? comparison :
    274                           string1c.compareTo(string2c);
    275     }
    276 }
    277