1 /* 2 * ProGuard -- shrinking, optimization, obfuscation, and preverification 3 * of Java bytecode. 4 * 5 * Copyright (c) 2002-2014 Eric Lafortune (eric (at) 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.peephole; 22 23 import proguard.classfile.*; 24 import proguard.classfile.attribute.*; 25 import proguard.classfile.attribute.visitor.AttributeVisitor; 26 import proguard.classfile.editor.VariableEditor; 27 import proguard.classfile.util.*; 28 import proguard.classfile.visitor.MemberVisitor; 29 import proguard.optimize.*; 30 import proguard.optimize.info.*; 31 32 /** 33 * This MemberVisitor removes unused local variables from the code of the methods 34 * that it visits. 35 * 36 * @see ParameterUsageMarker 37 * @see MethodStaticizer 38 * @see MethodDescriptorShrinker 39 * @author Eric Lafortune 40 */ 41 public class VariableShrinker 42 extends SimplifiedVisitor 43 implements AttributeVisitor 44 { 45 private static final boolean DEBUG = false; 46 47 48 private final MemberVisitor extraVariableMemberVisitor; 49 50 private final VariableUsageMarker variableUsageMarker = new VariableUsageMarker(); 51 private final VariableEditor variableEditor = new VariableEditor(); 52 53 54 /** 55 * Creates a new VariableShrinker. 56 */ 57 public VariableShrinker() 58 { 59 this(null); 60 } 61 62 63 /** 64 * Creates a new VariableShrinker with an extra visitor. 65 * @param extraVariableMemberVisitor an optional extra visitor for all 66 * removed variables. 67 */ 68 public VariableShrinker(MemberVisitor extraVariableMemberVisitor) 69 { 70 this.extraVariableMemberVisitor = extraVariableMemberVisitor; 71 } 72 73 74 // Implementations for AttributeVisitor. 75 76 public void visitAnyAttribute(Clazz clazz, Attribute attribute) {} 77 78 79 public void visitCodeAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute) 80 { 81 if ((method.getAccessFlags() & ClassConstants.ACC_ABSTRACT) == 0) 82 { 83 // Compute the parameter size. 84 int parameterSize = 85 ClassUtil.internalMethodParameterSize(method.getDescriptor(clazz), 86 method.getAccessFlags()); 87 88 // Get the total size of the local variable frame. 89 int maxLocals = codeAttribute.u2maxLocals; 90 91 if (DEBUG) 92 { 93 System.out.println("VariableShrinker: "+clazz.getName()+"."+method.getName(clazz)+method.getDescriptor(clazz)); 94 System.out.println(" Parameter size = " + parameterSize); 95 System.out.println(" Max locals = " + maxLocals); 96 } 97 98 // Figure out the local variables that are used by the code. 99 variableUsageMarker.visitCodeAttribute(clazz, method, codeAttribute); 100 101 // Delete unused local variables from the local variable frame. 102 variableEditor.reset(maxLocals); 103 104 for (int variableIndex = parameterSize; variableIndex < maxLocals; variableIndex++) 105 { 106 // Is the variable not required? 107 if (!variableUsageMarker.isVariableUsed(variableIndex)) 108 { 109 if (DEBUG) 110 { 111 System.out.println(" Deleting local variable #"+variableIndex); 112 } 113 114 // Delete the unused variable. 115 variableEditor.deleteVariable(variableIndex); 116 117 // Visit the method, if required. 118 if (extraVariableMemberVisitor != null) 119 { 120 method.accept(clazz, extraVariableMemberVisitor); 121 } 122 } 123 } 124 125 // Shift all remaining parameters and variables in the byte code. 126 variableEditor.visitCodeAttribute(clazz, method, codeAttribute); 127 } 128 } 129 } 130