001: /*
002: * ProGuard -- shrinking, optimization, obfuscation, and preverification
003: * of Java bytecode.
004: *
005: * Copyright (c) 2002-2007 Eric Lafortune (eric@graphics.cornell.edu)
006: *
007: * This program is free software; you can redistribute it and/or modify it
008: * under the terms of the GNU General Public License as published by the Free
009: * Software Foundation; either version 2 of the License, or (at your option)
010: * any later version.
011: *
012: * This program is distributed in the hope that it will be useful, but WITHOUT
013: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
014: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
015: * more details.
016: *
017: * You should have received a copy of the GNU General Public License along
018: * with this program; if not, write to the Free Software Foundation, Inc.,
019: * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
020: */
021: package proguard.optimize.info;
022:
023: import proguard.classfile.*;
024: import proguard.classfile.util.*;
025: import proguard.classfile.visitor.MemberVisitor;
026:
027: /**
028: * This MemberVisitor counts the parameters and marks the used parameters
029: * of the methods that it visits. It also marks the 'this' parameters of
030: * methods that have hierarchies.
031: *
032: * @author Eric Lafortune
033: */
034: public class ParameterUsageMarker extends SimplifiedVisitor implements
035: MemberVisitor {
036: private static final boolean DEBUG = false;
037:
038: private final VariableUsageMarker variableUsageMarker = new VariableUsageMarker();
039:
040: // Implementations for MemberVisitor.
041:
042: public void visitProgramMethod(ProgramClass programClass,
043: ProgramMethod programMethod) {
044: int parameterSize = ClassUtil.internalMethodParameterSize(
045: programMethod.getDescriptor(programClass),
046: programMethod.getAccessFlags());
047:
048: if (parameterSize > 0) {
049: // Is it a native method?
050: int accessFlags = programMethod.getAccessFlags();
051: if ((accessFlags & ClassConstants.INTERNAL_ACC_NATIVE) != 0) {
052: // Mark all parameters.
053: markUsedParameters(programMethod, -1L);
054: }
055:
056: // Is it an abstract method?
057: else if ((accessFlags & ClassConstants.INTERNAL_ACC_ABSTRACT) != 0) {
058: // Mark the 'this' parameter.
059: markParameterUsed(programMethod, 0);
060: }
061:
062: // Is it a non-native, concrete method?
063: else {
064: // Is the method not static, but synchronized, or can it have
065: // other implementations, or is it a class instance initializer?
066: if ((accessFlags & ClassConstants.INTERNAL_ACC_STATIC) == 0
067: && ((accessFlags & ClassConstants.INTERNAL_ACC_SYNCHRONIZED) != 0
068: || programClass
069: .mayHaveImplementations(programMethod) || programMethod
070: .getName(programClass)
071: .equals(
072: ClassConstants.INTERNAL_METHOD_NAME_INIT))) {
073: // Mark the 'this' parameter.
074: markParameterUsed(programMethod, 0);
075: }
076:
077: // Figure out the local variables that are used by the code.
078: programMethod.attributesAccept(programClass,
079: variableUsageMarker);
080:
081: // Mark the parameters that are used by the code.
082: for (int index = 0; index < parameterSize; index++) {
083: if (variableUsageMarker.isVariableUsed(index)) {
084: markParameterUsed(programMethod, index);
085: }
086: }
087: }
088:
089: if (DEBUG) {
090: System.out.print("ParameterUsageMarker: ["
091: + programClass.getName() + "."
092: + programMethod.getName(programClass)
093: + programMethod.getDescriptor(programClass)
094: + "]: ");
095: for (int index = 0; index < parameterSize; index++) {
096: System.out.print(isParameterUsed(programMethod,
097: index) ? '+' : '-');
098: }
099: System.out.println();
100: }
101:
102: }
103:
104: // Set the parameter size.
105: setParameterSize(programMethod, parameterSize);
106: }
107:
108: public void visitLibraryMethod(LibraryClass libraryClass,
109: LibraryMethod libraryMethod) {
110: // Can the method have other implementations?
111: if (libraryClass.mayHaveImplementations(libraryMethod)) {
112: // All implementations must keep all parameters of this method,
113: // including the 'this' parameter.
114: long usedParameters = -1L;
115:
116: // Mark it.
117: markUsedParameters(libraryMethod, usedParameters);
118: }
119: }
120:
121: // Small utility methods.
122:
123: /**
124: * Sets the total size of the parameters.
125: */
126: private static void setParameterSize(Method method,
127: int parameterSize) {
128: MethodOptimizationInfo info = MethodOptimizationInfo
129: .getMethodOptimizationInfo(method);
130: if (info != null) {
131: info.setParameterSize(parameterSize);
132: }
133: }
134:
135: /**
136: * Returns the total size of the parameters.
137: */
138: public static int getParameterSize(Method method) {
139: MethodOptimizationInfo info = MethodOptimizationInfo
140: .getMethodOptimizationInfo(method);
141: return info != null ? info.getParameterSize() : 0;
142: }
143:
144: /**
145: * Marks the given parameter as being used.
146: */
147: public static void markParameterUsed(Method method,
148: int variableIndex) {
149: MethodOptimizationInfo info = MethodOptimizationInfo
150: .getMethodOptimizationInfo(method);
151: if (info != null) {
152: info.setParameterUsed(variableIndex);
153: }
154: }
155:
156: /**
157: * Marks the given parameters as being used.
158: */
159: public static void markUsedParameters(Method method,
160: long usedParameters) {
161: MethodOptimizationInfo info = MethodOptimizationInfo
162: .getMethodOptimizationInfo(method);
163: if (info != null) {
164: info.setUsedParameters(info.getUsedParameters()
165: | usedParameters);
166: }
167: }
168:
169: /**
170: * Returns whether the given parameter is being used.
171: */
172: public static boolean isParameterUsed(Method method,
173: int variableIndex) {
174: MethodOptimizationInfo info = MethodOptimizationInfo
175: .getMethodOptimizationInfo(method);
176: return info == null || info.isParameterUsed(variableIndex);
177: }
178:
179: /**
180: * Returns which parameters are being used.
181: */
182: public static long getUsedParameters(Method method) {
183: MethodOptimizationInfo info = MethodOptimizationInfo
184: .getMethodOptimizationInfo(method);
185: return info != null ? info.getUsedParameters() : -1L;
186: }
187:
188: /**
189: * Returns a bit mask of 1-bits of the given size.
190: */
191: private int parameterMask(int parameterSize) {
192: return (1 << parameterSize) - 1;
193: }
194:
195: /**
196: * Returns the parameter size of the given method, including the 'this'
197: * parameter, if any.
198: */
199: private int parameterSize(Clazz clazz, Method method) {
200:
201: return ClassUtil.internalMethodParameterSize(method
202: .getDescriptor(clazz), method.getAccessFlags());
203: }
204: }
|