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.attribute.*;
025: import proguard.classfile.attribute.visitor.AttributeVisitor;
026: import proguard.classfile.instruction.*;
027: import proguard.classfile.util.SimplifiedVisitor;
028: import proguard.classfile.visitor.*;
029:
030: /**
031: * This ClassPoolVisitor marks all methods that have side effects.
032: *
033: * @see ReadWriteFieldMarker
034: * @see NoSideEffectMethodMarker
035: * @author Eric Lafortune
036: */
037: public class SideEffectMethodMarker extends SimplifiedVisitor implements
038: ClassPoolVisitor, ClassVisitor, MemberVisitor, AttributeVisitor {
039: // A reusable object for checking whether instructions have side effects.
040: private final SideEffectInstructionChecker sideEffectInstructionChecker = new SideEffectInstructionChecker(
041: false);
042:
043: // Parameters and values for visitor methods.
044: private int newSideEffectCount;
045: private boolean hasSideEffects;
046:
047: // Implementations for ClassPoolVisitor.
048:
049: public void visitClassPool(ClassPool classPool) {
050: // Go over all classes and their methods, marking if they have side
051: // effects, until no new cases can be found.
052: do {
053: newSideEffectCount = 0;
054:
055: // Go over all classes and their methods once.
056: classPool.classesAccept(this );
057: } while (newSideEffectCount > 0);
058: }
059:
060: // Implementations for ClassVisitor.
061:
062: public void visitProgramClass(ProgramClass programClass) {
063: // Go over all methods.
064: programClass.methodsAccept(this );
065: }
066:
067: // Implementations for MemberVisitor.
068:
069: public void visitProgramMethod(ProgramClass programClass,
070: ProgramMethod programMethod) {
071: if (!hasSideEffects(programMethod)
072: && !NoSideEffectMethodMarker
073: .hasNoSideEffects(programMethod)) {
074: // Initialize the return value.
075: hasSideEffects = (programMethod.getAccessFlags() & (ClassConstants.INTERNAL_ACC_NATIVE | ClassConstants.INTERNAL_ACC_SYNCHRONIZED)) != 0;
076:
077: // Look further if the method hasn't been marked yet.
078: if (!hasSideEffects) {
079: // Investigate the actual code.
080: programMethod.attributesAccept(programClass, this );
081: }
082:
083: // Mark the method depending on the return value.
084: if (hasSideEffects) {
085: markSideEffects(programMethod);
086:
087: newSideEffectCount++;
088: }
089: }
090: }
091:
092: // Implementations for AttributeVisitor.
093:
094: public void visitAnyAttribute(Clazz clazz, Attribute attribute) {
095: }
096:
097: public void visitCodeAttribute(Clazz clazz, Method method,
098: CodeAttribute codeAttribute) {
099: // Remember whether the code has any side effects.
100: hasSideEffects = hasSideEffects(clazz, method, codeAttribute);
101: }
102:
103: // Small utility methods.
104:
105: /**
106: * Returns whether the given code has any side effects.
107: */
108: private boolean hasSideEffects(Clazz clazz, Method method,
109: CodeAttribute codeAttribute) {
110: byte[] code = codeAttribute.code;
111: int length = codeAttribute.u4codeLength;
112:
113: // Go over all instructions.
114: int offset = 0;
115: do {
116: // Get the current instruction.
117: Instruction instruction = InstructionFactory.create(code,
118: offset);
119:
120: // Check if it may be throwing exceptions.
121: if (sideEffectInstructionChecker.hasSideEffects(clazz,
122: method, codeAttribute, offset, instruction)) {
123: return true;
124: }
125:
126: // Go to the next instruction.
127: offset += instruction.length(offset);
128: } while (offset < length);
129:
130: return false;
131: }
132:
133: private static void markSideEffects(Method method) {
134: MethodOptimizationInfo info = MethodOptimizationInfo
135: .getMethodOptimizationInfo(method);
136: if (info != null) {
137: info.setSideEffects();
138: }
139: }
140:
141: public static boolean hasSideEffects(Method method) {
142: MethodOptimizationInfo info = MethodOptimizationInfo
143: .getMethodOptimizationInfo(method);
144: return info == null || info.hasSideEffects();
145: }
146: }
|