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