diff options
Diffstat (limited to 'src/proguard/optimize/evaluation/VariableOptimizer.java')
-rw-r--r-- | src/proguard/optimize/evaluation/VariableOptimizer.java | 357 |
1 files changed, 0 insertions, 357 deletions
diff --git a/src/proguard/optimize/evaluation/VariableOptimizer.java b/src/proguard/optimize/evaluation/VariableOptimizer.java deleted file mode 100644 index bef1445..0000000 --- a/src/proguard/optimize/evaluation/VariableOptimizer.java +++ /dev/null @@ -1,357 +0,0 @@ -/* - * ProGuard -- shrinking, optimization, obfuscation, and preverification - * of Java bytecode. - * - * Copyright (c) 2002-2014 Eric Lafortune (eric@graphics.cornell.edu) - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the Free - * Software Foundation; either version 2 of the License, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ -package proguard.optimize.evaluation; - -import proguard.classfile.*; -import proguard.classfile.attribute.*; -import proguard.classfile.attribute.visitor.*; -import proguard.classfile.editor.*; -import proguard.classfile.util.*; -import proguard.classfile.visitor.MemberVisitor; - -/** - * This AttributeVisitor optimizes variable allocation based on their the liveness, - * in the code attributes that it visits. - * - * @author Eric Lafortune - */ -public class VariableOptimizer -extends SimplifiedVisitor -implements AttributeVisitor, - LocalVariableInfoVisitor, - LocalVariableTypeInfoVisitor -{ - //* - private static final boolean DEBUG = false; - /*/ - private static boolean DEBUG = true; - //*/ - - private static final int MAX_VARIABLES_SIZE = 64; - - - private final boolean reuseThis; - private final MemberVisitor extraVariableMemberVisitor; - - private final LivenessAnalyzer livenessAnalyzer = new LivenessAnalyzer(); - private final VariableRemapper variableRemapper = new VariableRemapper(); - private VariableCleaner variableCleaner = new VariableCleaner(); - - private int[] variableMap = new int[ClassConstants.TYPICAL_VARIABLES_SIZE]; - - - /** - * Creates a new VariableOptimizer. - * @param reuseThis specifies whether the 'this' variable can be reused. - * Many JVMs for JME and IBM's JVMs for JSE can't handle - * such reuse. - */ - public VariableOptimizer(boolean reuseThis) - { - this(reuseThis, null); - } - - - /** - * Creates a new VariableOptimizer with an extra visitor. - * @param reuseThis specifies whether the 'this' variable - * can be reused. Many JVMs for JME and - * IBM's JVMs for JSE can't handle such - * reuse. - * @param extraVariableMemberVisitor an optional extra visitor for all - * removed variables. - */ - public VariableOptimizer(boolean reuseThis, - MemberVisitor extraVariableMemberVisitor) - { - this.reuseThis = reuseThis; - this.extraVariableMemberVisitor = extraVariableMemberVisitor; - } - - - // Implementations for AttributeVisitor. - - public void visitAnyAttribute(Clazz clazz, Attribute attribute) {} - - - public void visitCodeAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute) - { -// DEBUG = -// clazz.getName().equals("abc/Def") && -// method.getName(clazz).equals("abc"); - - // Initialize the global arrays. - initializeArrays(codeAttribute); - - // Analyze the liveness of the variables in the code. - livenessAnalyzer.visitCodeAttribute(clazz, method, codeAttribute); - - // Trim the variables in the local variable tables, because even - // clipping the tables individually may leave some inconsistencies - // between them. - codeAttribute.attributesAccept(clazz, method, this); - - int startIndex = - (method.getAccessFlags() & ClassConstants.ACC_STATIC) != 0 || - reuseThis ? 0 : 1; - - int parameterSize = - ClassUtil.internalMethodParameterSize(method.getDescriptor(clazz), - method.getAccessFlags()); - - int variableSize = codeAttribute.u2maxLocals; - int codeLength = codeAttribute.u4codeLength; - - boolean remapping = false; - - // Loop over all variables. - for (int oldIndex = 0; oldIndex < variableSize; oldIndex++) - { - // By default, the variable will be mapped onto itself. - variableMap[oldIndex] = oldIndex; - - // Only try remapping the variable if it's not a parameter. - if (oldIndex >= parameterSize && - oldIndex < MAX_VARIABLES_SIZE) - { - // Try to remap the variable to a variable with a smaller index. - for (int newIndex = startIndex; newIndex < oldIndex; newIndex++) - { - if (areNonOverlapping(oldIndex, newIndex, codeLength)) - { - variableMap[oldIndex] = newIndex; - - updateLiveness(oldIndex, newIndex, codeLength); - - remapping = true; - - // This variable has been remapped. Go to the next one. - break; - } - } - } - } - - // Have we been able to remap any variables? - if (remapping) - { - if (DEBUG) - { - System.out.println("VariableOptimizer: "+clazz.getName()+"."+method.getName(clazz)+method.getDescriptor(clazz)); - for (int index= 0; index < variableSize; index++) - { - System.out.println(" v"+index+" -> "+variableMap[index]); - } - } - - // Remap the variables. - variableRemapper.setVariableMap(variableMap); - variableRemapper.visitCodeAttribute(clazz, method, codeAttribute); - - // Visit the method, if required. - if (extraVariableMemberVisitor != null) - { - method.accept(clazz, extraVariableMemberVisitor); - } - } - else - { - // Just clean up any empty variables. - variableCleaner.visitCodeAttribute(clazz, method, codeAttribute); - } - } - - - public void visitLocalVariableTableAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute, LocalVariableTableAttribute localVariableTableAttribute) - { - // Trim the variables in the local variable table. - localVariableTableAttribute.localVariablesAccept(clazz, method, codeAttribute, this); - } - - - public void visitLocalVariableTypeTableAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute, LocalVariableTypeTableAttribute localVariableTypeTableAttribute) - { - // Trim the variables in the local variable type table. - localVariableTypeTableAttribute.localVariablesAccept(clazz, method, codeAttribute, this); - } - - - // Implementations for LocalVariableInfoVisitor. - - public void visitLocalVariableInfo(Clazz clazz, Method method, CodeAttribute codeAttribute, LocalVariableInfo localVariableInfo) - { - // Trim the local variable to the instructions at which it is alive. - int variable = localVariableInfo.u2index; - int startPC = localVariableInfo.u2startPC; - int endPC = startPC + localVariableInfo.u2length; - - startPC = firstLiveness(startPC, endPC, variable); - endPC = lastLiveness(startPC, endPC, variable); - - // Leave the start address of unused variables unchanged. - int length = endPC - startPC; - if (length > 0) - { - localVariableInfo.u2startPC = startPC; - } - - localVariableInfo.u2length = length; - } - - - // Implementations for LocalVariableTypeInfoVisitor. - - public void visitLocalVariableTypeInfo(Clazz clazz, Method method, CodeAttribute codeAttribute, LocalVariableTypeInfo localVariableTypeInfo) - { - // Trim the local variable type to the instructions at which it is alive. - int variable = localVariableTypeInfo.u2index; - int startPC = localVariableTypeInfo.u2startPC; - int endPC = startPC + localVariableTypeInfo.u2length; - - startPC = firstLiveness(startPC, endPC, variable); - endPC = lastLiveness(startPC, endPC, variable); - - // Leave the start address of unused variables unchanged. - int length = endPC - startPC; - if (length > 0) - { - localVariableTypeInfo.u2startPC = startPC; - } - - localVariableTypeInfo.u2length = length; - } - - - // Small utility methods. - - /** - * Initializes the global arrays. - */ - private void initializeArrays(CodeAttribute codeAttribute) - { - int codeLength = codeAttribute.u4codeLength; - - // Create new arrays for storing information at each instruction offset. - if (variableMap.length < codeLength) - { - variableMap = new int[codeLength]; - } - } - - - /** - * Returns whether the given variables are never alive at the same time. - */ - private boolean areNonOverlapping(int variableIndex1, - int variableIndex2, - int codeLength) - { - // Loop over all instructions. - for (int offset = 0; offset < codeLength; offset++) - { - if ((livenessAnalyzer.isAliveBefore(offset, variableIndex1) && - livenessAnalyzer.isAliveBefore(offset, variableIndex2)) || - - (livenessAnalyzer.isAliveAfter(offset, variableIndex1) && - livenessAnalyzer.isAliveAfter(offset, variableIndex2)) || - - // For now, exclude Category 2 variables. - livenessAnalyzer.isCategory2(offset, variableIndex1)) - { - return false; - } - } - - return true; - } - - - /** - * Updates the liveness resulting from mapping the given old variable on - * the given new variable. - */ - private void updateLiveness(int oldVariableIndex, - int newVariableIndex, - int codeLength) - { - // Loop over all instructions. - for (int offset = 0; offset < codeLength; offset++) - { - // Update the liveness before the instruction. - if (livenessAnalyzer.isAliveBefore(offset, oldVariableIndex)) - { - livenessAnalyzer.setAliveBefore(offset, oldVariableIndex, false); - livenessAnalyzer.setAliveBefore(offset, newVariableIndex, true); - } - - // Update the liveness after the instruction. - if (livenessAnalyzer.isAliveAfter(offset, oldVariableIndex)) - { - livenessAnalyzer.setAliveAfter(offset, oldVariableIndex, false); - livenessAnalyzer.setAliveAfter(offset, newVariableIndex, true); - } - } - } - - - /** - * Returns the first instruction offset between the given offsets at which - * the given variable goes alive. - */ - private int firstLiveness(int startOffset, int endOffset, int variableIndex) - { - for (int offset = startOffset; offset < endOffset; offset++) - { - if (livenessAnalyzer.isTraced(offset) && - livenessAnalyzer.isAliveBefore(offset, variableIndex)) - { - return offset; - } - } - - return endOffset; - } - - - /** - * Returns the last instruction offset between the given offsets before - * which the given variable is still alive. - */ - private int lastLiveness(int startOffset, int endOffset, int variableIndex) - { - int previousOffset = endOffset; - - for (int offset = endOffset-1; offset >= startOffset; offset--) - { - if (livenessAnalyzer.isTraced(offset)) - { - if (livenessAnalyzer.isAliveBefore(offset, variableIndex)) - { - return previousOffset; - } - - previousOffset = offset; - } - } - - return endOffset; - } -} |