1 21 package proguard.optimize.evaluation; 22 23 import proguard.classfile.util.*; 24 import proguard.classfile.attribute.visitor.AttributeVisitor; 25 import proguard.classfile.attribute.*; 26 import proguard.classfile.editor.*; 27 import proguard.classfile.*; 28 29 35 public class VariableOptimizer 36 extends SimplifiedVisitor 37 implements AttributeVisitor 38 { 39 private static final boolean DEBUG = false; 41 44 45 private static final int MAX_VARIABLES_SIZE = 64; 46 47 private LivenessAnalyzer livenessAnalyzer = new LivenessAnalyzer(); 48 private VariableRemapper variableRemapper = new VariableRemapper(); 49 50 private int[] variableMap = new int[ClassConstants.TYPICAL_VARIABLES_SIZE]; 51 52 53 55 public void visitAnyAttribute(Clazz clazz, Attribute attribute) {} 56 57 58 public void visitCodeAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute) 59 { 60 64 initializeArrays(codeAttribute); 66 67 livenessAnalyzer.visitCodeAttribute(clazz, method, codeAttribute); 69 70 int parameterSize = ClassUtil.internalMethodParameterSize(method.getDescriptor(clazz)); 71 if ((method.getAccessFlags() & ClassConstants.INTERNAL_ACC_STATIC) == 0) 72 { 73 parameterSize++; 74 } 75 76 int variableSize = codeAttribute.u2maxLocals; 77 int codeLength = codeAttribute.u4codeLength; 78 79 boolean remapping = false; 80 81 for (int oldIndex = 0; oldIndex < variableSize; oldIndex++) 83 { 84 variableMap[oldIndex] = oldIndex; 86 87 if (oldIndex >= parameterSize && 89 oldIndex < MAX_VARIABLES_SIZE) 90 { 91 for (int newIndex = 0; newIndex < oldIndex; newIndex++) 93 { 94 if (areNonOverlapping(oldIndex, newIndex, codeLength)) 95 { 96 variableMap[oldIndex] = newIndex; 97 98 updateLiveness(oldIndex, newIndex, codeLength); 99 100 remapping = true; 101 102 break; 104 } 105 } 106 } 107 } 108 109 if (remapping) 111 { 112 if (DEBUG) 113 { 114 System.out.println("Remapping variables:"); 115 System.out.println(" Class "+ ClassUtil.externalClassName(clazz.getName())); 116 System.out.println(" Method "+ClassUtil.externalFullMethodDescription(clazz.getName(), 117 0, 118 method.getName(clazz), 119 method.getDescriptor(clazz))); 120 for (int index = 0; index < variableSize; index++) 121 { 122 System.out.println(" ["+index+"] -> ["+variableMap[index]+"]"); 123 } 124 } 125 126 variableRemapper.setVariableMap(variableMap); 127 variableRemapper.visitCodeAttribute(clazz, method, codeAttribute); 128 } 129 } 130 131 132 134 137 private void initializeArrays(CodeAttribute codeAttribute) 138 { 139 int codeLength = codeAttribute.u4codeLength; 140 141 if (variableMap.length < codeLength) 143 { 144 variableMap = new int[codeLength]; 145 } 146 } 147 148 149 152 private boolean areNonOverlapping(int variableIndex1, 153 int variableIndex2, 154 int codeLength) 155 { 156 for (int offset = 0; offset < codeLength; offset++) 158 { 159 if ((livenessAnalyzer.isAliveBefore(offset, variableIndex1) && 160 livenessAnalyzer.isAliveBefore(offset, variableIndex2)) || 161 162 (livenessAnalyzer.isAliveAfter(offset, variableIndex1) && 163 livenessAnalyzer.isAliveAfter(offset, variableIndex2)) || 164 165 livenessAnalyzer.isCategory2(offset, variableIndex1)) 167 { 168 return false; 169 } 170 } 171 172 return true; 173 } 174 175 176 180 private void updateLiveness(int oldVariableIndex, 181 int newVariableIndex, 182 int codeLength) 183 { 184 for (int offset = 0; offset < codeLength; offset++) 186 { 187 if (livenessAnalyzer.isAliveBefore(offset, oldVariableIndex)) 189 { 190 livenessAnalyzer.setAliveBefore(offset, oldVariableIndex, false); 191 livenessAnalyzer.setAliveBefore(offset, newVariableIndex, true); 192 } 193 194 if (livenessAnalyzer.isAliveAfter(offset, oldVariableIndex)) 196 { 197 livenessAnalyzer.setAliveAfter(offset, oldVariableIndex, false); 198 livenessAnalyzer.setAliveAfter(offset, newVariableIndex, true); 199 } 200 } 201 } 202 } 203 | Popular Tags |