• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * ProGuard -- shrinking, optimization, obfuscation, and preverification
3  *             of Java bytecode.
4  *
5  * Copyright (c) 2002-2014 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.optimize;
22 
23 import proguard.classfile.*;
24 import proguard.classfile.attribute.*;
25 import proguard.classfile.attribute.visitor.AttributeVisitor;
26 import proguard.classfile.constant.*;
27 import proguard.classfile.constant.visitor.ConstantVisitor;
28 import proguard.classfile.editor.CodeAttributeEditor;
29 import proguard.classfile.instruction.*;
30 import proguard.classfile.instruction.visitor.InstructionVisitor;
31 import proguard.classfile.util.*;
32 import 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  */
38 public class DuplicateInitializerInvocationFixer
39 extends      SimplifiedVisitor
40 implements   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 int    descriptorLengthDelta;
53 
54 
55     /**
56      * Creates a new DuplicateInitializerInvocationFixer.
57      */
DuplicateInitializerInvocationFixer()58     public DuplicateInitializerInvocationFixer()
59     {
60         this(null);
61     }
62 
63 
64     /**
65      * Creates a new DuplicateInitializerInvocationFixer.
66      * @param extraAddedInstructionVisitor an optional extra visitor for all
67      *                                     added instructions.
68      */
DuplicateInitializerInvocationFixer(InstructionVisitor extraAddedInstructionVisitor)69     public DuplicateInitializerInvocationFixer(InstructionVisitor extraAddedInstructionVisitor)
70     {
71         this.extraAddedInstructionVisitor = extraAddedInstructionVisitor;
72     }
73 
74 
75    // Implementations for AttributeVisitor.
76 
visitAnyAttribute(Clazz clazz, Attribute attribute)77     public void visitAnyAttribute(Clazz clazz, Attribute attribute) {}
78 
79 
visitCodeAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute)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 
visitAnyInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, Instruction instruction)98     public void visitAnyInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, Instruction instruction) {}
99 
100 
visitConstantInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, ConstantInstruction constantInstruction)101     public void visitConstantInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, ConstantInstruction constantInstruction)
102     {
103         if (constantInstruction.opcode == InstructionConstants.OP_INVOKESPECIAL)
104         {
105             descriptorLengthDelta = 0;
106             clazz.constantPoolEntryAccept(constantInstruction.constantIndex, this);
107 
108             if (descriptorLengthDelta > 0)
109             {
110                 Instruction extraInstruction =
111                     new SimpleInstruction(descriptorLengthDelta == 1 ?
112                                               InstructionConstants.OP_ICONST_0 :
113                                               InstructionConstants.OP_ACONST_NULL);
114 
115                 codeAttributeEditor.insertBeforeInstruction(offset,
116                                                             extraInstruction);
117 
118                 if (DEBUG)
119                 {
120                     System.out.println("  ["+clazz.getName()+"."+method.getName(clazz)+method.getDescriptor(clazz)+"] Inserting "+extraInstruction.toString()+" before "+constantInstruction.toString(offset));
121                 }
122 
123                 if (extraAddedInstructionVisitor != null)
124                 {
125                     extraInstruction.accept(null, null, null, offset, extraAddedInstructionVisitor);
126                 }
127             }
128         }
129     }
130 
131 
132     // Implementations for ConstantVisitor.
133 
visitAnyMethodrefConstant(Clazz clazz, RefConstant refConstant)134     public void visitAnyMethodrefConstant(Clazz clazz, RefConstant refConstant)
135     {
136         // Check the referenced constructor descriptor.
137         if (refConstant.getName(clazz).equals(ClassConstants.METHOD_NAME_INIT))
138         {
139             descriptor = refConstant.getType(clazz);
140 
141             refConstant.referencedMemberAccept(this);
142         }
143     }
144 
145 
146     // Implementations for MemberVisitor.
147 
visitLibraryMethod(LibraryClass libraryClass, LibraryMethod libraryMethod)148     public void visitLibraryMethod(LibraryClass libraryClass, LibraryMethod libraryMethod) {}
149 
150 
visitProgramMethod(ProgramClass programClass, ProgramMethod programMethod)151     public void visitProgramMethod(ProgramClass programClass, ProgramMethod programMethod)
152     {
153         descriptorLengthDelta =
154             programMethod.getDescriptor(programClass).length() - descriptor.length();
155 
156         if (DEBUG)
157         {
158             if (descriptorLengthDelta > 0)
159             {
160                 System.out.println("DuplicateInitializerInvocationFixer:");
161                 System.out.println("  ["+programClass.getName()+"."+programMethod.getName(programClass)+programMethod.getDescriptor(programClass)+"] ("+ClassUtil.externalClassAccessFlags(programMethod.getAccessFlags())+") referenced by:");
162             }
163         }
164     }
165 }
166