• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * ProGuard -- shrinking, optimization, obfuscation, and preverification
3  *             of Java bytecode.
4  *
5  * Copyright (c) 2002-2009 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.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 
visitProgramClass(ProgramClass programClass)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