~ubuntu-branches/ubuntu/feisty/proguard/feisty

« back to all changes in this revision

Viewing changes to src/proguard/classfile/editor/MethodInvocationFixer.java

  • Committer: Bazaar Package Importer
  • Author(s): Sam Clegg
  • Date: 2005-11-13 09:42:59 UTC
  • mfrom: (1.1.1 upstream)
  • Revision ID: james.westby@ubuntu.com-20051113094259-432zf4yyw4890mmn
Tags: 3.4-1
* New upstream release (Closes: #338355)
* debian/control: bump standards version
* debian/copyright: update FSF address
* increase java stack size for proguard and proguardgui

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* $Id: MethodInvocationFixer.java,v 1.4 2005/08/13 21:01:04 eric Exp $
 
2
 *
 
3
 * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
 
4
 *
 
5
 * Copyright (c) 2002-2005 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.util.ClassUtil;
 
25
import proguard.classfile.attribute.CodeAttrInfo;
 
26
import proguard.classfile.instruction.*;
 
27
import proguard.classfile.visitor.*;
 
28
 
 
29
/**
 
30
 * This InstructionVisitor fixes all inappropriate special/virtual/static/interface
 
31
 * invocations.
 
32
 *
 
33
 * @author Eric Lafortune
 
34
 */
 
35
public class MethodInvocationFixer
 
36
implements   InstructionVisitor,
 
37
             CpInfoVisitor,
 
38
             MemberInfoVisitor
 
39
{
 
40
    private static final boolean DEBUG = false;
 
41
 
 
42
    private CodeAttrInfoEditor codeAttrInfoEditor;
 
43
 
 
44
    // Return values for the visitor methods.
 
45
    private boolean isMethodInvocation;
 
46
    private int     accessFlags;
 
47
    private boolean isInitializer;
 
48
    private boolean isInterfaceMethod;
 
49
    private int     parameterSize;
 
50
 
 
51
 
 
52
    /**
 
53
     * Creates a new MethodInvocationFixer.
 
54
     * @param codeAttrInfoEditor a code editor that can be used for
 
55
     *                           accumulating changes to the code.
 
56
     */
 
57
    public MethodInvocationFixer(CodeAttrInfoEditor codeAttrInfoEditor)
 
58
    {
 
59
        this.codeAttrInfoEditor = codeAttrInfoEditor;
 
60
    }
 
61
 
 
62
 
 
63
    // Implementations for InstructionVisitor.
 
64
 
 
65
    public void visitSimpleInstruction(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, int offset, SimpleInstruction simpleInstruction) {}
 
66
    public void visitVariableInstruction(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, int offset, VariableInstruction variableInstruction) {}
 
67
    public void visitBranchInstruction(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, int offset, BranchInstruction branchInstruction) {}
 
68
    public void visitTableSwitchInstruction(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, int offset, TableSwitchInstruction tableSwitchInstruction) {}
 
69
    public void visitLookUpSwitchInstruction(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, int offset, LookUpSwitchInstruction lookUpSwitchInstruction) {}
 
70
 
 
71
 
 
72
    public void visitCpInstruction(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, int offset, CpInstruction cpInstruction)
 
73
    {
 
74
        int cpIndex  = cpInstruction.cpIndex;
 
75
        int constant = cpInstruction.constant;
 
76
 
 
77
        // Get the constant pool entry's information.
 
78
        isMethodInvocation = false;
 
79
        isInterfaceMethod  = false;
 
80
        accessFlags        = 0;
 
81
        parameterSize      = constant;
 
82
 
 
83
        classFile.constantPoolEntryAccept(cpIndex, this);
 
84
 
 
85
        // Is it a method invocation?
 
86
        if (isMethodInvocation)
 
87
        {
 
88
            // Do we need to update the opcode?
 
89
            byte opcode = cpInstruction.opcode;
 
90
 
 
91
            // Is the method static?
 
92
            if ((accessFlags & ClassConstants.INTERNAL_ACC_STATIC) != 0)
 
93
            {
 
94
                // But is it not a static invocation?
 
95
                if (opcode != InstructionConstants.OP_INVOKESTATIC)
 
96
                {
 
97
                    // Replace the invocation by an invokestatic instruction.
 
98
                    Instruction replacementInstruction =
 
99
                        new CpInstruction(InstructionConstants.OP_INVOKESTATIC,
 
100
                                          cpIndex).shrink();
 
101
 
 
102
                    codeAttrInfoEditor.replaceInstruction(offset, replacementInstruction);
 
103
 
 
104
                    if (DEBUG)
 
105
                    {
 
106
                        debug(classFile, methodInfo, offset, cpInstruction, replacementInstruction);
 
107
                    }
 
108
                }
 
109
            }
 
110
 
 
111
            // Is the method private, or an instance initializer?
 
112
            else if ((accessFlags & ClassConstants.INTERNAL_ACC_PRIVATE) != 0 ||
 
113
                     isInitializer)
 
114
            {
 
115
                // But is it not a special invocation?
 
116
                if (opcode != InstructionConstants.OP_INVOKESPECIAL)
 
117
                {
 
118
                    // Replace the invocation by an invokespecial instruction.
 
119
                    Instruction replacementInstruction =
 
120
                        new CpInstruction(InstructionConstants.OP_INVOKESPECIAL,
 
121
                                          cpIndex).shrink();
 
122
 
 
123
                    codeAttrInfoEditor.replaceInstruction(offset, replacementInstruction);
 
124
 
 
125
                    if (DEBUG)
 
126
                    {
 
127
                        debug(classFile, methodInfo, offset, cpInstruction, replacementInstruction);
 
128
                    }
 
129
                }
 
130
            }
 
131
 
 
132
            // Is the method an interface method?
 
133
            else if (isInterfaceMethod)
 
134
            {
 
135
                // But is it not an interface invocation, or is the parameter
 
136
                // size incorrect?
 
137
                if (opcode != InstructionConstants.OP_INVOKEINTERFACE ||
 
138
                    parameterSize != constant)
 
139
                {
 
140
                    // Fix the parameter size of the interface invocation.
 
141
                    Instruction replacementInstruction =
 
142
                        new CpInstruction(InstructionConstants.OP_INVOKEINTERFACE,
 
143
                                          cpIndex,
 
144
                                          parameterSize).shrink();
 
145
 
 
146
                    codeAttrInfoEditor.replaceInstruction(offset, replacementInstruction);
 
147
 
 
148
                    if (DEBUG)
 
149
                    {
 
150
                        debug(classFile, methodInfo, offset, cpInstruction, replacementInstruction);
 
151
                    }
 
152
                }
 
153
            }
 
154
 
 
155
            // The method is not static, private, an instance initializer, or
 
156
            // an interface method.
 
157
            else
 
158
            {
 
159
                // But is it not a virtual invocation (or a special invocation,
 
160
                // which is allowed for super calls)?
 
161
                if (opcode != InstructionConstants.OP_INVOKEVIRTUAL &&
 
162
                    opcode != InstructionConstants.OP_INVOKESPECIAL)
 
163
                {
 
164
                    // Replace the invocation by an invokevirtual instruction.
 
165
                    Instruction replacementInstruction =
 
166
                        new CpInstruction(InstructionConstants.OP_INVOKEVIRTUAL,
 
167
                                          cpIndex).shrink();
 
168
 
 
169
                    codeAttrInfoEditor.replaceInstruction(offset, replacementInstruction);
 
170
 
 
171
                    if (DEBUG)
 
172
                    {
 
173
                        debug(classFile, methodInfo, offset, cpInstruction, replacementInstruction);
 
174
                    }
 
175
                }
 
176
            }
 
177
        }
 
178
    }
 
179
 
 
180
 
 
181
    // Implementations for CpInfoVisitor.
 
182
 
 
183
    public void visitIntegerCpInfo(ClassFile classFile, IntegerCpInfo integerCpInfo) {}
 
184
    public void visitLongCpInfo(ClassFile classFile, LongCpInfo longCpInfo) {}
 
185
    public void visitFloatCpInfo(ClassFile classFile, FloatCpInfo floatCpInfo) {}
 
186
    public void visitDoubleCpInfo(ClassFile classFile, DoubleCpInfo doubleCpInfo) {}
 
187
    public void visitStringCpInfo(ClassFile classFile, StringCpInfo stringCpInfo) {}
 
188
    public void visitFieldrefCpInfo(ClassFile classFile, FieldrefCpInfo fieldrefCpInfo) {}
 
189
    public void visitNameAndTypeCpInfo(ClassFile classFile, NameAndTypeCpInfo nameAndTypeCpInfo) {}
 
190
    public void visitUtf8CpInfo(ClassFile classFile, Utf8CpInfo utf8CpInfo) {}
 
191
 
 
192
 
 
193
    public void visitInterfaceMethodrefCpInfo(ClassFile classFile, InterfaceMethodrefCpInfo interfaceMethodrefCpInfo)
 
194
    {
 
195
        // Check if this is an interface method.
 
196
        classFile.constantPoolEntryAccept(interfaceMethodrefCpInfo.u2classIndex, this);
 
197
 
 
198
        // Get the referenced method's access flags.
 
199
        interfaceMethodrefCpInfo.referencedMemberInfoAccept(this);
 
200
    }
 
201
 
 
202
 
 
203
    public void visitMethodrefCpInfo(ClassFile classFile, MethodrefCpInfo methodrefCpInfo)
 
204
    {
 
205
        // Check if this is an interface method.
 
206
        classFile.constantPoolEntryAccept(methodrefCpInfo.u2classIndex, this);
 
207
 
 
208
        // Get the referenced method's access flags.
 
209
        methodrefCpInfo.referencedMemberInfoAccept(this);
 
210
    }
 
211
 
 
212
 
 
213
    public void visitClassCpInfo(ClassFile classFile, ClassCpInfo classCpInfo)
 
214
    {
 
215
        // Check if this class entry refers to an interface class.
 
216
        ClassFile referencedClassFile = classCpInfo.referencedClassFile;
 
217
        if (referencedClassFile != null)
 
218
        {
 
219
            isInterfaceMethod = (referencedClassFile.getAccessFlags() & ClassConstants.INTERNAL_ACC_INTERFACE) != 0;
 
220
        }
 
221
    }
 
222
 
 
223
 
 
224
    // Implementations for MemberInfoVisitor.
 
225
 
 
226
    public void visitProgramFieldInfo(ProgramClassFile programClassFile, ProgramFieldInfo programFieldInfo) {}
 
227
 
 
228
    public void visitProgramMethodInfo(ProgramClassFile programClassFile, ProgramMethodInfo programMethodInfo)
 
229
    {
 
230
        visitMethodInfo(programClassFile, programMethodInfo);
 
231
    }
 
232
 
 
233
 
 
234
    public void visitLibraryFieldInfo(LibraryClassFile libraryClassFile, LibraryFieldInfo libraryFieldInfo) {}
 
235
 
 
236
    public void visitLibraryMethodInfo(LibraryClassFile libraryClassFile, LibraryMethodInfo libraryMethodInfo)
 
237
    {
 
238
        visitMethodInfo(libraryClassFile, libraryMethodInfo);
 
239
    }
 
240
 
 
241
 
 
242
    private void visitMethodInfo(ClassFile classFile, MethodInfo methodInfo)
 
243
    {
 
244
        // We've found a method definition.
 
245
        isMethodInvocation = true;
 
246
 
 
247
        // Get the method's access flags.
 
248
        accessFlags = methodInfo.getAccessFlags();
 
249
 
 
250
        // Check if this is an instance initializer.
 
251
        isInitializer = methodInfo.getName(classFile).equals(ClassConstants.INTERNAL_METHOD_NAME_INIT);
 
252
 
 
253
        // Remember the parameter size of interface methods.
 
254
        if (isInterfaceMethod)
 
255
        {
 
256
            parameterSize = ClassUtil.internalMethodParameterSize(methodInfo.getDescriptor(classFile)) + 1 << 8;
 
257
        }
 
258
    }
 
259
 
 
260
 
 
261
    // Small utility methods.
 
262
 
 
263
    private void debug(ClassFile     classFile,
 
264
                       MethodInfo    methodInfo,
 
265
                       int           offset,
 
266
                       CpInstruction cpInstruction,
 
267
                       Instruction   replacementInstruction)
 
268
    {
 
269
        System.out.println("MethodInvocationFixer:");
 
270
        System.out.println("  Class file       = "+classFile.getName());
 
271
        System.out.println("  Method           = "+methodInfo.getName(classFile)+methodInfo.getDescriptor(classFile));
 
272
        System.out.println("  Instruction      = "+cpInstruction.toString(offset));
 
273
        System.out.println("  Interface method = "+isInterfaceMethod);
 
274
        if (isInterfaceMethod)
 
275
        {
 
276
            System.out.println("  Parameter size   = "+parameterSize);
 
277
        }
 
278
        System.out.println("  Replacement instruction = "+replacementInstruction.toString(offset));
 
279
    }
 
280
}