1674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen/***
2674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen * ASM: a very small and fast Java bytecode manipulation framework
3674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen * Copyright (c) 2000-2007 INRIA, France Telecom
4674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen * All rights reserved.
5674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen *
6674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen * Redistribution and use in source and binary forms, with or without
7674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen * modification, are permitted provided that the following conditions
8674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen * are met:
9674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen * 1. Redistributions of source code must retain the above copyright
10674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen *    notice, this list of conditions and the following disclaimer.
11674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen * 2. Redistributions in binary form must reproduce the above copyright
12674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen *    notice, this list of conditions and the following disclaimer in the
13674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen *    documentation and/or other materials provided with the distribution.
14674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen * 3. Neither the name of the copyright holders nor the names of its
15674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen *    contributors may be used to endorse or promote products derived from
16674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen *    this software without specific prior written permission.
17674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen *
18674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
22674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
28674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen * THE POSSIBILITY OF SUCH DAMAGE.
29674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen */
30674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogenpackage org.mockito.asm.tree.analysis;
31674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen
32674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogenimport java.util.ArrayList;
33674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogenimport java.util.HashMap;
34674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogenimport java.util.List;
35674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogenimport java.util.Map;
36674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen
37674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogenimport org.mockito.asm.Opcodes;
38674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogenimport org.mockito.asm.Type;
39674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogenimport org.mockito.asm.tree.AbstractInsnNode;
40674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogenimport org.mockito.asm.tree.IincInsnNode;
41674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogenimport org.mockito.asm.tree.InsnList;
42674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogenimport org.mockito.asm.tree.JumpInsnNode;
43674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogenimport org.mockito.asm.tree.LabelNode;
44674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogenimport org.mockito.asm.tree.LookupSwitchInsnNode;
45674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogenimport org.mockito.asm.tree.MethodNode;
46674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogenimport org.mockito.asm.tree.TableSwitchInsnNode;
47674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogenimport org.mockito.asm.tree.TryCatchBlockNode;
48674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogenimport org.mockito.asm.tree.VarInsnNode;
49674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen
50674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen/**
51674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen * A semantic bytecode analyzer. <i>This class does not fully check that JSR and
52674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen * RET instructions are valid.</i>
53674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen *
54674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen * @author Eric Bruneton
55674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen */
56674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogenpublic class Analyzer implements Opcodes {
57674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen
58674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    private final Interpreter interpreter;
59674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen
60674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    private int n;
61674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen
62674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    private InsnList insns;
63674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen
64674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    private List[] handlers;
65674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen
66674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    private Frame[] frames;
67674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen
68674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    private Subroutine[] subroutines;
69674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen
70674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    private boolean[] queued;
71674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen
72674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    private int[] queue;
73674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen
74674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    private int top;
75674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen
76674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    /**
77674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen     * Constructs a new {@link Analyzer}.
78674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen     *
79674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen     * @param interpreter the interpreter to be used to symbolically interpret
80674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen     *        the bytecode instructions.
81674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen     */
82674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    public Analyzer(final Interpreter interpreter) {
83674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        this.interpreter = interpreter;
84674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    }
85674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen
86674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    /**
87674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen     * Analyzes the given method.
88674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen     *
89674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen     * @param owner the internal name of the class to which the method belongs.
90674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen     * @param m the method to be analyzed.
91674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen     * @return the symbolic state of the execution stack frame at each bytecode
92674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen     *         instruction of the method. The size of the returned array is
93674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen     *         equal to the number of instructions (and labels) of the method. A
94674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen     *         given frame is <tt>null</tt> if and only if the corresponding
95674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen     *         instruction cannot be reached (dead code).
96674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen     * @throws AnalyzerException if a problem occurs during the analysis.
97674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen     */
98674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    public Frame[] analyze(final String owner, final MethodNode m)
99674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            throws AnalyzerException
100674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    {
101674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        if ((m.access & (ACC_ABSTRACT | ACC_NATIVE)) != 0) {
102674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            frames = new Frame[0];
103674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            return frames;
104674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        }
105674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        n = m.instructions.size();
106674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        insns = m.instructions;
107674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        handlers = new List[n];
108674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        frames = new Frame[n];
109674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        subroutines = new Subroutine[n];
110674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        queued = new boolean[n];
111674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        queue = new int[n];
112674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        top = 0;
113674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen
114674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        // computes exception handlers for each instruction
115674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        for (int i = 0; i < m.tryCatchBlocks.size(); ++i) {
116674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            TryCatchBlockNode tcb = (TryCatchBlockNode) m.tryCatchBlocks.get(i);
117674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            int begin = insns.indexOf(tcb.start);
118674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            int end = insns.indexOf(tcb.end);
119674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            for (int j = begin; j < end; ++j) {
120674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                List insnHandlers = handlers[j];
121674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                if (insnHandlers == null) {
122674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                    insnHandlers = new ArrayList();
123674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                    handlers[j] = insnHandlers;
124674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                }
125674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                insnHandlers.add(tcb);
126674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            }
127674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        }
128674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen
129674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        // computes the subroutine for each instruction:
130674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        Subroutine main = new Subroutine(null, m.maxLocals, null);
131674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        List subroutineCalls = new ArrayList();
132674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        Map subroutineHeads = new HashMap();
133674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        findSubroutine(0, main, subroutineCalls);
134674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        while (!subroutineCalls.isEmpty()) {
135674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            JumpInsnNode jsr = (JumpInsnNode) subroutineCalls.remove(0);
136674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            Subroutine sub = (Subroutine) subroutineHeads.get(jsr.label);
137674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            if (sub == null) {
138674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                sub = new Subroutine(jsr.label, m.maxLocals, jsr);
139674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                subroutineHeads.put(jsr.label, sub);
140674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                findSubroutine(insns.indexOf(jsr.label), sub, subroutineCalls);
141674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            } else {
142674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                sub.callers.add(jsr);
143674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            }
144674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        }
145674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        for (int i = 0; i < n; ++i) {
146674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            if (subroutines[i] != null && subroutines[i].start == null) {
147674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                subroutines[i] = null;
148674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            }
149674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        }
150674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen
151674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        // initializes the data structures for the control flow analysis
152674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        Frame current = newFrame(m.maxLocals, m.maxStack);
153674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        Frame handler = newFrame(m.maxLocals, m.maxStack);
154674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        Type[] args = Type.getArgumentTypes(m.desc);
155674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        int local = 0;
156674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        if ((m.access & ACC_STATIC) == 0) {
157674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            Type ctype = Type.getObjectType(owner);
158674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            current.setLocal(local++, interpreter.newValue(ctype));
159674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        }
160674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        for (int i = 0; i < args.length; ++i) {
161674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            current.setLocal(local++, interpreter.newValue(args[i]));
162674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            if (args[i].getSize() == 2) {
163674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                current.setLocal(local++, interpreter.newValue(null));
164674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            }
165674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        }
166674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        while (local < m.maxLocals) {
167674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            current.setLocal(local++, interpreter.newValue(null));
168674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        }
169674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        merge(0, current, null);
170674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen
171674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        // control flow analysis
172674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        while (top > 0) {
173674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            int insn = queue[--top];
174674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            Frame f = frames[insn];
175674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            Subroutine subroutine = subroutines[insn];
176674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            queued[insn] = false;
177674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen
178674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            try {
179674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                AbstractInsnNode insnNode = m.instructions.get(insn);
180674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                int insnOpcode = insnNode.getOpcode();
181674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                int insnType = insnNode.getType();
182674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen
183674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                if (insnType == AbstractInsnNode.LABEL
184674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                        || insnType == AbstractInsnNode.LINE
185674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                        || insnType == AbstractInsnNode.FRAME)
186674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                {
187674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                    merge(insn + 1, f, subroutine);
188674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                    newControlFlowEdge(insn, insn + 1);
189674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                } else {
190674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                    current.init(f).execute(insnNode, interpreter);
191674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                    subroutine = subroutine == null ? null : subroutine.copy();
192674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen
193674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                    if (insnNode instanceof JumpInsnNode) {
194674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                        JumpInsnNode j = (JumpInsnNode) insnNode;
195674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                        if (insnOpcode != GOTO && insnOpcode != JSR) {
196674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                            merge(insn + 1, current, subroutine);
197674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                            newControlFlowEdge(insn, insn + 1);
198674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                        }
199674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                        int jump = insns.indexOf(j.label);
200674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                        if (insnOpcode == JSR) {
201674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                            merge(jump, current, new Subroutine(j.label,
202674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                                    m.maxLocals,
203674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                                    j));
204674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                        } else {
205674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                            merge(jump, current, subroutine);
206674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                        }
207674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                        newControlFlowEdge(insn, jump);
208674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                    } else if (insnNode instanceof LookupSwitchInsnNode) {
209674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                        LookupSwitchInsnNode lsi = (LookupSwitchInsnNode) insnNode;
210674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                        int jump = insns.indexOf(lsi.dflt);
211674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                        merge(jump, current, subroutine);
212674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                        newControlFlowEdge(insn, jump);
213674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                        for (int j = 0; j < lsi.labels.size(); ++j) {
214674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                            LabelNode label = (LabelNode) lsi.labels.get(j);
215674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                            jump = insns.indexOf(label);
216674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                            merge(jump, current, subroutine);
217674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                            newControlFlowEdge(insn, jump);
218674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                        }
219674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                    } else if (insnNode instanceof TableSwitchInsnNode) {
220674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                        TableSwitchInsnNode tsi = (TableSwitchInsnNode) insnNode;
221674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                        int jump = insns.indexOf(tsi.dflt);
222674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                        merge(jump, current, subroutine);
223674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                        newControlFlowEdge(insn, jump);
224674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                        for (int j = 0; j < tsi.labels.size(); ++j) {
225674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                            LabelNode label = (LabelNode) tsi.labels.get(j);
226674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                            jump = insns.indexOf(label);
227674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                            merge(jump, current, subroutine);
228674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                            newControlFlowEdge(insn, jump);
229674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                        }
230674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                    } else if (insnOpcode == RET) {
231674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                        if (subroutine == null) {
232674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                            throw new AnalyzerException("RET instruction outside of a sub routine");
233674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                        }
234674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                        for (int i = 0; i < subroutine.callers.size(); ++i) {
235674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                            Object caller = subroutine.callers.get(i);
236674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                            int call = insns.indexOf((AbstractInsnNode) caller);
237674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                            if (frames[call] != null) {
238674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                                merge(call + 1,
239674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                                        frames[call],
240674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                                        current,
241674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                                        subroutines[call],
242674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                                        subroutine.access);
243674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                                newControlFlowEdge(insn, call + 1);
244674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                            }
245674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                        }
246674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                    } else if (insnOpcode != ATHROW
247674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                            && (insnOpcode < IRETURN || insnOpcode > RETURN))
248674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                    {
249674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                        if (subroutine != null) {
250674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                            if (insnNode instanceof VarInsnNode) {
251674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                                int var = ((VarInsnNode) insnNode).var;
252674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                                subroutine.access[var] = true;
253674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                                if (insnOpcode == LLOAD || insnOpcode == DLOAD
254674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                                        || insnOpcode == LSTORE
255674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                                        || insnOpcode == DSTORE)
256674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                                {
257674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                                    subroutine.access[var + 1] = true;
258674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                                }
259674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                            } else if (insnNode instanceof IincInsnNode) {
260674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                                int var = ((IincInsnNode) insnNode).var;
261674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                                subroutine.access[var] = true;
262674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                            }
263674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                        }
264674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                        merge(insn + 1, current, subroutine);
265674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                        newControlFlowEdge(insn, insn + 1);
266674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                    }
267674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                }
268674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen
269674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                List insnHandlers = handlers[insn];
270674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                if (insnHandlers != null) {
271674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                    for (int i = 0; i < insnHandlers.size(); ++i) {
272674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                        TryCatchBlockNode tcb = (TryCatchBlockNode) insnHandlers.get(i);
273674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                        Type type;
274674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                        if (tcb.type == null) {
275674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                            type = Type.getObjectType("java/lang/Throwable");
276674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                        } else {
277674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                            type = Type.getObjectType(tcb.type);
278674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                        }
279674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                        int jump = insns.indexOf(tcb.handler);
280674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                        if (newControlFlowExceptionEdge(insn, jump)) {
281674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                            handler.init(f);
282674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                            handler.clearStack();
283674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                            handler.push(interpreter.newValue(type));
284674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                            merge(jump, handler, subroutine);
285674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                        }
286674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                    }
287674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                }
288674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            } catch (AnalyzerException e) {
289674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                throw new AnalyzerException("Error at instruction " + insn
290674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                        + ": " + e.getMessage(), e);
291674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            } catch (Exception e) {
292674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                throw new AnalyzerException("Error at instruction " + insn
293674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                        + ": " + e.getMessage(), e);
294674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            }
295674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        }
296674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen
297674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        return frames;
298674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    }
299674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen
300674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    private void findSubroutine(int insn, final Subroutine sub, final List calls)
301674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            throws AnalyzerException
302674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    {
303674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        while (true) {
304674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            if (insn < 0 || insn >= n) {
305674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                throw new AnalyzerException("Execution can fall off end of the code");
306674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            }
307674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            if (subroutines[insn] != null) {
308674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                return;
309674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            }
310674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            subroutines[insn] = sub.copy();
311674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            AbstractInsnNode node = insns.get(insn);
312674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen
313674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            // calls findSubroutine recursively on normal successors
314674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            if (node instanceof JumpInsnNode) {
315674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                if (node.getOpcode() == JSR) {
316674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                    // do not follow a JSR, it leads to another subroutine!
317674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                    calls.add(node);
318674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                } else {
319674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                    JumpInsnNode jnode = (JumpInsnNode) node;
320674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                    findSubroutine(insns.indexOf(jnode.label), sub, calls);
321674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                }
322674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            } else if (node instanceof TableSwitchInsnNode) {
323674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                TableSwitchInsnNode tsnode = (TableSwitchInsnNode) node;
324674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                findSubroutine(insns.indexOf(tsnode.dflt), sub, calls);
325674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                for (int i = tsnode.labels.size() - 1; i >= 0; --i) {
326674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                    LabelNode l = (LabelNode) tsnode.labels.get(i);
327674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                    findSubroutine(insns.indexOf(l), sub, calls);
328674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                }
329674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            } else if (node instanceof LookupSwitchInsnNode) {
330674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                LookupSwitchInsnNode lsnode = (LookupSwitchInsnNode) node;
331674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                findSubroutine(insns.indexOf(lsnode.dflt), sub, calls);
332674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                for (int i = lsnode.labels.size() - 1; i >= 0; --i) {
333674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                    LabelNode l = (LabelNode) lsnode.labels.get(i);
334674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                    findSubroutine(insns.indexOf(l), sub, calls);
335674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                }
336674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            }
337674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen
338674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            // calls findSubroutine recursively on exception handler successors
339674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            List insnHandlers = handlers[insn];
340674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            if (insnHandlers != null) {
341674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                for (int i = 0; i < insnHandlers.size(); ++i) {
342674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                    TryCatchBlockNode tcb = (TryCatchBlockNode) insnHandlers.get(i);
343674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                    findSubroutine(insns.indexOf(tcb.handler), sub, calls);
344674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                }
345674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            }
346674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen
347674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            // if insn does not falls through to the next instruction, return.
348674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            switch (node.getOpcode()) {
349674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                case GOTO:
350674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                case RET:
351674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                case TABLESWITCH:
352674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                case LOOKUPSWITCH:
353674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                case IRETURN:
354674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                case LRETURN:
355674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                case FRETURN:
356674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                case DRETURN:
357674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                case ARETURN:
358674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                case RETURN:
359674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                case ATHROW:
360674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                    return;
361674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            }
362674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            insn++;
363674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        }
364674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    }
365674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen
366674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    /**
367674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen     * Returns the symbolic stack frame for each instruction of the last
368674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen     * recently analyzed method.
369674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen     *
370674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen     * @return the symbolic state of the execution stack frame at each bytecode
371674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen     *         instruction of the method. The size of the returned array is
372674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen     *         equal to the number of instructions (and labels) of the method. A
373674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen     *         given frame is <tt>null</tt> if the corresponding instruction
374674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen     *         cannot be reached, or if an error occured during the analysis of
375674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen     *         the method.
376674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen     */
377674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    public Frame[] getFrames() {
378674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        return frames;
379674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    }
380674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen
381674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    /**
382674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen     * Returns the exception handlers for the given instruction.
383674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen     *
384674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen     * @param insn the index of an instruction of the last recently analyzed
385674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen     *        method.
386674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen     * @return a list of {@link TryCatchBlockNode} objects.
387674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen     */
388674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    public List getHandlers(final int insn) {
389674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        return handlers[insn];
390674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    }
391674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen
392674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    /**
393674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen     * Constructs a new frame with the given size.
394674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen     *
395674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen     * @param nLocals the maximum number of local variables of the frame.
396674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen     * @param nStack the maximum stack size of the frame.
397674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen     * @return the created frame.
398674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen     */
399674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    protected Frame newFrame(final int nLocals, final int nStack) {
400674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        return new Frame(nLocals, nStack);
401674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    }
402674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen
403674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    /**
404674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen     * Constructs a new frame that is identical to the given frame.
405674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen     *
406674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen     * @param src a frame.
407674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen     * @return the created frame.
408674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen     */
409674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    protected Frame newFrame(final Frame src) {
410674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        return new Frame(src);
411674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    }
412674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen
413674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    /**
414674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen     * Creates a control flow graph edge. The default implementation of this
415674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen     * method does nothing. It can be overriden in order to construct the
416674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen     * control flow graph of a method (this method is called by the
417674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen     * {@link #analyze analyze} method during its visit of the method's code).
418674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen     *
419674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen     * @param insn an instruction index.
420674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen     * @param successor index of a successor instruction.
421674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen     */
422674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    protected void newControlFlowEdge(final int insn, final int successor) {
423674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    }
424674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen
425674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    /**
426674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen     * Creates a control flow graph edge corresponding to an exception handler.
427674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen     * The default implementation of this method does nothing. It can be
428674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen     * overriden in order to construct the control flow graph of a method (this
429674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen     * method is called by the {@link #analyze analyze} method during its visit
430674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen     * of the method's code).
431674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen     *
432674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen     * @param insn an instruction index.
433674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen     * @param successor index of a successor instruction.
434674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen     * @return true if this edge must be considered in the data flow analysis
435674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen     *         performed by this analyzer, or false otherwise. The default
436674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen     *         implementation of this method always returns true.
437674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen     */
438674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    protected boolean newControlFlowExceptionEdge(
439674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        final int insn,
440674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        final int successor)
441674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    {
442674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        return true;
443674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    }
444674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen
445674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    // -------------------------------------------------------------------------
446674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen
447674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    private void merge(
448674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        final int insn,
449674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        final Frame frame,
450674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        final Subroutine subroutine) throws AnalyzerException
451674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    {
452674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        Frame oldFrame = frames[insn];
453674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        Subroutine oldSubroutine = subroutines[insn];
454674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        boolean changes;
455674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen
456674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        if (oldFrame == null) {
457674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            frames[insn] = newFrame(frame);
458674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            changes = true;
459674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        } else {
460674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            changes = oldFrame.merge(frame, interpreter);
461674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        }
462674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen
463674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        if (oldSubroutine == null) {
464674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            if (subroutine != null) {
465674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                subroutines[insn] = subroutine.copy();
466674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                changes = true;
467674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            }
468674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        } else {
469674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            if (subroutine != null) {
470674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                changes |= oldSubroutine.merge(subroutine);
471674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            }
472674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        }
473674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        if (changes && !queued[insn]) {
474674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            queued[insn] = true;
475674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            queue[top++] = insn;
476674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        }
477674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    }
478674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen
479674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    private void merge(
480674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        final int insn,
481674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        final Frame beforeJSR,
482674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        final Frame afterRET,
483674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        final Subroutine subroutineBeforeJSR,
484674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        final boolean[] access) throws AnalyzerException
485674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    {
486674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        Frame oldFrame = frames[insn];
487674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        Subroutine oldSubroutine = subroutines[insn];
488674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        boolean changes;
489674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen
490674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        afterRET.merge(beforeJSR, access);
491674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen
492674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        if (oldFrame == null) {
493674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            frames[insn] = newFrame(afterRET);
494674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            changes = true;
495674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        } else {
496674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            changes = oldFrame.merge(afterRET, access);
497674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        }
498674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen
499674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        if (oldSubroutine != null && subroutineBeforeJSR != null) {
500674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            changes |= oldSubroutine.merge(subroutineBeforeJSR);
501674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        }
502674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        if (changes && !queued[insn]) {
503674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            queued[insn] = true;
504674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            queue[top++] = insn;
505674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        }
506674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    }
507674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen}
508