SideEffectMethodMarker.java revision cfead78069f3dc32998dc118ee08cab3867acea2
1/* 2 * ProGuard -- shrinking, optimization, obfuscation, and preverification 3 * of Java bytecode. 4 * 5 * Copyright (c) 2002-2011 Eric Lafortune (eric@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 */ 21package proguard.optimize.info; 22 23import proguard.classfile.*; 24import proguard.classfile.attribute.*; 25import proguard.classfile.attribute.visitor.AttributeVisitor; 26import proguard.classfile.instruction.*; 27import proguard.classfile.util.SimplifiedVisitor; 28import proguard.classfile.visitor.*; 29 30/** 31 * This ClassPoolVisitor marks all methods that have side effects. 32 * 33 * @see ReadWriteFieldMarker 34 * @see NoSideEffectMethodMarker 35 * @author Eric Lafortune 36 */ 37public class SideEffectMethodMarker 38extends SimplifiedVisitor 39implements ClassPoolVisitor, 40 ClassVisitor, 41 MemberVisitor, 42 AttributeVisitor 43{ 44 // A reusable object for checking whether instructions have side effects. 45 private final SideEffectInstructionChecker sideEffectInstructionChecker = new SideEffectInstructionChecker(false); 46 47 // Parameters and values for visitor methods. 48 private int newSideEffectCount; 49 private boolean hasSideEffects; 50 51 52 // Implementations for ClassPoolVisitor. 53 54 public void visitClassPool(ClassPool classPool) 55 { 56 // Go over all classes and their methods, marking if they have side 57 // effects, until no new cases can be found. 58 do 59 { 60 newSideEffectCount = 0; 61 62 // Go over all classes and their methods once. 63 classPool.classesAccept(this); 64 } 65 while (newSideEffectCount > 0); 66 } 67 68 69 // Implementations for ClassVisitor. 70 71 public void visitProgramClass(ProgramClass programClass) 72 { 73 // Go over all methods. 74 programClass.methodsAccept(this); 75 } 76 77 78 // Implementations for MemberVisitor. 79 80 public void visitProgramMethod(ProgramClass programClass, ProgramMethod programMethod) 81 { 82 if (!hasSideEffects(programMethod) && 83 !NoSideEffectMethodMarker.hasNoSideEffects(programMethod)) 84 { 85 // Initialize the return value. 86 hasSideEffects = 87 (programMethod.getAccessFlags() & 88 (ClassConstants.INTERNAL_ACC_NATIVE | 89 ClassConstants.INTERNAL_ACC_SYNCHRONIZED)) != 0; 90 91 // Look further if the method hasn't been marked yet. 92 if (!hasSideEffects) 93 { 94 // Investigate the actual code. 95 programMethod.attributesAccept(programClass, this); 96 } 97 98 // Mark the method depending on the return value. 99 if (hasSideEffects) 100 { 101 markSideEffects(programMethod); 102 103 newSideEffectCount++; 104 } 105 } 106 } 107 108 109 // Implementations for AttributeVisitor. 110 111 public void visitAnyAttribute(Clazz clazz, Attribute attribute) {} 112 113 114 public void visitCodeAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute) 115 { 116 // Remember whether the code has any side effects. 117 hasSideEffects = hasSideEffects(clazz, method, codeAttribute); 118 } 119 120 121 // Small utility methods. 122 123 /** 124 * Returns whether the given code has any side effects. 125 */ 126 private boolean hasSideEffects(Clazz clazz, 127 Method method, 128 CodeAttribute codeAttribute) 129 { 130 byte[] code = codeAttribute.code; 131 int length = codeAttribute.u4codeLength; 132 133 // Go over all instructions. 134 int offset = 0; 135 do 136 { 137 // Get the current instruction. 138 Instruction instruction = InstructionFactory.create(code, offset); 139 140 // Check if it may be throwing exceptions. 141 if (sideEffectInstructionChecker.hasSideEffects(clazz, 142 method, 143 codeAttribute, 144 offset, 145 instruction)) 146 { 147 return true; 148 } 149 150 // Go to the next instruction. 151 offset += instruction.length(offset); 152 } 153 while (offset < length); 154 155 return false; 156 } 157 158 159 private static void markSideEffects(Method method) 160 { 161 MethodOptimizationInfo info = MethodOptimizationInfo.getMethodOptimizationInfo(method); 162 if (info != null) 163 { 164 info.setSideEffects(); 165 } 166 } 167 168 169 public static boolean hasSideEffects(Method method) 170 { 171 MethodOptimizationInfo info = MethodOptimizationInfo.getMethodOptimizationInfo(method); 172 return info == null || 173 info.hasSideEffects(); 174 } 175} 176