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