123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289 |
- /*
- * Javassist, a Java-bytecode translator toolkit.
- * Copyright (C) 1999- Shigeru Chiba. All Rights Reserved.
- *
- * The contents of this file are subject to the Mozilla Public License Version
- * 1.1 (the "License"); you may not use this file except in compliance with
- * the License. Alternatively, the contents of this file may be used under
- * the terms of the GNU Lesser General Public License Version 2.1 or later,
- * or the Apache License Version 2.0.
- *
- * Software distributed under the License is distributed on an "AS IS" basis,
- * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
- * for the specific language governing rights and limitations under the
- * License.
- */
- package javassist.bytecode.analysis;
-
-
- /**
- * Represents the stack frame and local variable table at a particular point in time.
- *
- * @author Jason T. Greene
- */
- public class Frame {
- private Type[] locals;
- private Type[] stack;
- private int top;
- private boolean jsrMerged;
- private boolean retMerged;
-
- /**
- * Create a new frame with the specified local variable table size, and max stack size
- *
- * @param locals the number of local variable table entries
- * @param stack the maximum stack size
- */
- public Frame(int locals, int stack) {
- this.locals = new Type[locals];
- this.stack = new Type[stack];
- }
-
- /**
- * Returns the local varaible table entry at index.
- *
- * @param index the position in the table
- * @return the type if one exists, or null if the position is empty
- */
- public Type getLocal(int index) {
- return locals[index];
- }
-
- /**
- * Sets the local variable table entry at index to a type.
- *
- * @param index the position in the table
- * @param type the type to set at the position
- */
- public void setLocal(int index, Type type) {
- locals[index] = type;
- }
-
-
- /**
- * Returns the type on the stack at the specified index.
- *
- * @param index the position on the stack
- * @return the type of the stack position
- */
- public Type getStack(int index) {
- return stack[index];
- }
-
- /**
- * Sets the type of the stack position
- *
- * @param index the position on the stack
- * @param type the type to set
- */
- public void setStack(int index, Type type) {
- stack[index] = type;
- }
-
- /**
- * Empties the stack
- */
- public void clearStack() {
- top = 0;
- }
-
- /**
- * Gets the index of the type sitting at the top of the stack.
- * This is not to be confused with a length operation which
- * would return the number of elements, not the position of
- * the last element.
- *
- * @return the position of the element at the top of the stack
- */
- public int getTopIndex() {
- return top - 1;
- }
-
- /**
- * Returns the number of local variable table entries, specified
- * at construction.
- *
- * @return the number of local variable table entries
- */
- public int localsLength() {
- return locals.length;
- }
-
- /**
- * Gets the top of the stack without altering it
- *
- * @return the top of the stack
- */
- public Type peek() {
- if (top < 1)
- throw new IndexOutOfBoundsException("Stack is empty");
-
- return stack[top - 1];
- }
-
- /**
- * Alters the stack to contain one less element and return it.
- *
- * @return the element popped from the stack
- */
- public Type pop() {
- if (top < 1)
- throw new IndexOutOfBoundsException("Stack is empty");
- return stack[--top];
- }
-
- /**
- * Alters the stack by placing the passed type on the top
- *
- * @param type the type to add to the top
- */
- public void push(Type type) {
- stack[top++] = type;
- }
-
-
- /**
- * Makes a shallow copy of this frame, i.e. the type instances will
- * remain the same.
- *
- * @return the shallow copy
- */
- public Frame copy() {
- Frame frame = new Frame(locals.length, stack.length);
- System.arraycopy(locals, 0, frame.locals, 0, locals.length);
- System.arraycopy(stack, 0, frame.stack, 0, stack.length);
- frame.top = top;
- return frame;
- }
-
- /**
- * Makes a shallow copy of the stack portion of this frame. The local
- * variable table size will be copied, but its contents will be empty.
- *
- * @return the shallow copy of the stack
- */
- public Frame copyStack() {
- Frame frame = new Frame(locals.length, stack.length);
- System.arraycopy(stack, 0, frame.stack, 0, stack.length);
- frame.top = top;
- return frame;
- }
-
- /**
- * Merges all types on the stack of this frame instance with that of the specified frame.
- * The local variable table is left untouched.
- *
- * @param frame the frame to merge the stack from
- * @return true if any changes where made
- */
- public boolean mergeStack(Frame frame) {
- boolean changed = false;
- if (top != frame.top)
- throw new RuntimeException("Operand stacks could not be merged, they are different sizes!");
-
- for (int i = 0; i < top; i++) {
- if (stack[i] != null) {
- Type prev = stack[i];
- Type merged = prev.merge(frame.stack[i]);
- if (merged == Type.BOGUS)
- throw new RuntimeException("Operand stacks could not be merged due to differing primitive types: pos = " + i);
-
- stack[i] = merged;
- // always replace the instance in case a multi-interface type changes to a normal Type
- if ((! merged.equals(prev)) || merged.popChanged()) {
- changed = true;
- }
- }
- }
-
- return changed;
- }
-
- /**
- * Merges all types on the stack and local variable table of this frame with that of the specified
- * type.
- *
- * @param frame the frame to merge with
- * @return true if any changes to this frame where made by this merge
- */
- public boolean merge(Frame frame) {
- boolean changed = false;
-
- // Local variable table
- for (int i = 0; i < locals.length; i++) {
- if (locals[i] != null) {
- Type prev = locals[i];
- Type merged = prev.merge(frame.locals[i]);
- // always replace the instance in case a multi-interface type changes to a normal Type
- locals[i] = merged;
- if (! merged.equals(prev) || merged.popChanged()) {
- changed = true;
- }
- } else if (frame.locals[i] != null) {
- locals[i] = frame.locals[i];
- changed = true;
- }
- }
-
- changed |= mergeStack(frame);
- return changed;
- }
-
- public String toString() {
- StringBuffer buffer = new StringBuffer();
-
- buffer.append("locals = [");
- for (int i = 0; i < locals.length; i++) {
- buffer.append(locals[i] == null ? "empty" : locals[i].toString());
- if (i < locals.length - 1)
- buffer.append(", ");
- }
- buffer.append("] stack = [");
- for (int i = 0; i < top; i++) {
- buffer.append(stack[i]);
- if (i < top - 1)
- buffer.append(", ");
- }
- buffer.append("]");
-
- return buffer.toString();
- }
-
- /**
- * Whether or not state from the source JSR instruction has been merged
- *
- * @return true if JSR state has been merged
- */
- boolean isJsrMerged() {
- return jsrMerged;
- }
-
- /**
- * Sets whether of not the state from the source JSR instruction has been merged
- *
- * @param jsrMerged true if merged, otherwise false
- */
- void setJsrMerged(boolean jsrMerged) {
- this.jsrMerged = jsrMerged;
- }
-
- /**
- * Whether or not state from the RET instruction, of the subroutine that was jumped
- * to has been merged.
- *
- * @return true if RET state has been merged
- */
- boolean isRetMerged() {
- return retMerged;
- }
-
- /**
- * Sets whether or not state from the RET instruction, of the subroutine that was jumped
- * to has been merged.
- *
- * @param retMerged true if RET state has been merged
- */
- void setRetMerged(boolean retMerged) {
- this.retMerged = retMerged;
- }
- }
|