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