StringSharer.java revision b72c5c2e5482cf10117b2b25f642f7616b2326c3
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 */
21package proguard.classfile.util;
22
23import proguard.classfile.*;
24import proguard.classfile.attribute.Attribute;
25import proguard.classfile.attribute.visitor.AttributeVisitor;
26import proguard.classfile.constant.*;
27import proguard.classfile.constant.visitor.ConstantVisitor;
28import proguard.classfile.visitor.ClassVisitor;
29
30/**
31 * This ClassVisitor shares strings in the class files that it visits.
32 *
33 * @author Eric Lafortune
34 */
35public class StringSharer
36extends      SimplifiedVisitor
37implements   ClassVisitor,
38             ConstantVisitor,
39             AttributeVisitor
40{
41    // A fields acting as an argument for the visitor methods.
42    private String name;
43    private String type;
44
45
46    // Implementations for ClassVisitor.
47
48    public void visitProgramClass(ProgramClass programClass)
49    {
50        // Replace name strings in the constant pool by shared strings.
51        programClass.constantPoolEntriesAccept(this);
52
53        // Replace attribute name strings in the constant pool by internalized
54        // strings.
55        programClass.attributesAccept(this);
56    }
57
58
59    public void visitLibraryClass(LibraryClass libraryClass)
60    {
61        // Replace the super class name string by the shared name string.
62        Clazz superClass = libraryClass.superClass;
63        if (superClass != null)
64        {
65            libraryClass.superClassName = superClass.getName();
66        }
67    }
68
69
70    // Implementations for ConstantVisitor.
71
72
73    public void visitAnyConstant(Clazz clazz, Constant constant) {}
74
75
76    public void visitAnyStringConstant(Clazz clazz, StringConstant stringConstant)
77    {
78        Member referencedMember = stringConstant.referencedMember;
79        if (referencedMember != null)
80        {
81            Clazz referencedClass = stringConstant.referencedClass;
82
83            // Put the actual class member's name in the class pool.
84            name = referencedMember.getName(referencedClass);
85            clazz.constantPoolEntryAccept(stringConstant.u2stringIndex, this);
86        }
87    }
88
89
90    public void visitAnyRefConstant(Clazz clazz, RefConstant refConstant)
91    {
92        Member referencedMember = refConstant.referencedMember;
93        if (referencedMember != null)
94        {
95            Clazz referencedClass = refConstant.referencedClass;
96
97            // Put the actual class member's name and type strings in the class
98            // pool.
99            name = referencedMember.getName(referencedClass);
100            type = referencedMember.getDescriptor(referencedClass);
101            clazz.constantPoolEntryAccept(refConstant.u2nameAndTypeIndex, this);
102        }
103    }
104
105
106    public void visitNameAndTypeConstant(Clazz clazz, NameAndTypeConstant nameAndTypeConstant)
107    {
108        if (name != null)
109        {
110            // Put the actual class member's name and type strings in the class
111            // pool.
112            clazz.constantPoolEntryAccept(nameAndTypeConstant.u2nameIndex, this);
113            name = type;
114            clazz.constantPoolEntryAccept(nameAndTypeConstant.u2descriptorIndex, this);
115        }
116    }
117
118
119    public void visitClassConstant(Clazz clazz, ClassConstant classConstant)
120    {
121        Clazz referencedClass = classConstant.referencedClass;
122        if (referencedClass != null)
123        {
124            // Put the actual class's name string in the class pool.
125            name = referencedClass.getName();
126            clazz.constantPoolEntryAccept(classConstant.u2nameIndex, this);
127        }
128    }
129
130
131    public void visitUtf8Constant(Clazz clazz, Utf8Constant utf8Constant)
132    {
133        // Do we have a new string to put into this constant?
134        if (name != null)
135        {
136            // Replace the string, if it's actually the same.
137            if (name.equals(utf8Constant.getString()))
138            {
139                utf8Constant.setString(name);
140            }
141
142            name = null;
143        }
144    }
145
146
147    // Implementations for AttributeVisitor.
148
149    public void visitAnyAttribute(Clazz clazz, Attribute attribute)
150    {
151        // Put the internalized attribute's name string in the class pool.
152        name = attribute.getAttributeName(clazz).intern();
153        clazz.constantPoolEntryAccept(attribute.u2attributeNameIndex, this);
154    }
155}
156