1 /* 2 * ProGuard -- shrinking, optimization, obfuscation, and preverification 3 * of Java bytecode. 4 * 5 * Copyright (c) 2002-2009 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; 22 23 import proguard.classfile.*; 24 import proguard.classfile.attribute.*; 25 import proguard.classfile.attribute.visitor.AttributeVisitor; 26 import proguard.classfile.editor.*; 27 import proguard.classfile.util.*; 28 import proguard.classfile.visitor.MemberVisitor; 29 import proguard.optimize.info.ParameterUsageMarker; 30 31 /** 32 * This MemberVisitor removes unused parameters from the code of the methods 33 * that it visits. 34 * 35 * @see ParameterUsageMarker 36 * @see MethodStaticizer 37 * @see MethodDescriptorShrinker 38 * @author Eric Lafortune 39 */ 40 public class ParameterShrinker 41 extends SimplifiedVisitor 42 implements AttributeVisitor 43 { 44 private static final boolean DEBUG = false; 45 46 47 private final MemberVisitor extraVariableMemberVisitor; 48 49 private final VariableRemapper variableRemapper = new VariableRemapper(); 50 51 52 /** 53 * Creates a new ParameterShrinker. 54 */ 55 public ParameterShrinker() 56 { 57 this(null); 58 } 59 60 61 /** 62 * Creates a new ParameterShrinker with an extra visitor. 63 * @param extraVariableMemberVisitor an optional extra visitor for all 64 * removed parameters. 65 */ 66 public ParameterShrinker(MemberVisitor extraVariableMemberVisitor) 67 { 68 this.extraVariableMemberVisitor = extraVariableMemberVisitor; 69 } 70 71 72 // Implementations for AttributeVisitor. 73 74 public void visitAnyAttribute(Clazz clazz, Attribute attribute) {} 75 76 77 public void visitCodeAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute) 78 { 79 // Get the original parameter size that was saved. 80 int oldParameterSize = ParameterUsageMarker.getParameterSize(method); 81 82 // Compute the new parameter size from the shrunk descriptor. 83 int newParameterSize = 84 ClassUtil.internalMethodParameterSize(method.getDescriptor(clazz), 85 method.getAccessFlags()); 86 87 if (oldParameterSize > newParameterSize) 88 { 89 // Get the total size of the local variable frame. 90 int maxLocals = codeAttribute.u2maxLocals; 91 92 if (DEBUG) 93 { 94 System.out.println("ParameterShrinker: "+clazz.getName()+"."+method.getName(clazz)+method.getDescriptor(clazz)); 95 System.out.println(" Old parameter size = " + oldParameterSize); 96 System.out.println(" New parameter size = " + newParameterSize); 97 System.out.println(" Max locals = " + maxLocals); 98 } 99 100 // Create a variable map. 101 int[] variableMap = new int[maxLocals]; 102 103 // Move unused parameters right after the parameter block. 104 int usedParameterIndex = 0; 105 int unusedParameterIndex = newParameterSize; 106 for (int parameterIndex = 0; parameterIndex < oldParameterSize; parameterIndex++) 107 { 108 // Is the variable required as a parameter? 109 if (ParameterUsageMarker.isParameterUsed(method, parameterIndex)) 110 { 111 // Keep the variable as a parameter. 112 variableMap[parameterIndex] = usedParameterIndex++; 113 } 114 else 115 { 116 if (DEBUG) 117 { 118 System.out.println(" Deleting parameter #"+parameterIndex); 119 } 120 121 // Shift the variable to the unused parameter block, 122 // in case it is still used as a variable. 123 variableMap[parameterIndex] = unusedParameterIndex++; 124 125 // Visit the method, if required. 126 if (extraVariableMemberVisitor != null) 127 { 128 method.accept(clazz, extraVariableMemberVisitor); 129 } 130 } 131 } 132 133 // Fill out the remainder of the map. 134 for (int variableIndex = oldParameterSize; variableIndex < maxLocals; variableIndex++) 135 { 136 variableMap[variableIndex] = variableIndex; 137 } 138 139 // Set the map. 140 variableRemapper.setVariableMap(variableMap); 141 142 // Remap the variables. 143 variableRemapper.visitCodeAttribute(clazz, method, codeAttribute); 144 } 145 } 146 } 147