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.classfile.editor; 22 23 import proguard.classfile.*; 24 import proguard.classfile.attribute.*; 25 import proguard.classfile.attribute.visitor.*; 26 import proguard.classfile.instruction.*; 27 import proguard.classfile.instruction.visitor.InstructionVisitor; 28 import proguard.classfile.util.SimplifiedVisitor; 29 30 /** 31 * This AttributeVisitor remaps variable indexes in all attributes that it 32 * visits, based on a given index map. 33 * 34 * @author Eric Lafortune 35 */ 36 public class VariableRemapper 37 extends SimplifiedVisitor 38 implements AttributeVisitor, 39 InstructionVisitor, 40 LocalVariableInfoVisitor, 41 LocalVariableTypeInfoVisitor 42 { 43 private final CodeAttributeEditor codeAttributeEditor = new CodeAttributeEditor(); 44 45 private int[] variableMap; 46 47 48 /** 49 * Sets the given mapping of old variable indexes to their new indexes. 50 * Variables that should disappear can be mapped to -1. 51 */ 52 public void setVariableMap(int[] variableMap) 53 { 54 this.variableMap = variableMap; 55 } 56 57 58 // Implementations for AttributeVisitor. 59 60 public void visitAnyAttribute(Clazz clazz, Attribute attribute) {} 61 62 63 public void visitCodeAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute) 64 { 65 // Initially, the code attribute editor doesn't contain any changes. 66 codeAttributeEditor.reset(codeAttribute.u4codeLength); 67 68 // Remap the variables of the instructions. 69 codeAttribute.instructionsAccept(clazz, method, this); 70 71 // Apply the code atribute editor. 72 codeAttributeEditor.visitCodeAttribute(clazz, method, codeAttribute); 73 74 // Remap the variables of the attributes. 75 codeAttribute.attributesAccept(clazz, method, this); 76 } 77 78 79 public void visitLocalVariableTableAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute, LocalVariableTableAttribute localVariableTableAttribute) 80 { 81 // Remap the variable references of the local variables. 82 localVariableTableAttribute.localVariablesAccept(clazz, method, codeAttribute, this); 83 84 // Remove local variables that haven't been mapped. 85 localVariableTableAttribute.u2localVariableTableLength = 86 removeEmptyLocalVariables(localVariableTableAttribute.localVariableTable, 87 localVariableTableAttribute.u2localVariableTableLength); 88 } 89 90 91 public void visitLocalVariableTypeTableAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute, LocalVariableTypeTableAttribute localVariableTypeTableAttribute) 92 { 93 // Remap the variable references of the local variables. 94 localVariableTypeTableAttribute.localVariablesAccept(clazz, method, codeAttribute, this); 95 96 // Remove local variables that haven't been mapped. 97 localVariableTypeTableAttribute.u2localVariableTypeTableLength = 98 removeEmptyLocalVariableTypes(localVariableTypeTableAttribute.localVariableTypeTable, 99 localVariableTypeTableAttribute.u2localVariableTypeTableLength); 100 } 101 102 103 // Implementations for LocalVariableInfoVisitor. 104 105 public void visitLocalVariableInfo(Clazz clazz, Method method, CodeAttribute codeAttribute, LocalVariableInfo localVariableInfo) 106 { 107 localVariableInfo.u2index = 108 remapVariable(localVariableInfo.u2index); 109 } 110 111 112 // Implementations for LocalVariableTypeInfoVisitor. 113 114 public void visitLocalVariableTypeInfo(Clazz clazz, Method method, CodeAttribute codeAttribute, LocalVariableTypeInfo localVariableTypeInfo) 115 { 116 localVariableTypeInfo.u2index = 117 remapVariable(localVariableTypeInfo.u2index); 118 } 119 120 121 // Implementations for InstructionVisitor. 122 123 public void visitAnyInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, Instruction instruction) {} 124 125 126 public void visitVariableInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, VariableInstruction variableInstruction) 127 { 128 // Is the new variable index different from the original one? 129 int oldVariableIndex = variableInstruction.variableIndex; 130 int newVariableIndex = remapVariable(oldVariableIndex); 131 if (newVariableIndex != oldVariableIndex) 132 { 133 // Replace the instruction. 134 Instruction replacementInstruction = 135 new VariableInstruction(variableInstruction.opcode, 136 newVariableIndex, 137 variableInstruction.constant).shrink(); 138 139 codeAttributeEditor.replaceInstruction(offset, replacementInstruction); 140 } 141 } 142 143 144 // Small utility methods. 145 146 /** 147 * Returns the new variable index of the given variable. 148 */ 149 private int remapVariable(int variableIndex) 150 { 151 return variableMap[variableIndex]; 152 } 153 154 155 /** 156 * Returns the given list of local variables, without the ones that have 157 * been removed. 158 */ 159 private int removeEmptyLocalVariables(LocalVariableInfo[] localVariableInfos, 160 int localVariableInfoCount) 161 { 162 // Overwrite all empty local variable entries. 163 int newIndex = 0; 164 for (int index = 0; index < localVariableInfoCount; index++) 165 { 166 LocalVariableInfo localVariableInfo = localVariableInfos[index]; 167 if (localVariableInfo.u2index >= 0) 168 { 169 localVariableInfos[newIndex++] = localVariableInfo; 170 } 171 } 172 173 return newIndex; 174 } 175 176 177 /** 178 * Returns the given list of local variable types, without the ones that 179 * have been removed. 180 */ 181 private int removeEmptyLocalVariableTypes(LocalVariableTypeInfo[] localVariableTypeInfos, 182 int localVariableTypeInfoCount) 183 { 184 // Overwrite all empty local variable type entries. 185 int newIndex = 0; 186 for (int index = 0; index < localVariableTypeInfoCount; index++) 187 { 188 LocalVariableTypeInfo localVariableTypeInfo = localVariableTypeInfos[index]; 189 if (localVariableTypeInfo.u2index >= 0) 190 { 191 localVariableTypeInfos[newIndex++] = localVariableTypeInfo; 192 } 193 } 194 195 return newIndex; 196 } 197 } 198