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 Sigal
1869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal/**
1969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * Represents the stack frame and local variable table at a particular point in time.
2069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal *
2169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * @author Jason T. Greene
2269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal */
2369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigalpublic class Frame {
2469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    private Type[] locals;
2569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    private Type[] stack;
2669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    private int top;
2769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    private boolean jsrMerged;
2869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    private boolean retMerged;
2969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
3069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    /**
3169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * Create a new frame with the specified local variable table size, and max stack size
3269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     *
3369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * @param locals the number of local variable table entries
3469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * @param stack the maximum stack size
3569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     */
3669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    public Frame(int locals, int stack) {
3769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        this.locals = new Type[locals];
3869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        this.stack = new Type[stack];
3969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    }
4069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
4169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    /**
4269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * Returns the local varaible table entry at index.
4369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     *
4469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * @param index the position in the table
4569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * @return the type if one exists, or null if the position is empty
4669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     */
4769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    public Type getLocal(int index) {
4869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        return locals[index];
4969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    }
5069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
5169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    /**
5269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * Sets the local variable table entry at index to a type.
5369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     *
5469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * @param index the position in the table
5569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * @param type the type to set at the position
5669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     */
5769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    public void setLocal(int index, Type type) {
5869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        locals[index] = type;
5969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    }
6069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
6169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
6269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    /**
6369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * Returns the type on the stack at the specified index.
6469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     *
6569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * @param index the position on the stack
6669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * @return the type of the stack position
6769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     */
6869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    public Type getStack(int index) {
6969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        return stack[index];
7069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    }
7169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
7269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    /**
7369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * Sets the type of the stack position
7469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     *
7569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * @param index the position on the stack
7669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * @param type the type to set
7769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     */
7869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    public void setStack(int index, Type type) {
7969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        stack[index] = type;
8069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    }
8169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
8269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    /**
8369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * Empties the stack
8469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     */
8569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    public void clearStack() {
8669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        top = 0;
8769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    }
8869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
8969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    /**
9069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * Gets the index of the type sitting at the top of the stack.
9169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * This is not to be confused with a length operation which
9269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * would return the number of elements, not the position of
9369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * the last element.
9469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     *
9569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * @return the position of the element at the top of the stack
9669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     */
9769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    public int getTopIndex() {
9869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        return top - 1;
9969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    }
10069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
10169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    /**
10269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * Returns the number of local variable table entries, specified
10369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * at construction.
10469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     *
10569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * @return the number of local variable table entries
10669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     */
10769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    public int localsLength() {
10869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        return locals.length;
10969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    }
11069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
11169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    /**
11269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * Gets the top of the stack without altering it
11369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     *
11469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * @return the top of the stack
11569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     */
11669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    public Type peek() {
11769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        if (top < 1)
11869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            throw new IndexOutOfBoundsException("Stack is empty");
11969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
12069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        return stack[top - 1];
12169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    }
12269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
12369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    /**
12469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * Alters the stack to contain one less element and return it.
12569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     *
12669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * @return the element popped from the stack
12769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     */
12869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    public Type pop() {
12969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        if (top < 1)
13069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            throw new IndexOutOfBoundsException("Stack is empty");
13169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        return stack[--top];
13269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    }
13369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
13469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    /**
13569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * Alters the stack by placing the passed type on the top
13669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     *
13769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * @param type the type to add to the top
13869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     */
13969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    public void push(Type type) {
14069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        stack[top++] = type;
14169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    }
14269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
14369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
14469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    /**
14569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * Makes a shallow copy of this frame, i.e. the type instances will
14669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * remain the same.
14769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     *
14869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * @return the shallow copy
14969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     */
15069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    public Frame copy() {
15169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        Frame frame = new Frame(locals.length, stack.length);
15269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        System.arraycopy(locals, 0, frame.locals, 0, locals.length);
15369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        System.arraycopy(stack, 0, frame.stack, 0, stack.length);
15469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        frame.top = top;
15569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        return frame;
15669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    }
15769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
15869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    /**
15969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * Makes a shallow copy of the stack portion of this frame. The local
16069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * variable table size will be copied, but its contents will be empty.
16169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     *
16269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * @return the shallow copy of the stack
16369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     */
16469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    public Frame copyStack() {
16569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        Frame frame = new Frame(locals.length, stack.length);
16669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        System.arraycopy(stack, 0, frame.stack, 0, stack.length);
16769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        frame.top = top;
16869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        return frame;
16969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    }
17069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
17169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    /**
17269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * Merges all types on the stack of this frame instance with that of the specified frame.
17369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * The local variable table is left untouched.
17469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     *
17569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * @param frame the frame to merge the stack from
17669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * @return true if any changes where made
17769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     */
17869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    public boolean mergeStack(Frame frame) {
17969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        boolean changed = false;
18069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        if (top != frame.top)
18169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            throw new RuntimeException("Operand stacks could not be merged, they are different sizes!");
18269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
18369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        for (int i = 0; i < top; i++) {
18469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            if (stack[i] != null) {
18569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                Type prev = stack[i];
18669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                Type merged = prev.merge(frame.stack[i]);
18769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                if (merged == Type.BOGUS)
18869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                    throw new RuntimeException("Operand stacks could not be merged due to differing primitive types: pos = " + i);
18969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
19069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                stack[i] = merged;
19169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                // always replace the instance in case a multi-interface type changes to a normal Type
19269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                if ((! merged.equals(prev)) || merged.popChanged()) {
19369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                    changed = true;
19469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                }
19569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            }
19669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        }
19769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
19869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        return changed;
19969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    }
20069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
20169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    /**
20269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * Merges all types on the stack and local variable table of this frame with that of the specified
20369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * type.
20469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     *
20569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * @param frame the frame to merge with
20669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * @return true if any changes to this frame where made by this merge
20769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     */
20869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    public boolean merge(Frame frame) {
20969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        boolean changed = false;
21069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
21169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        // Local variable table
21269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        for (int i = 0; i < locals.length; i++) {
21369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            if (locals[i] != null) {
21469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                Type prev = locals[i];
21569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                Type merged = prev.merge(frame.locals[i]);
21669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                // always replace the instance in case a multi-interface type changes to a normal Type
21769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                locals[i] = merged;
21869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                if (! merged.equals(prev) || merged.popChanged()) {
21969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                    changed = true;
22069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                }
22169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            } else if (frame.locals[i] != null) {
22269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                locals[i] = frame.locals[i];
22369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                changed = true;
22469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            }
22569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        }
22669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
22769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        changed |= mergeStack(frame);
22869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        return changed;
22969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    }
23069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
23169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    public String toString() {
23269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        StringBuffer buffer = new StringBuffer();
23369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
23469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        buffer.append("locals = [");
23569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        for (int i = 0; i < locals.length; i++) {
23669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            buffer.append(locals[i] == null ? "empty" : locals[i].toString());
23769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            if (i < locals.length - 1)
23869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                buffer.append(", ");
23969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        }
24069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        buffer.append("] stack = [");
24169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        for (int i = 0; i < top; i++) {
24269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            buffer.append(stack[i]);
24369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            if (i < top - 1)
24469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                buffer.append(", ");
24569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        }
24669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        buffer.append("]");
24769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
24869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        return buffer.toString();
24969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    }
25069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
25169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    /**
25269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * Whether or not state from the source JSR instruction has been merged
25369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     *
25469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * @return true if JSR state has been merged
25569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     */
25669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    boolean isJsrMerged() {
25769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        return jsrMerged;
25869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    }
25969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
26069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    /**
26169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * Sets whether of not the state from the source JSR instruction has been merged
26269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     *
26369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * @param jsrMerged true if merged, otherwise false
26469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     */
26569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    void setJsrMerged(boolean jsrMerged) {
26669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        this.jsrMerged = jsrMerged;
26769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    }
26869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
26969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    /**
27069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * Whether or not state from the RET instruction, of the subroutine that was jumped
27169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * to has been merged.
27269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     *
27369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * @return true if RET state has been merged
27469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     */
27569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    boolean isRetMerged() {
27669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        return retMerged;
27769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    }
27869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
27969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    /**
28069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * Sets whether or not state from the RET instruction, of the subroutine that was jumped
28169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * to has been merged.
28269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     *
28369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * @param retMerged true if RET state has been merged
28469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     */
28569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    void setRetMerged(boolean retMerged) {
28669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        this.retMerged = retMerged;
28769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    }
28869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal}
289