1b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato/* 2b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato * ProGuard -- shrinking, optimization, obfuscation, and preverification 3b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato * of Java bytecode. 4b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato * 59f606f95f03a75961498803e24bee6799a7c0885Ying Wang * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu) 6b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato * 7b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato * This program is free software; you can redistribute it and/or modify it 8b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato * under the terms of the GNU General Public License as published by the Free 9b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato * Software Foundation; either version 2 of the License, or (at your option) 10b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato * any later version. 11b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato * 12b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato * This program is distributed in the hope that it will be useful, but WITHOUT 13b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 14b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 15b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato * more details. 16b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato * 17b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato * You should have received a copy of the GNU General Public License along 18b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato * with this program; if not, write to the Free Software Foundation, Inc., 19b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 20b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato */ 21b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onoratopackage proguard.classfile.attribute.visitor; 22b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 23b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onoratoimport proguard.classfile.*; 24b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onoratoimport proguard.classfile.visitor.ClassPrinter; 25b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onoratoimport proguard.classfile.attribute.*; 26b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onoratoimport proguard.classfile.instruction.*; 27b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onoratoimport proguard.classfile.instruction.visitor.InstructionVisitor; 28b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onoratoimport proguard.classfile.util.SimplifiedVisitor; 29b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 30b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato/** 31b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato * This AttributeVisitor computes the stack sizes at all instruction offsets 32b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato * of the code attributes that it visits. 33b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato * 34b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato * @author Eric Lafortune 35b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato */ 36b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onoratopublic class StackSizeComputer 37b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onoratoextends SimplifiedVisitor 38b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onoratoimplements AttributeVisitor, 39b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato InstructionVisitor, 40b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato ExceptionInfoVisitor 41b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato{ 42b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato //* 43b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato private static final boolean DEBUG = false; 44b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato /*/ 45b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato private static boolean DEBUG = true; 46b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato //*/ 47b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 48b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 49b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato private boolean[] evaluated = new boolean[ClassConstants.TYPICAL_CODE_LENGTH]; 50b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato private int[] stackSizes = new int[ClassConstants.TYPICAL_CODE_LENGTH]; 51b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 52b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato private boolean exitInstructionBlock; 53b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 54b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato private int stackSize; 55b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato private int maxStackSize; 56b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 57b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 58b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato /** 59b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato * Returns whether the instruction at the given offset is reachable in the 60b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato * most recently visited code attribute. 61b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato */ 62b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato public boolean isReachable(int instructionOffset) 63b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato { 64b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato return evaluated[instructionOffset]; 65b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato } 66b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 67b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 68b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato /** 69b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato * Returns the stack size at the given instruction offset of the most 70b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato * recently visited code attribute. 71b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato */ 72b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato public int getStackSize(int instructionOffset) 73b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato { 74b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato if (!evaluated[instructionOffset]) 75b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato { 76b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato throw new IllegalArgumentException("Unknown stack size at unreachable instruction offset ["+instructionOffset+"]"); 77b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato } 78b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 79b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato return stackSizes[instructionOffset]; 80b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato } 81b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 82b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 83b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato /** 84b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato * Returns the maximum stack size of the most recently visited code attribute. 85b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato */ 86b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato public int getMaxStackSize() 87b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato { 88b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato return maxStackSize; 89b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato } 90b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 91b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 92b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato // Implementations for AttributeVisitor. 93b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 94b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato public void visitAnyAttribute(Clazz clazz, Attribute attribute) {} 95b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 96b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 97b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato public void visitCodeAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute) 98b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato { 99b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato// DEBUG = 100b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato// clazz.getName().equals("abc/Def") && 101b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato// method.getName(clazz).equals("abc"); 102b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 103b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato // TODO: Remove this when the code has stabilized. 104b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato // Catch any unexpected exceptions from the actual visiting method. 105b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato try 106b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato { 107b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato // Process the code. 108b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato visitCodeAttribute0(clazz, method, codeAttribute); 109b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato } 110b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato catch (RuntimeException ex) 111b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato { 112b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato System.err.println("Unexpected error while computing stack sizes:"); 113b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato System.err.println(" Class = ["+clazz.getName()+"]"); 114b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato System.err.println(" Method = ["+method.getName(clazz)+method.getDescriptor(clazz)+"]"); 115b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato System.err.println(" Exception = ["+ex.getClass().getName()+"] ("+ex.getMessage()+")"); 116b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 117b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato if (DEBUG) 118b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato { 119b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato method.accept(clazz, new ClassPrinter()); 120b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato } 121b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 122b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato throw ex; 123b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato } 124b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato } 125b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 126b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 127b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato public void visitCodeAttribute0(Clazz clazz, Method method, CodeAttribute codeAttribute) 128b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato { 129b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato if (DEBUG) 130b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato { 131b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato System.out.println("StackSizeComputer: "+clazz.getName()+"."+method.getName(clazz)+method.getDescriptor(clazz)); 132b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato } 133b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 134b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato // Try to reuse the previous array. 135b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato int codeLength = codeAttribute.u4codeLength; 136b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato if (evaluated.length < codeLength) 137b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato { 138b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato evaluated = new boolean[codeLength]; 139b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato stackSizes = new int[codeLength]; 140b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato } 141b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato else 142b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato { 1439f606f95f03a75961498803e24bee6799a7c0885Ying Wang for (int index = 0; index < codeLength; index++) 1449f606f95f03a75961498803e24bee6799a7c0885Ying Wang { 1459f606f95f03a75961498803e24bee6799a7c0885Ying Wang evaluated[index] = false; 1469f606f95f03a75961498803e24bee6799a7c0885Ying Wang } 147b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato } 148b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 149b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato // The initial stack is always empty. 150b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato stackSize = 0; 151b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato maxStackSize = 0; 152b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 153b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato // Evaluate the instruction block starting at the entry point of the method. 154b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato evaluateInstructionBlock(clazz, method, codeAttribute, 0); 155b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 156b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato // Evaluate the exception handlers. 157b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato codeAttribute.exceptionsAccept(clazz, method, this); 158b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato } 159b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 160b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 161b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato // Implementations for InstructionVisitor. 162b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 163b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato public void visitSimpleInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, SimpleInstruction simpleInstruction) 164b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato { 165b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato byte opcode = simpleInstruction.opcode; 166b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 167b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato // Some simple instructions exit from the current instruction block. 168b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato exitInstructionBlock = 169b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato opcode == InstructionConstants.OP_IRETURN || 170b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato opcode == InstructionConstants.OP_LRETURN || 171b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato opcode == InstructionConstants.OP_FRETURN || 172b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato opcode == InstructionConstants.OP_DRETURN || 173b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato opcode == InstructionConstants.OP_ARETURN || 174b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato opcode == InstructionConstants.OP_RETURN || 175b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato opcode == InstructionConstants.OP_ATHROW; 176b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato } 177b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 178b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato public void visitConstantInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, ConstantInstruction constantInstruction) 179b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato { 180b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato // Constant pool instructions never end the current instruction block. 181b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato exitInstructionBlock = false; 182b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato } 183b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 184b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato public void visitVariableInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, VariableInstruction variableInstruction) 185b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato { 186b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato byte opcode = variableInstruction.opcode; 187b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 188b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato // The ret instruction end the current instruction block. 189b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato exitInstructionBlock = 190b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato opcode == InstructionConstants.OP_RET; 191b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato } 192b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 193b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato public void visitBranchInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, BranchInstruction branchInstruction) 194b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato { 195b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato byte opcode = branchInstruction.opcode; 196b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 197b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato // Evaluate the target instruction blocks. 198b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato evaluateInstructionBlock(clazz, 199b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato method, 200b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato codeAttribute, 201b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato offset + 202b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato branchInstruction.branchOffset); 203b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 204b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato // Evaluate the instructions after a subroutine branch. 205b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato if (opcode == InstructionConstants.OP_JSR || 206b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato opcode == InstructionConstants.OP_JSR_W) 207b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato { 208b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato // We assume subroutine calls (jsr and jsr_w instructions) don't 209b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato // change the stack, other than popping the return value. 210b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato stackSize -= 1; 211b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 212b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato evaluateInstructionBlock(clazz, 213b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato method, 214b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato codeAttribute, 215b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato offset + branchInstruction.length(offset)); 216b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato } 217b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 218b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato // Some branch instructions always end the current instruction block. 219b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato exitInstructionBlock = 220b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato opcode == InstructionConstants.OP_GOTO || 221b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato opcode == InstructionConstants.OP_GOTO_W || 222b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato opcode == InstructionConstants.OP_JSR || 223b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato opcode == InstructionConstants.OP_JSR_W; 224b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato } 225b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 226b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 227b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato public void visitAnySwitchInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, SwitchInstruction switchInstruction) 228b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato { 229b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato // Evaluate the target instruction blocks. 230b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 231b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato // Loop over all jump offsets. 232b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato int[] jumpOffsets = switchInstruction.jumpOffsets; 233b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 234b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato for (int index = 0; index < jumpOffsets.length; index++) 235b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato { 236b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato // Evaluate the jump instruction block. 237b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato evaluateInstructionBlock(clazz, 238b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato method, 239b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato codeAttribute, 240b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato offset + jumpOffsets[index]); 241b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato } 242b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 243b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato // Also evaluate the default instruction block. 244b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato evaluateInstructionBlock(clazz, 245b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato method, 246b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato codeAttribute, 247b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato offset + switchInstruction.defaultOffset); 248b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 249b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato // The switch instruction always ends the current instruction block. 250b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato exitInstructionBlock = true; 251b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato } 252b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 253b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 254b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato // Implementations for ExceptionInfoVisitor. 255b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 256b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato public void visitExceptionInfo(Clazz clazz, Method method, CodeAttribute codeAttribute, ExceptionInfo exceptionInfo) 257b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato { 258b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato if (DEBUG) 259b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato { 260b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato System.out.println("Exception:"); 261b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato } 262b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 263b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato // The stack size when entering the exception handler is always 1. 264b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato stackSize = 1; 265b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 266b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato // Evaluate the instruction block starting at the entry point of the 267b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato // exception handler. 268b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato evaluateInstructionBlock(clazz, 269b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato method, 270b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato codeAttribute, 271b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato exceptionInfo.u2handlerPC); 272b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato } 273b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 274b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 275b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato // Small utility methods. 276b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 277b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato /** 278b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato * Evaluates a block of instructions that hasn't been handled before, 279b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato * starting at the given offset and ending at a branch instruction, a return 280b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato * instruction, or a throw instruction. Branch instructions are handled 281b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato * recursively. 282b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato */ 283b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato private void evaluateInstructionBlock(Clazz clazz, 284b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato Method method, 285b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato CodeAttribute codeAttribute, 286b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato int instructionOffset) 287b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato { 288b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato if (DEBUG) 289b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato { 290b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato if (evaluated[instructionOffset]) 291b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato { 292b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato System.out.println("-- (instruction block at "+instructionOffset+" already evaluated)"); 293b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato } 294b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato else 295b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato { 296b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato System.out.println("-- instruction block:"); 297b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato } 298b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato } 299b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 300b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato // Remember the initial stack size. 301b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato int initialStackSize = stackSize; 302b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 303b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato // Remember the maximum stack size. 304b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato if (maxStackSize < stackSize) 305b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato { 306b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato maxStackSize = stackSize; 307b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato } 308b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 309b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato // Evaluate any instructions that haven't been evaluated before. 310b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato while (!evaluated[instructionOffset]) 311b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato { 312b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato // Mark the instruction as evaluated. 313b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato evaluated[instructionOffset] = true; 314b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 315b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato Instruction instruction = InstructionFactory.create(codeAttribute.code, 316b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato instructionOffset); 317b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 318b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato if (DEBUG) 319b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato { 320b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato int stackPushCount = instruction.stackPushCount(clazz); 321b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato int stackPopCount = instruction.stackPopCount(clazz); 322b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato System.out.println("["+instructionOffset+"]: "+ 323b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato stackSize+" - "+ 324b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato stackPopCount+" + "+ 325b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato stackPushCount+" = "+ 326b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato (stackSize+stackPushCount-stackPopCount)+": "+ 327b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato instruction.toString(instructionOffset)); 328b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato } 329b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 330b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato // Compute the instruction's effect on the stack size. 331b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato stackSize -= instruction.stackPopCount(clazz); 332b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 333b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato if (stackSize < 0) 334b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato { 335b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato throw new IllegalArgumentException("Stack size becomes negative after instruction "+ 336b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato instruction.toString(instructionOffset)+" in ["+ 337b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato clazz.getName()+"."+ 338b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato method.getName(clazz)+ 339b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato method.getDescriptor(clazz)+"]"); 340b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato } 341b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 342b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato stackSizes[instructionOffset] = 343b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato stackSize += instruction.stackPushCount(clazz); 344b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 345b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato // Remember the maximum stack size. 346b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato if (maxStackSize < stackSize) 347b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato { 348b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato maxStackSize = stackSize; 349b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato } 350b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 351b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato // Remember the next instruction offset. 352b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato int nextInstructionOffset = instructionOffset + 353b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato instruction.length(instructionOffset); 354b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 355b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato // Visit the instruction, in order to handle branches. 356b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato instruction.accept(clazz, method, codeAttribute, instructionOffset, this); 357b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 358b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato // Stop evaluating after a branch. 359b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato if (exitInstructionBlock) 360b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato { 361b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato break; 362b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato } 363b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 364b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato // Continue with the next instruction. 365b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato instructionOffset = nextInstructionOffset; 366b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 367b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato if (DEBUG) 368b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato { 369b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato if (evaluated[instructionOffset]) 370b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato { 371b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato System.out.println("-- (instruction at "+instructionOffset+" already evaluated)"); 372b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato } 373b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato } 374b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato } 375b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 376b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato // Restore the stack size for possible subsequent instruction blocks. 377b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato this.stackSize = initialStackSize; 378b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato } 379b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato} 380