001: /* SwitchBlock Copyright (C) 1998-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: SwitchBlock.java,v 4.15.2.1 2002/05/28 17:34:09 hoenicke Exp $
018: */
019:
020: package jode.flow;
021:
022: import jode.decompiler.TabbedPrintWriter;
023: import jode.expr.Expression;
024:
025: /**
026: * This is the structured block for an empty block.
027: */
028: public class SwitchBlock extends InstructionContainer implements
029: BreakableBlock {
030: CaseBlock[] caseBlocks;
031: VariableStack exprStack;
032: VariableStack breakedStack;
033:
034: public SwitchBlock(Expression instr, int[] cases, FlowBlock[] dests) {
035: super (instr);
036:
037: /* First remove all dests that jump to the default dest. */
038: int numCases = dests.length;
039: FlowBlock defaultDest = dests[cases.length];
040: for (int i = 0; i < cases.length; i++) {
041: if (dests[i] == defaultDest) {
042: dests[i] = null;
043: numCases--;
044: }
045: }
046:
047: caseBlocks = new CaseBlock[numCases];
048: FlowBlock lastDest = null;
049: for (int i = numCases - 1; i >= 0; i--) {
050: /**
051: * Sort the destinations by finding the greatest destAddr
052: */
053: int index = 0;
054: for (int j = 1; j < dests.length; j++) {
055: if (dests[j] != null
056: && (dests[index] == null || dests[j].getAddr() >= dests[index]
057: .getAddr()))
058: index = j;
059: }
060: /* assert(dests[index] != null) */
061:
062: int value;
063: if (index == cases.length)
064: value = -1;
065: else
066: value = cases[index];
067:
068: if (dests[index] == lastDest)
069: caseBlocks[i] = new CaseBlock(value);
070: else
071: caseBlocks[i] = new CaseBlock(value, new Jump(
072: dests[index]));
073: caseBlocks[i].outer = this ;
074: lastDest = dests[index];
075: dests[index] = null;
076: if (index == cases.length)
077: caseBlocks[i].isDefault = true;
078: }
079: caseBlocks[numCases - 1].isLastBlock = true;
080: this .jump = null;
081: isBreaked = false;
082: }
083:
084: /**
085: * This does take the instr into account and modifies stack
086: * accordingly. It then calls super.mapStackToLocal.
087: * @param stack the stack before the instruction is called
088: * @return stack the stack afterwards.
089: */
090: public VariableStack mapStackToLocal(VariableStack stack) {
091: VariableStack newStack;
092: int params = instr.getFreeOperandCount();
093: if (params > 0) {
094: exprStack = stack.peek(params);
095: newStack = stack.pop(params);
096: } else
097: newStack = stack;
098: VariableStack lastStack = newStack;
099: for (int i = 0; i < caseBlocks.length; i++) {
100: if (lastStack != null)
101: newStack.merge(lastStack);
102: lastStack = caseBlocks[i].mapStackToLocal(newStack);
103: }
104: if (lastStack != null)
105: mergeBreakedStack(lastStack);
106: if (jump != null) {
107: jump.stackMap = breakedStack;
108: return null;
109: }
110: return breakedStack;
111: }
112:
113: /**
114: * Is called by BreakBlock, to tell us what the stack can be after a
115: * break.
116: */
117: public void mergeBreakedStack(VariableStack stack) {
118: if (breakedStack != null)
119: breakedStack.merge(stack);
120: else
121: breakedStack = stack;
122: }
123:
124: public void removePush() {
125: if (exprStack != null)
126: instr = exprStack.mergeIntoExpression(instr);
127: super .removePush();
128: }
129:
130: /**
131: * Find the case that jumps directly to destination.
132: * @return The sub block of the case block, which jumps to destination.
133: */
134: public StructuredBlock findCase(FlowBlock destination) {
135: for (int i = 0; i < caseBlocks.length; i++) {
136: if (caseBlocks[i].subBlock != null
137: && caseBlocks[i].subBlock instanceof EmptyBlock
138: && caseBlocks[i].subBlock.jump != null
139: && caseBlocks[i].subBlock.jump.destination == destination)
140:
141: return caseBlocks[i].subBlock;
142: }
143: return null;
144: }
145:
146: /**
147: * Find the case that precedes the given case.
148: * @param block The sub block of the case, whose predecessor should
149: * be returned.
150: * @return The sub block of the case precedes the given case.
151: */
152: public StructuredBlock prevCase(StructuredBlock block) {
153: for (int i = caseBlocks.length - 1; i >= 0; i--) {
154: if (caseBlocks[i].subBlock == block) {
155: for (i--; i >= 0; i--) {
156: if (caseBlocks[i].subBlock != null)
157: return caseBlocks[i].subBlock;
158: }
159: }
160: }
161: return null;
162: }
163:
164: /**
165: * Returns the block where the control will normally flow to, when
166: * the given sub block is finished (<em>not</em> ignoring the jump
167: * after this block). (This is overwritten by SequentialBlock and
168: * SwitchBlock). If this isn't called with a direct sub block,
169: * the behaviour is undefined, so take care.
170: * @return null, if the control flows to another FlowBlock. */
171: public StructuredBlock getNextBlock(StructuredBlock subBlock) {
172: for (int i = 0; i < caseBlocks.length - 1; i++) {
173: if (subBlock == caseBlocks[i]) {
174: return caseBlocks[i + 1];
175: }
176: }
177: return getNextBlock();
178: }
179:
180: public FlowBlock getNextFlowBlock(StructuredBlock subBlock) {
181: for (int i = 0; i < caseBlocks.length - 1; i++) {
182: if (subBlock == caseBlocks[i]) {
183: return null;
184: }
185: }
186: return getNextFlowBlock();
187: }
188:
189: public void dumpInstruction(TabbedPrintWriter writer)
190: throws java.io.IOException {
191: if (label != null) {
192: writer.untab();
193: writer.println(label + ":");
194: writer.tab();
195: }
196: writer.print("switch (");
197: instr.dumpExpression(writer.EXPL_PAREN, writer);
198: writer.print(")");
199: writer.openBrace();
200: for (int i = 0; i < caseBlocks.length; i++)
201: caseBlocks[i].dumpSource(writer);
202: writer.closeBrace();
203: }
204:
205: /**
206: * Returns all sub block of this structured block.
207: */
208: public StructuredBlock[] getSubBlocks() {
209: return caseBlocks;
210: }
211:
212: boolean isBreaked = false;
213:
214: /**
215: * The serial number for labels.
216: */
217: static int serialno = 0;
218:
219: /**
220: * The label of this instruction, or null if it needs no label.
221: */
222: String label = null;
223:
224: /**
225: * Returns the label of this block and creates a new label, if
226: * there wasn't a label previously.
227: */
228: public String getLabel() {
229: if (label == null)
230: label = "switch_" + (serialno++) + "_";
231: return label;
232: }
233:
234: /**
235: * Is called by BreakBlock, to tell us that this block is breaked.
236: */
237: public void setBreaked() {
238: isBreaked = true;
239: }
240:
241: /**
242: * Determines if there is a sub block, that flows through to the end
243: * of this block. If this returns true, you know that jump is null.
244: * @return true, if the jump may be safely changed.
245: */
246: public boolean jumpMayBeChanged() {
247: return !isBreaked
248: && (caseBlocks[caseBlocks.length - 1].jump != null || caseBlocks[caseBlocks.length - 1]
249: .jumpMayBeChanged());
250: }
251: }
|