• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * ProGuard -- shrinking, optimization, obfuscation, and preverification
3  *             of Java bytecode.
4  *
5  * Copyright (c) 2002-2014 Eric Lafortune (eric@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 
ComparableConstant(Clazz clazz, int index, Constant constant)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 
getIndex()77     public int getIndex()
78     {
79         return thisIndex;
80     }
81 
82 
getConstant()83     public Constant getConstant()
84     {
85         return thisConstant;
86     }
87 
88 
89     // Implementations for Comparable.
90 
compareTo(Object other)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 
visitIntegerConstant(Clazz clazz, IntegerConstant integerConstant)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