169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal/* 269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * Javassist, a Java-bytecode translator toolkit. 369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * Copyright (C) 1999-2007 Shigeru Chiba, and others. All Rights Reserved. 469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * 569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * The contents of this file are subject to the Mozilla Public License Version 669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * 1.1 (the "License"); you may not use this file except in compliance with 769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * the License. Alternatively, the contents of this file may be used under 869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * the terms of the GNU Lesser General Public License Version 2.1 or later. 969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * 1069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * Software distributed under the License is distributed on an "AS IS" basis, 1169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License 1269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * for the specific language governing rights and limitations under the 1369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * License. 1469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal */ 1569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigalpackage javassist.bytecode.analysis; 1669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal 1769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigalimport java.util.Iterator; 1869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal 1969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigalimport javassist.ClassPool; 2069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigalimport javassist.CtClass; 2169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigalimport javassist.CtMethod; 2269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigalimport javassist.NotFoundException; 2369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigalimport javassist.bytecode.AccessFlag; 2469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigalimport javassist.bytecode.BadBytecode; 2569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigalimport javassist.bytecode.CodeAttribute; 2669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigalimport javassist.bytecode.CodeIterator; 2769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigalimport javassist.bytecode.ConstPool; 2869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigalimport javassist.bytecode.Descriptor; 2969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigalimport javassist.bytecode.ExceptionTable; 3069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigalimport javassist.bytecode.MethodInfo; 3169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigalimport javassist.bytecode.Opcode; 3269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal 3369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal/** 3469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * A data-flow analyzer that determines the type state of the stack and local 3569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * variable table at every reachable instruction in a method. During analysis, 3669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * bytecode verification is performed in a similar manner to that described 3769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * in the JVM specification. 3869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * 3969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * <p>Example:</p> 4069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * 4169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * <pre> 4269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * // Method to analyze 4369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * public Object doSomething(int x) { 4469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * Number n; 4569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * if (x < 5) { 4669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * n = new Double(0); 4769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * } else { 4869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * n = new Long(0); 4969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * } 5069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * 5169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * return n; 5269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * } 5369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * 5469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * // Which compiles to: 5569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * // 0: iload_1 5669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * // 1: iconst_5 5769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * // 2: if_icmpge 17 5869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * // 5: new #18; //class java/lang/Double 5969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * // 8: dup 6069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * // 9: dconst_0 6169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * // 10: invokespecial #44; //Method java/lang/Double."<init>":(D)V 6269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * // 13: astore_2 6369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * // 14: goto 26 6469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * // 17: new #16; //class java/lang/Long 6569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * // 20: dup 6669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * // 21: lconst_1 6769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * // 22: invokespecial #47; //Method java/lang/Long."<init>":(J)V 6869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * // 25: astore_2 6969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * // 26: aload_2 7069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * // 27: areturn 7169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * 7269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * public void analyzeIt(CtClass clazz, MethodInfo method) { 7369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * Analyzer analyzer = new Analyzer(); 7469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * Frame[] frames = analyzer.analyze(clazz, method); 7569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * frames[0].getLocal(0).getCtClass(); // returns clazz; 7669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * frames[0].getLocal(1).getCtClass(); // returns java.lang.String 7769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * frames[1].peek(); // returns Type.INTEGER 7869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * frames[27].peek().getCtClass(); // returns java.lang.Number 7969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * } 8069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * </pre> 8169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * 8269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * @see FramePrinter 8369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * @author Jason T. Greene 8469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal */ 8569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigalpublic class Analyzer implements Opcode { 8669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal private final SubroutineScanner scanner = new SubroutineScanner(); 8769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal private CtClass clazz; 8869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal private ExceptionInfo[] exceptions; 8969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal private Frame[] frames; 9069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal private Subroutine[] subroutines; 9169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal 9269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal private static class ExceptionInfo { 9369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal private int end; 9469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal private int handler; 9569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal private int start; 9669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal private Type type; 9769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal 9869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal private ExceptionInfo(int start, int end, int handler, Type type) { 9969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal this.start = start; 10069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal this.end = end; 10169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal this.handler = handler; 10269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal this.type = type; 10369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal } 10469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal } 10569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal 10669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal /** 10769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * Performs data-flow analysis on a method and returns an array, indexed by 10869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * instruction position, containing the starting frame state of all reachable 10969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * instructions. Non-reachable code, and illegal code offsets are represented 11069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * as a null in the frame state array. This can be used to detect dead code. 11169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * 11269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * If the method does not contain code (it is either native or abstract), null 11369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * is returned. 11469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * 11569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * @param clazz the declaring class of the method 11669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * @param method the method to analyze 11769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * @return an array, indexed by instruction position, of the starting frame state, 11869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * or null if this method doesn't have code 11969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * @throws BadBytecode if the bytecode does not comply with the JVM specification 12069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal */ 12169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal public Frame[] analyze(CtClass clazz, MethodInfo method) throws BadBytecode { 12269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal this.clazz = clazz; 12369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal CodeAttribute codeAttribute = method.getCodeAttribute(); 12469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal // Native or Abstract 12569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal if (codeAttribute == null) 12669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal return null; 12769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal 12869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal int maxLocals = codeAttribute.getMaxLocals(); 12969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal int maxStack = codeAttribute.getMaxStack(); 13069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal int codeLength = codeAttribute.getCodeLength(); 13169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal 13269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal CodeIterator iter = codeAttribute.iterator(); 13369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal IntQueue queue = new IntQueue(); 13469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal 13569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal exceptions = buildExceptionInfo(method); 13669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal subroutines = scanner.scan(method); 13769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal 13869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal Executor executor = new Executor(clazz.getClassPool(), method.getConstPool()); 13969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal frames = new Frame[codeLength]; 14069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal frames[iter.lookAhead()] = firstFrame(method, maxLocals, maxStack); 14169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal queue.add(iter.next()); 14269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal while (!queue.isEmpty()) { 14369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal analyzeNextEntry(method, iter, queue, executor); 14469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal } 14569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal 14669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal return frames; 14769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal } 14869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal 14969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal /** 15069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * Performs data-flow analysis on a method and returns an array, indexed by 15169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * instruction position, containing the starting frame state of all reachable 15269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * instructions. Non-reachable code, and illegal code offsets are represented 15369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * as a null in the frame state array. This can be used to detect dead code. 15469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * 15569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * If the method does not contain code (it is either native or abstract), null 15669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * is returned. 15769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * 15869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * @param method the method to analyze 15969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * @return an array, indexed by instruction position, of the starting frame state, 16069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * or null if this method doesn't have code 16169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * @throws BadBytecode if the bytecode does not comply with the JVM specification 16269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal */ 16369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal public Frame[] analyze(CtMethod method) throws BadBytecode { 16469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal return analyze(method.getDeclaringClass(), method.getMethodInfo2()); 16569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal } 16669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal 16769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal private void analyzeNextEntry(MethodInfo method, CodeIterator iter, 16869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal IntQueue queue, Executor executor) throws BadBytecode { 16969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal int pos = queue.take(); 17069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal iter.move(pos); 17169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal iter.next(); 17269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal 17369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal Frame frame = frames[pos].copy(); 17469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal Subroutine subroutine = subroutines[pos]; 17569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal 17669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal try { 17769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal executor.execute(method, pos, iter, frame, subroutine); 17869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal } catch (RuntimeException e) { 17969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal throw new BadBytecode(e.getMessage() + "[pos = " + pos + "]", e); 18069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal } 18169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal 18269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal int opcode = iter.byteAt(pos); 18369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal 18469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal if (opcode == TABLESWITCH) { 18569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal mergeTableSwitch(queue, pos, iter, frame); 18669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal } else if (opcode == LOOKUPSWITCH) { 18769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal mergeLookupSwitch(queue, pos, iter, frame); 18869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal } else if (opcode == RET) { 18969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal mergeRet(queue, iter, pos, frame, subroutine); 19069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal } else if (Util.isJumpInstruction(opcode)) { 19169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal int target = Util.getJumpTarget(pos, iter); 19269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal 19369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal if (Util.isJsr(opcode)) { 19469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal // Merge the state before the jsr into the next instruction 19569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal mergeJsr(queue, frames[pos], subroutines[target], pos, lookAhead(iter, pos)); 19669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal } else if (! Util.isGoto(opcode)) { 19769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal merge(queue, frame, lookAhead(iter, pos)); 19869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal } 19969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal 20069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal merge(queue, frame, target); 20169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal } else if (opcode != ATHROW && ! Util.isReturn(opcode)) { 20269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal // Can advance to next instruction 20369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal merge(queue, frame, lookAhead(iter, pos)); 20469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal } 20569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal 20669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal // Merge all exceptions that are reachable from this instruction. 20769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal // The redundancy is intentional, since the state must be based 20869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal // on the current instruction frame. 20969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal mergeExceptionHandlers(queue, method, pos, frame); 21069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal } 21169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal 21269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal private ExceptionInfo[] buildExceptionInfo(MethodInfo method) { 21369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal ConstPool constPool = method.getConstPool(); 21469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal ClassPool classes = clazz.getClassPool(); 21569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal 21669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal ExceptionTable table = method.getCodeAttribute().getExceptionTable(); 21769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal ExceptionInfo[] exceptions = new ExceptionInfo[table.size()]; 21869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal for (int i = 0; i < table.size(); i++) { 21969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal int index = table.catchType(i); 22069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal Type type; 22169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal try { 22269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal type = index == 0 ? Type.THROWABLE : Type.get(classes.get(constPool.getClassInfo(index))); 22369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal } catch (NotFoundException e) { 22469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal throw new IllegalStateException(e.getMessage()); 22569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal } 22669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal 22769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal exceptions[i] = new ExceptionInfo(table.startPc(i), table.endPc(i), table.handlerPc(i), type); 22869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal } 22969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal 23069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal return exceptions; 23169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal } 23269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal 23369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal private Frame firstFrame(MethodInfo method, int maxLocals, int maxStack) { 23469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal int pos = 0; 23569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal 23669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal Frame first = new Frame(maxLocals, maxStack); 23769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal if ((method.getAccessFlags() & AccessFlag.STATIC) == 0) { 23869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal first.setLocal(pos++, Type.get(clazz)); 23969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal } 24069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal 24169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal CtClass[] parameters; 24269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal try { 24369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal parameters = Descriptor.getParameterTypes(method.getDescriptor(), clazz.getClassPool()); 24469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal } catch (NotFoundException e) { 24569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal throw new RuntimeException(e); 24669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal } 24769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal 24869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal for (int i = 0; i < parameters.length; i++) { 24969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal Type type = zeroExtend(Type.get(parameters[i])); 25069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal first.setLocal(pos++, type); 25169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal if (type.getSize() == 2) 25269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal first.setLocal(pos++, Type.TOP); 25369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal } 25469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal 25569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal return first; 25669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal } 25769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal 25869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal private int getNext(CodeIterator iter, int of, int restore) throws BadBytecode { 25969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal iter.move(of); 26069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal iter.next(); 26169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal int next = iter.lookAhead(); 26269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal iter.move(restore); 26369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal iter.next(); 26469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal 26569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal return next; 26669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal } 26769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal 26869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal private int lookAhead(CodeIterator iter, int pos) throws BadBytecode { 26969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal if (! iter.hasNext()) 27069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal throw new BadBytecode("Execution falls off end! [pos = " + pos + "]"); 27169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal 27269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal return iter.lookAhead(); 27369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal } 27469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal 27569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal 27669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal private void merge(IntQueue queue, Frame frame, int target) { 27769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal Frame old = frames[target]; 27869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal boolean changed; 27969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal 28069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal if (old == null) { 28169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal frames[target] = frame.copy(); 28269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal changed = true; 28369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal } else { 28469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal changed = old.merge(frame); 28569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal } 28669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal 28769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal if (changed) { 28869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal queue.add(target); 28969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal } 29069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal } 29169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal 29269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal private void mergeExceptionHandlers(IntQueue queue, MethodInfo method, int pos, Frame frame) { 29369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal for (int i = 0; i < exceptions.length; i++) { 29469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal ExceptionInfo exception = exceptions[i]; 29569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal 29669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal // Start is inclusive, while end is exclusive! 29769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal if (pos >= exception.start && pos < exception.end) { 29869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal Frame newFrame = frame.copy(); 29969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal newFrame.clearStack(); 30069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal newFrame.push(exception.type); 30169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal merge(queue, newFrame, exception.handler); 30269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal } 30369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal } 30469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal } 30569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal 30669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal private void mergeJsr(IntQueue queue, Frame frame, Subroutine sub, int pos, int next) throws BadBytecode { 30769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal if (sub == null) 30869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal throw new BadBytecode("No subroutine at jsr target! [pos = " + pos + "]"); 30969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal 31069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal Frame old = frames[next]; 31169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal boolean changed = false; 31269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal 31369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal if (old == null) { 31469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal old = frames[next] = frame.copy(); 31569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal changed = true; 31669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal } else { 31769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal for (int i = 0; i < frame.localsLength(); i++) { 31869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal // Skip everything accessed by a subroutine, mergeRet must handle this 31969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal if (!sub.isAccessed(i)) { 32069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal Type oldType = old.getLocal(i); 32169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal Type newType = frame.getLocal(i); 32269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal if (oldType == null) { 32369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal old.setLocal(i, newType); 32469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal changed = true; 32569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal continue; 32669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal } 32769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal 32869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal newType = oldType.merge(newType); 32969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal // Always set the type, in case a multi-type switched to a standard type. 33069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal old.setLocal(i, newType); 33169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal if (!newType.equals(oldType) || newType.popChanged()) 33269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal changed = true; 33369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal } 33469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal } 33569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal } 33669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal 33769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal if (! old.isJsrMerged()) { 33869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal old.setJsrMerged(true); 33969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal changed = true; 34069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal } 34169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal 34269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal if (changed && old.isRetMerged()) 34369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal queue.add(next); 34469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal 34569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal } 34669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal 34769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal private void mergeLookupSwitch(IntQueue queue, int pos, CodeIterator iter, Frame frame) throws BadBytecode { 34869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal int index = (pos & ~3) + 4; 34969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal // default 35069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal merge(queue, frame, pos + iter.s32bitAt(index)); 35169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal int npairs = iter.s32bitAt(index += 4); 35269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal int end = npairs * 8 + (index += 4); 35369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal 35469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal // skip "match" 35569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal for (index += 4; index < end; index += 8) { 35669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal int target = iter.s32bitAt(index) + pos; 35769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal merge(queue, frame, target); 35869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal } 35969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal } 36069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal 36169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal private void mergeRet(IntQueue queue, CodeIterator iter, int pos, Frame frame, Subroutine subroutine) throws BadBytecode { 36269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal if (subroutine == null) 36369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal throw new BadBytecode("Ret on no subroutine! [pos = " + pos + "]"); 36469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal 36569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal Iterator callerIter = subroutine.callers().iterator(); 36669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal while (callerIter.hasNext()) { 36769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal int caller = ((Integer) callerIter.next()).intValue(); 36869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal int returnLoc = getNext(iter, caller, pos); 36969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal boolean changed = false; 37069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal 37169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal Frame old = frames[returnLoc]; 37269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal if (old == null) { 37369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal old = frames[returnLoc] = frame.copyStack(); 37469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal changed = true; 37569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal } else { 37669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal changed = old.mergeStack(frame); 37769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal } 37869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal 37969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal for (Iterator i = subroutine.accessed().iterator(); i.hasNext(); ) { 38069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal int index = ((Integer)i.next()).intValue(); 38169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal Type oldType = old.getLocal(index); 38269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal Type newType = frame.getLocal(index); 38369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal if (oldType != newType) { 38469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal old.setLocal(index, newType); 38569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal changed = true; 38669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal } 38769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal } 38869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal 38969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal if (! old.isRetMerged()) { 39069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal old.setRetMerged(true); 39169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal changed = true; 39269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal } 39369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal 39469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal if (changed && old.isJsrMerged()) 39569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal queue.add(returnLoc); 39669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal } 39769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal } 39869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal 39969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal 40069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal private void mergeTableSwitch(IntQueue queue, int pos, CodeIterator iter, Frame frame) throws BadBytecode { 40169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal // Skip 4 byte alignment padding 40269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal int index = (pos & ~3) + 4; 40369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal // default 40469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal merge(queue, frame, pos + iter.s32bitAt(index)); 40569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal int low = iter.s32bitAt(index += 4); 40669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal int high = iter.s32bitAt(index += 4); 40769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal int end = (high - low + 1) * 4 + (index += 4); 40869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal 40969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal // Offset table 41069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal for (; index < end; index += 4) { 41169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal int target = iter.s32bitAt(index) + pos; 41269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal merge(queue, frame, target); 41369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal } 41469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal } 41569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal 41669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal private Type zeroExtend(Type type) { 41769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal if (type == Type.SHORT || type == Type.BYTE || type == Type.CHAR || type == Type.BOOLEAN) 41869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal return Type.INTEGER; 41969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal 42069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal return type; 42169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal } 42269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal} 423