001: /* VariableStack Copyright (C) 1999-2002 Jochen Hoenicke.
002: *
003: * This program is free software; you can redistribute it and/or modify
004: * it under the terms of the GNU Lesser General Public License as published by
005: * the Free Software Foundation; either version 2, or (at your option)
006: * any later version.
007: *
008: * This program is distributed in the hope that it will be useful,
009: * but WITHOUT ANY WARRANTY; without even the implied warranty of
010: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
011: * GNU General Public License for more details.
012: *
013: * You should have received a copy of the GNU Lesser General Public License
014: * along with this program; see the file COPYING.LESSER. If not, write to
015: * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
016: *
017: * $Id: VariableStack.java,v 1.8.4.1 2002/05/28 17:34:09 hoenicke Exp $
018: */
019:
020: package jode.flow;
021:
022: import jode.decompiler.LocalInfo;
023: import jode.expr.Expression;
024: import jode.expr.LocalLoadOperator;
025: import jode.expr.Operator;
026:
027: /**
028: * This class represents the state of the stack at various points in
029: * the program. Each entry is a anonymous local, which is used instead
030: * of the PUSH / stack_i statements. <p>
031: *
032: * This class is immutable, but note, that the local infos can get merged.
033: * @see FlowBlock.mapStackToLocal
034: * @see FlowBlock.removePush
035: */
036: public class VariableStack {
037: public final static VariableStack EMPTY = new VariableStack();
038:
039: final LocalInfo[] stackMap;
040:
041: private VariableStack() {
042: stackMap = new LocalInfo[0];
043: }
044:
045: private VariableStack(LocalInfo[] stack) {
046: stackMap = stack;
047: }
048:
049: public boolean isEmpty() {
050: return stackMap.length == 0;
051: }
052:
053: public VariableStack pop(int count) {
054: LocalInfo[] newStack = new LocalInfo[stackMap.length - count];
055: System.arraycopy(stackMap, 0, newStack, 0, stackMap.length
056: - count);
057: return new VariableStack(newStack);
058: }
059:
060: public VariableStack push(LocalInfo li) {
061: return poppush(0, li);
062: }
063:
064: public VariableStack poppush(int count, LocalInfo li) {
065: LocalInfo[] newStack = new LocalInfo[stackMap.length - count
066: + 1];
067: System.arraycopy(stackMap, 0, newStack, 0, stackMap.length
068: - count);
069: newStack[stackMap.length - count] = li;
070: return new VariableStack(newStack);
071: }
072:
073: public VariableStack peek(int count) {
074: LocalInfo[] peeked = new LocalInfo[count];
075: System.arraycopy(stackMap, stackMap.length - count, peeked, 0,
076: count);
077: return new VariableStack(peeked);
078: }
079:
080: public void merge(VariableStack other) {
081: if (stackMap.length != other.stackMap.length)
082: throw new IllegalArgumentException("stack length differs");
083: for (int i = 0; i < stackMap.length; i++) {
084: if (stackMap[i].getType().stackSize() != other.stackMap[i]
085: .getType().stackSize())
086: throw new IllegalArgumentException(
087: "stack element length differs at " + i);
088: stackMap[i].combineWith(other.stackMap[i]);
089: }
090: }
091:
092: /**
093: * Merge to VariableStacks. Either one may be null, in which case
094: * the other is returned.
095: */
096: public static VariableStack merge(VariableStack first,
097: VariableStack second) {
098: if (first == null)
099: return second;
100: else if (second == null)
101: return first;
102: first.merge(second);
103: return first;
104: }
105:
106: public Expression mergeIntoExpression(Expression expr) {
107: /* assert expr.getFreeOperandCount() == stackMap.length */
108:
109: for (int i = stackMap.length - 1; i >= 0; i--) {
110: // if (!used.contains(stackMap[i]))
111: // used.addElement(stackMap[i]);
112: expr = expr.addOperand(new LocalLoadOperator(stackMap[i]
113: .getType(), null, stackMap[i]));
114: }
115: return expr;
116: }
117:
118: public VariableStack executeSpecial(SpecialBlock special) {
119: if (special.type == special.POP) {
120: int popped = 0;
121: int newLength = stackMap.length;
122: while (popped < special.count) {
123: newLength--;
124: popped += stackMap[newLength].getType().stackSize();
125: }
126: if (popped != special.count)
127: throw new IllegalArgumentException("wrong POP");
128: LocalInfo[] newStack = new LocalInfo[newLength];
129: System.arraycopy(stackMap, 0, newStack, 0, newLength);
130: return new VariableStack(newStack);
131: } else if (special.type == special.DUP) {
132: int popped = 0;
133: int numDup = 0;
134: int startDup = stackMap.length;
135: while (popped < special.count) {
136: startDup--;
137: numDup++;
138: popped += stackMap[startDup].getType().stackSize();
139: }
140: if (popped != special.count)
141: throw new IllegalArgumentException("wrong DUP");
142: int destDup = startDup;
143: int depth = 0;
144: while (depth < special.depth) {
145: destDup--;
146: depth += stackMap[destDup].getType().stackSize();
147: }
148: if (depth != special.depth)
149: throw new IllegalArgumentException("wrong DUP");
150: LocalInfo[] newStack = new LocalInfo[stackMap.length
151: + numDup];
152: System.arraycopy(stackMap, 0, newStack, 0, destDup);
153: System.arraycopy(stackMap, startDup, newStack, destDup,
154: numDup);
155: System.arraycopy(stackMap, destDup, newStack, destDup
156: + numDup, startDup - destDup);
157: System.arraycopy(stackMap, startDup, newStack, startDup
158: + numDup, numDup);
159: return new VariableStack(newStack);
160: } else if (special.type == special.SWAP) {
161: LocalInfo[] newStack = new LocalInfo[stackMap.length];
162: System.arraycopy(stackMap, 0, newStack, 0,
163: stackMap.length - 2);
164: if (stackMap[stackMap.length - 2].getType().stackSize() != 1
165: || stackMap[stackMap.length - 1].getType()
166: .stackSize() != 1)
167: throw new IllegalArgumentException("wrong SWAP");
168: newStack[stackMap.length - 2] = stackMap[stackMap.length - 1];
169: newStack[stackMap.length - 1] = stackMap[stackMap.length - 2];
170: return new VariableStack(newStack);
171: } else
172: throw new jode.AssertError("Unknown SpecialBlock");
173: }
174:
175: public String toString() {
176: StringBuffer result = new StringBuffer("[");
177: for (int i = 0; i < stackMap.length; i++) {
178: if (i > 0)
179: result.append(", ");
180: result.append(stackMap[i].getName());
181: }
182: return result.append("]").toString();
183: }
184: }
|