DuplicateInitializerInvocationFixer.java revision 9f606f95f03a75961498803e24bee6799a7c0885
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.optimize;
22
23import proguard.classfile.*;
24import proguard.classfile.attribute.*;
25import proguard.classfile.attribute.visitor.AttributeVisitor;
26import proguard.classfile.constant.*;
27import proguard.classfile.constant.visitor.ConstantVisitor;
28import proguard.classfile.editor.CodeAttributeEditor;
29import proguard.classfile.instruction.*;
30import proguard.classfile.instruction.visitor.InstructionVisitor;
31import proguard.classfile.util.SimplifiedVisitor;
32import proguard.classfile.visitor.MemberVisitor;
33
34/**
35 * This AttributeVisitor adds an additional integer parameter to the tweaked
36 * initialization method invocations that it visits.
37 */
38public class DuplicateInitializerInvocationFixer
39extends      SimplifiedVisitor
40implements   AttributeVisitor,
41             InstructionVisitor,
42             ConstantVisitor,
43             MemberVisitor
44{
45    private static final boolean DEBUG = false;
46
47    private final InstructionVisitor extraAddedInstructionVisitor;
48
49    private final CodeAttributeEditor codeAttributeEditor = new CodeAttributeEditor();
50
51    private String  descriptor;
52    private boolean hasBeenFixed;
53
54
55    /**
56     * Creates a new EvaluationSimplifier.
57     */
58    public DuplicateInitializerInvocationFixer()
59    {
60        this(null);
61    }
62
63
64    /**
65     * Creates a new EvaluationSimplifier.
66     * @param extraAddedInstructionVisitor an optional extra visitor for all
67     *                                     added instructions.
68     */
69    public DuplicateInitializerInvocationFixer(InstructionVisitor extraAddedInstructionVisitor)
70    {
71        this.extraAddedInstructionVisitor = extraAddedInstructionVisitor;
72    }
73
74
75   // Implementations for AttributeVisitor.
76
77    public void visitAnyAttribute(Clazz clazz, Attribute attribute) {}
78
79
80    public void visitCodeAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute)
81    {
82
83        // Reset the code changes.
84        codeAttributeEditor.reset(codeAttribute.u4codeLength);
85
86        // Fix any duplicate constructor invocations.
87        codeAttribute.instructionsAccept(clazz,
88                                         method,
89                                         this);
90
91        // Apply all accumulated changes to the code.
92        codeAttributeEditor.visitCodeAttribute(clazz, method, codeAttribute);
93    }
94
95
96    // Implementations for InstructionVisitor.
97
98    public void visitAnyInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, Instruction instruction) {}
99
100
101    public void visitConstantInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, ConstantInstruction constantInstruction)
102    {
103        if (constantInstruction.opcode == InstructionConstants.OP_INVOKESPECIAL)
104        {
105            hasBeenFixed = false;
106            clazz.constantPoolEntryAccept(constantInstruction.constantIndex, this);
107
108            if (hasBeenFixed)
109            {
110                Instruction extraInstruction =
111                    new SimpleInstruction(InstructionConstants.OP_ICONST_0);
112
113                codeAttributeEditor.insertBeforeInstruction(offset,
114                                                            extraInstruction);
115
116                if (DEBUG)
117                {
118                    System.out.println("DuplicateInitializerInvocationFixer:");
119                    System.out.println("  Inserting "+extraInstruction.toString()+" before "+constantInstruction.toString(offset));
120                }
121
122                if (extraAddedInstructionVisitor != null)
123                {
124                    extraInstruction.accept(null, null, null, offset, extraAddedInstructionVisitor);
125                }
126            }
127        }
128    }
129
130
131    // Implementations for ConstantVisitor.
132
133    public void visitMethodrefConstant(Clazz clazz, MethodrefConstant methodrefConstant)
134    {
135        // Check the referenced constructor descriptor.
136        descriptor = methodrefConstant.getType(clazz);
137        methodrefConstant.referencedMemberAccept(this);
138    }
139
140
141    // Implementations for MemberVisitor.
142
143    public void visitLibraryMethod(LibraryClass libraryClass, LibraryMethod libraryMethod) {}
144
145
146    public void visitProgramMethod(ProgramClass programClass, ProgramMethod programMethod)
147    {
148        hasBeenFixed = !descriptor.equals(programMethod.getDescriptor(programClass));
149    }
150}