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