1 /* 2 * ProGuard -- shrinking, optimization, obfuscation, and preverification 3 * of Java bytecode. 4 * 5 * Copyright (c) 2002-2009 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.Constant; 25 import proguard.classfile.util.SimplifiedVisitor; 26 import proguard.classfile.visitor.ClassVisitor; 27 28 import java.util.Arrays; 29 30 /** 31 * This ClassVisitor sorts the constant pool entries of the program classes 32 * that it visits. The sorting order is based on the types of the constant pool 33 * entries in the first place, and on their contents in the second place. 34 * 35 * @author Eric Lafortune 36 */ 37 public class ConstantPoolSorter 38 extends SimplifiedVisitor 39 implements ClassVisitor 40 { 41 private int[] constantIndexMap = new int[ClassConstants.TYPICAL_CONSTANT_POOL_SIZE]; 42 private ComparableConstant[] comparableConstantPool = new ComparableConstant[ClassConstants.TYPICAL_CONSTANT_POOL_SIZE]; 43 private Constant[] newConstantPool = new Constant[ClassConstants.TYPICAL_CONSTANT_POOL_SIZE]; 44 45 private final ConstantPoolRemapper constantPoolRemapper = new ConstantPoolRemapper(); 46 47 48 // Implementations for ClassVisitor. 49 50 public void visitProgramClass(ProgramClass programClass) 51 { 52 int constantPoolCount = programClass.u2constantPoolCount; 53 54 // Sort the constant pool and set up an index map. 55 if (constantIndexMap.length < constantPoolCount) 56 { 57 constantIndexMap = new int[constantPoolCount]; 58 comparableConstantPool = new ComparableConstant[constantPoolCount]; 59 newConstantPool = new Constant[constantPoolCount]; 60 } 61 62 // Initialize an array whose elements can be compared. 63 int sortLength = 0; 64 for (int oldIndex = 1; oldIndex < constantPoolCount; oldIndex++) 65 { 66 Constant constant = programClass.constantPool[oldIndex]; 67 if (constant != null) 68 { 69 comparableConstantPool[sortLength++] = 70 new ComparableConstant(programClass, oldIndex, constant); 71 } 72 } 73 74 // Sort the array. 75 Arrays.sort(comparableConstantPool, 0, sortLength); 76 77 // Save the sorted elements. 78 int newLength = 1; 79 int newIndex = 1; 80 ComparableConstant previousComparableConstant = null; 81 for (int sortIndex = 0; sortIndex < sortLength; sortIndex++) 82 { 83 ComparableConstant comparableConstant = comparableConstantPool[sortIndex]; 84 85 // Isn't this a duplicate of the previous constant? 86 if (!comparableConstant.equals(previousComparableConstant)) 87 { 88 // Remember the index of the new entry. 89 newIndex = newLength; 90 91 // Copy the sorted constant pool entry over to the constant pool. 92 Constant constant = comparableConstant.getConstant(); 93 94 newConstantPool[newLength++] = constant; 95 96 // Long entries take up two slots, the second of which is null. 97 int tag = constant.getTag(); 98 if (tag == ClassConstants.CONSTANT_Long || 99 tag == ClassConstants.CONSTANT_Double) 100 { 101 newConstantPool[newLength++] = null; 102 } 103 104 previousComparableConstant = comparableConstant; 105 } 106 107 // Fill out the map array. 108 constantIndexMap[comparableConstant.getIndex()] = newIndex; 109 } 110 111 // Copy the new constant pool over. 112 System.arraycopy(newConstantPool, 0, programClass.constantPool, 0, newLength); 113 114 // Clear any remaining entries. 115 for (int index = newLength; index < constantPoolCount; index++) 116 { 117 programClass.constantPool[index] = null; 118 } 119 120 programClass.u2constantPoolCount = newLength; 121 122 // Remap all constant pool references. 123 constantPoolRemapper.setConstantIndexMap(constantIndexMap); 124 constantPoolRemapper.visitProgramClass(programClass); 125 } 126 } 127