• 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.evaluation;
22 
23 import proguard.classfile.*;
24 import proguard.classfile.attribute.*;
25 import proguard.classfile.attribute.visitor.*;
26 import proguard.classfile.constant.*;
27 import proguard.classfile.editor.*;
28 import proguard.classfile.instruction.*;
29 import proguard.classfile.instruction.visitor.InstructionVisitor;
30 import proguard.classfile.util.SimplifiedVisitor;
31 import proguard.classfile.visitor.*;
32 import proguard.optimize.info.SimpleEnumMarker;
33 import proguard.optimize.peephole.*;
34 
35 /**
36  * This ClassVisitor simplifies the classes that it visits to simple enums.
37  *
38  * @see SimpleEnumMarker
39  * @see MemberReferenceFixer
40  * @author Eric Lafortune
41  */
42 public class SimpleEnumClassSimplifier
43 extends      SimplifiedVisitor
44 implements   ClassVisitor,
45              AttributeVisitor,
46              InstructionVisitor
47 {
48     //*
49     private static final boolean DEBUG = false;
50     /*/
51     private static       boolean DEBUG = System.getProperty("enum") != null;
52     //*/
53 
54 
55     private static final int ENUM_CLASS_NAME          = InstructionSequenceReplacer.A;
56     private static final int ENUM_TYPE_NAME           = InstructionSequenceReplacer.B;
57     private static final int ENUM_CONSTANT_NAME       = InstructionSequenceReplacer.X;
58     private static final int ENUM_CONSTANT_ORDINAL    = InstructionSequenceReplacer.Y;
59     private static final int ENUM_CONSTANT_FIELD_NAME = InstructionSequenceReplacer.Z;
60 
61     private static final int STRING_ENUM_CONSTANT_NAME   = 0;
62 
63     private static final int METHOD_ENUM_INIT            = 1;
64     private static final int FIELD_ENUM_CONSTANT         = 2;
65 
66     private static final int CLASS_ENUM                  = 3;
67 
68     private static final int NAME_AND_TYPE_ENUM_INIT     = 4;
69     private static final int NAME_AND_TYPE_ENUM_CONSTANT = 5;
70 
71     private static final int UTF8_INIT                   = 6;
72     private static final int UTF8_STRING_I               = 7;
73 
74 
75     private static final Constant[] CONSTANTS = new Constant[]
76     {
77         new StringConstant(ENUM_CONSTANT_NAME, null, null),
78 
79         new MethodrefConstant(CLASS_ENUM, NAME_AND_TYPE_ENUM_INIT,     null, null),
80         new FieldrefConstant( CLASS_ENUM, NAME_AND_TYPE_ENUM_CONSTANT, null, null),
81 
82         new ClassConstant(ENUM_CLASS_NAME,  null),
83 
84         new NameAndTypeConstant(UTF8_INIT, UTF8_STRING_I),
85         new NameAndTypeConstant(ENUM_CONSTANT_FIELD_NAME, ENUM_TYPE_NAME),
86 
87         new Utf8Constant(ClassConstants.METHOD_NAME_INIT),
88         new Utf8Constant(ClassConstants.METHOD_TYPE_INIT_ENUM),
89     };
90 
91     private static final Instruction[] INSTRUCTIONS = new Instruction[]
92     {
93         new ConstantInstruction(InstructionConstants.OP_NEW, CLASS_ENUM),
94         new SimpleInstruction(InstructionConstants.OP_DUP),
95         new ConstantInstruction(InstructionConstants.OP_LDC, STRING_ENUM_CONSTANT_NAME),
96         new SimpleInstruction(InstructionConstants.OP_ICONST_0, ENUM_CONSTANT_ORDINAL),
97         new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_ENUM_INIT),
98     };
99 
100     private static final Instruction[] REPLACEMENT_INSTRUCTIONS = new Instruction[]
101     {
102         new SimpleInstruction(InstructionConstants.OP_SIPUSH, ENUM_CONSTANT_ORDINAL),
103         new SimpleInstruction(InstructionConstants.OP_ICONST_1),
104         new SimpleInstruction(InstructionConstants.OP_IADD),
105     };
106 
107 
108     private final CodeAttributeEditor codeAttributeEditor =
109         new CodeAttributeEditor(true, true);
110 
111     private final InstructionSequenceReplacer instructionSequenceReplacer =
112         new InstructionSequenceReplacer(CONSTANTS,
113                                         INSTRUCTIONS,
114                                         REPLACEMENT_INSTRUCTIONS,
115                                         null,
116                                         codeAttributeEditor);
117 
118     private final MemberVisitor initializerSimplifier = new AllAttributeVisitor(this);
119 
120 
121     // Implementations for ClassVisitor.
122 
visitProgramClass(ProgramClass programClass)123     public void visitProgramClass(ProgramClass programClass)
124     {
125         if (DEBUG)
126         {
127             System.out.println("SimpleEnumClassSimplifier: ["+programClass.getName()+"]");
128         }
129 
130         // Unmark the class as an enum.
131         programClass.u2accessFlags &= ~ClassConstants.ACC_ENUM;
132 
133         // Remove the valueOf method, if present.
134         Method valueOfMethod =
135             programClass.findMethod(ClassConstants.METHOD_NAME_VALUEOF, null);
136         if (valueOfMethod != null)
137         {
138             new ClassEditor(programClass).removeMethod(valueOfMethod);
139         }
140 
141         // Simplify the static initializer.
142         programClass.methodAccept(ClassConstants.METHOD_NAME_CLINIT,
143                                   ClassConstants.METHOD_TYPE_CLINIT,
144                                   initializerSimplifier);
145     }
146 
147 
148     // Implementations for AttributeVisitor.
149 
visitAnyAttribute(Clazz clazz, Attribute attribute)150     public void visitAnyAttribute(Clazz clazz, Attribute attribute) {}
151 
152 
visitCodeAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute)153     public void visitCodeAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute)
154     {
155         // Set up the code attribute editor.
156         codeAttributeEditor.reset(codeAttribute.u4codeLength);
157 
158         // Find the peephole changes.
159         codeAttribute.instructionsAccept(clazz, method, instructionSequenceReplacer);
160 
161         // Apply the peephole changes.
162         codeAttributeEditor.visitCodeAttribute(clazz, method, codeAttribute);
163     }
164 }
165