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.classfile.editor; 22 23import proguard.classfile.*; 24import proguard.classfile.attribute.*; 25import proguard.classfile.attribute.visitor.*; 26import proguard.classfile.instruction.*; 27import proguard.classfile.instruction.visitor.InstructionVisitor; 28import proguard.classfile.util.SimplifiedVisitor; 29import proguard.optimize.info.VariableUsageMarker; 30 31/** 32 * This AttributeVisitor cleans up unused variables in all attributes that it 33 * visits. 34 * 35 * @author Eric Lafortune 36 */ 37public class VariableCleaner 38extends SimplifiedVisitor 39implements AttributeVisitor 40{ 41 private final VariableUsageMarker variableUsageMarker = new VariableUsageMarker(); 42 43 44 // Implementations for AttributeVisitor. 45 46 public void visitAnyAttribute(Clazz clazz, Attribute attribute) {} 47 48 49 public void visitCodeAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute) 50 { 51 // Figure out the local variables that are used by the code. 52 variableUsageMarker.visitCodeAttribute(clazz, method, codeAttribute); 53 54 // Clean up the variables of the attributes. 55 codeAttribute.attributesAccept(clazz, method, this); 56 } 57 58 59 public void visitLocalVariableTableAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute, LocalVariableTableAttribute localVariableTableAttribute) 60 { 61 // Clean up local variables that aren't used. 62 localVariableTableAttribute.u2localVariableTableLength = 63 removeEmptyLocalVariables(localVariableTableAttribute.localVariableTable, 64 localVariableTableAttribute.u2localVariableTableLength, 65 codeAttribute.u2maxLocals); 66 } 67 68 69 public void visitLocalVariableTypeTableAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute, LocalVariableTypeTableAttribute localVariableTypeTableAttribute) 70 { 71 // Clean up local variables that aren't used. 72 localVariableTypeTableAttribute.u2localVariableTypeTableLength = 73 removeEmptyLocalVariableTypes(localVariableTypeTableAttribute.localVariableTypeTable, 74 localVariableTypeTableAttribute.u2localVariableTypeTableLength, 75 codeAttribute.u2maxLocals); 76 } 77 78 79 // Small utility methods. 80 81 /** 82 * Returns the given list of local variables, without the ones that aren't 83 * used 84 */ 85 private int removeEmptyLocalVariables(LocalVariableInfo[] localVariableInfos, 86 int localVariableInfoCount, 87 int maxLocals) 88 { 89 // Overwrite all empty local variable entries. 90 int newIndex = 0; 91 for (int index = 0; index < localVariableInfoCount && index < maxLocals; index++) 92 { 93 if (variableUsageMarker.isVariableUsed(index)) 94 { 95 localVariableInfos[newIndex++] = localVariableInfos[index]; 96 } 97 } 98 99 // Clean up any remaining array elements. 100 for (int index = newIndex; index < localVariableInfoCount; index++) 101 { 102 localVariableInfos[index] = null; 103 } 104 105 return newIndex; 106 } 107 108 109 /** 110 * Returns the given list of local variable types, without the ones that 111 * aren't used 112 */ 113 private int removeEmptyLocalVariableTypes(LocalVariableTypeInfo[] localVariableTypeInfos, 114 int localVariableTypeInfoCount, 115 int maxLocals) 116 { 117 // Overwrite all empty local variable type entries. 118 int newIndex = 0; 119 for (int index = 0; index < localVariableTypeInfoCount && index < maxLocals; index++) 120 { 121 if (variableUsageMarker.isVariableUsed(index)) 122 { 123 localVariableTypeInfos[newIndex++] = localVariableTypeInfos[index]; 124 } 125 } 126 127 // Clean up any remaining array elements. 128 for (int index = newIndex; index < localVariableTypeInfoCount; index++) 129 { 130 localVariableTypeInfos[index] = null; 131 } 132 133 return newIndex; 134 } 135}