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