KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > jode > flow > SequentialBlock


1 /* SequentialBlock Copyright (C) 1998-2002 Jochen Hoenicke.
2  *
3  * This program is free software; you can redistribute it and/or modify
4  * it under the terms of the GNU Lesser General Public License as published by
5  * the Free Software Foundation; either version 2, or (at your option)
6  * any later version.
7  *
8  * This program is distributed in the hope that it will be useful,
9  * but WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11  * GNU General Public License for more details.
12  *
13  * You should have received a copy of the GNU Lesser General Public License
14  * along with this program; see the file COPYING.LESSER. If not, write to
15  * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
16  *
17  * $Id: SequentialBlock.java.in,v 4.1.2.1 2002/05/28 17:34:09 hoenicke Exp $
18  */

19
20 package jode.flow;
21 import jode.decompiler.TabbedPrintWriter;
22 import jode.decompiler.LocalInfo;
23 import jode.expr.LocalStoreOperator;
24 import jode.expr.StoreInstruction;
25 import jode.util.SimpleSet;
26
27 import java.util.Set JavaDoc;
28
29 /**
30  * A sequential block combines exactly two structured blocks to a new
31  * one. The first sub block mustn't be another sequential block,
32  * instead the second sub block should be used for this.
33  */

34 public class SequentialBlock extends StructuredBlock {
35     StructuredBlock[] subBlocks;
36
37     public SequentialBlock() {
38         subBlocks = new StructuredBlock[2];
39     }
40
41     public void setFirst(StructuredBlock sb) {
42         subBlocks[0] = sb;
43         sb.outer = this;
44         sb.setFlowBlock(flowBlock);
45     }
46
47     public void setSecond(StructuredBlock sb) {
48         subBlocks[1] = sb;
49         sb.outer = this;
50         sb.setFlowBlock(flowBlock);
51     }
52
53     public void checkConsistent() {
54         super.checkConsistent();
55         if (subBlocks[0].jump != null
56             || subBlocks[0] instanceof SequentialBlock
57             || jump != null)
58             throw new jode.AssertError("Inconsistency");
59     }
60
61     /**
62      * This does take the instr into account and modifies stack
63      * accordingly. It then calls super.mapStackToLocal.
64      * @param stack the stack before the instruction is called
65      * @return stack the stack afterwards.
66      */

67     public VariableStack mapStackToLocal(VariableStack stack) {
68     if (stack == null)
69         jode.GlobalOptions.err.println("map stack to local called with null: " + this+ " in "+this.flowBlock);
70     VariableStack middle = subBlocks[0].mapStackToLocal(stack);
71     if (middle != null)
72         // Otherwise the second block is at least "logical" dead code
73
return subBlocks[1].mapStackToLocal(middle);
74     jode.GlobalOptions.err.println("Dead code after Block " + subBlocks[0]);
75     return null;
76     }
77
78     /**
79      * This method should remove local variables that are only written
80      * and read one time directly after another. <br>
81      *
82      * This is especially important for stack locals, that are created
83      * when there are unusual swap or dup instructions, but also makes
84      * inlined functions more pretty (but not that close to the
85      * bytecode).
86      */

87     public void removeOnetimeLocals() {
88     StructuredBlock secondBlock = subBlocks[1];
89     if (secondBlock instanceof SequentialBlock)
90         secondBlock = ((SequentialBlock)secondBlock).subBlocks[0];
91     if (subBlocks[0] instanceof InstructionBlock
92         && secondBlock instanceof InstructionContainer) {
93         InstructionBlock first = (InstructionBlock) subBlocks[0];
94         InstructionContainer second = (InstructionContainer) secondBlock;
95         /* check if subBlocks[0] writes to a local, second reads
96          * that local, the local is only used by this two blocks,
97          * and there are no side effects. In that case replace
98          * the LoadLocal with the righthandside of subBlocks[0]
99          * and replace subBlocks[1] with this block. Call
100          * removeOnetimelLocals on subBlocks[1] afterwards and
101          * return.
102          */

103
104         if (first.getInstruction() instanceof StoreInstruction) {
105         StoreInstruction store
106             = (StoreInstruction) first.getInstruction();
107         if (store.getLValue() instanceof LocalStoreOperator
108             && (((LocalStoreOperator) store.getLValue())
109             .getLocalInfo().getUseCount() == 2)
110             && (second.getInstruction().canCombine(store) > 0)) {
111             System.err.println("before: "+first+second);
112
113             second.setInstruction(second.getInstruction()
114                       .combine(store));
115             System.err.println("after: "+second);
116             StructuredBlock sb = subBlocks[1];
117             sb.moveDefinitions(this, sb);
118             sb.replace(this);
119             sb.removeOnetimeLocals();
120             return;
121         }
122         }
123     }
124     super.removeOnetimeLocals();
125     }
126
127     /**
128      * Returns the block where the control will normally flow to, when
129      * the given sub block is finished (<em>not</em> ignoring the jump
130      * after this block). (This is overwritten by SequentialBlock and
131      * SwitchBlock). If this isn't called with a direct sub block,
132      * the behaviour is undefined, so take care.
133      * @return null, if the control flows to another FlowBlock. */

134     public StructuredBlock getNextBlock(StructuredBlock subBlock) {
135         if (subBlock == subBlocks[0]) {
136             if (subBlocks[1].isEmpty())
137                 return subBlocks[1].getNextBlock();
138             else
139                 return subBlocks[1];
140         }
141         return getNextBlock();
142     }
143
144     public FlowBlock getNextFlowBlock(StructuredBlock subBlock) {
145         if (subBlock == subBlocks[0]) {
146             if (subBlocks[1].isEmpty())
147                 return subBlocks[1].getNextFlowBlock();
148             else
149                 return null;
150         }
151         return getNextFlowBlock();
152     }
153
154     /**
155      * Tells if the sub block is the single exit point of the current block.
156      * @param subBlock the sub block.
157      * @return true, if the sub block is the single exit point of the
158      * current block.
159      */

160     public boolean isSingleExit(StructuredBlock subBlock) {
161     return (subBlock == subBlocks[1]);
162     }
163     
164     /**
165      * Propagate the used set. Sequential blocks are special, because
166      * they "use" everything the first block uses. This is, because
167      * the first block can't declare something that is only visible in
168      * the first block.
169      *
170      * @return all locals that are used in this block or in some sub
171      * block (this is <i>not</i> the used set).
172      */

173     public Set propagateUsage() {
174     used = new SimpleSet();
175         Set allUse = new SimpleSet();
176     Set childUse0 = subBlocks[0].propagateUsage();
177     Set childUse1 = subBlocks[1].propagateUsage();
178     /* All variables used somewhere inside both sub blocks, are
179      * used in this block, too.
180      * Also the variables used in first block are used in this
181      * block, except when it can be declared locally. (Note that
182      * subBlocks[0].used != childUse0)
183      */

184     used.addAll(subBlocks[0].used);
185     if (subBlocks[0] instanceof LoopBlock)
186         ((LoopBlock) subBlocks[0]).removeLocallyDeclareable(used);
187     allUse.addAll(childUse0);
188     allUse.addAll(childUse1);
189     childUse0.retainAll(childUse1);
190     used.addAll(childUse0);
191         return allUse;
192     }
193
194     /**
195      * Make the declarations, i.e. initialize the declare variable
196      * to correct values. This will declare every variable that
197      * is marked as used, but not done.
198      * @param done The set of the already declare variables.
199      */

200     public void makeDeclaration(Set done) {
201     super.makeDeclaration(done);
202     if (subBlocks[0] instanceof InstructionBlock)
203         /* An instruction block may declare a variable for us.
204          */

205         ((InstructionBlock) subBlocks[0]).checkDeclaration(this.declare);
206     }
207
208     public void dumpInstruction(TabbedPrintWriter writer)
209         throws java.io.IOException JavaDoc
210     {
211         subBlocks[0].dumpSource(writer);
212         subBlocks[1].dumpSource(writer);
213     }
214
215     /**
216      * Replaces the given sub block with a new block.
217      * @param oldBlock the old sub block.
218      * @param newBlock the new sub block.
219      * @return false, if oldBlock wasn't a direct sub block.
220      */

221     public boolean replaceSubBlock(StructuredBlock oldBlock,
222                             StructuredBlock newBlock) {
223         for (int i=0; i<2; i++) {
224             if (subBlocks[i] == oldBlock) {
225                 subBlocks[i] = newBlock;
226                 return true;
227             }
228         }
229         return false;
230     }
231
232     /**
233      * Returns all sub block of this structured block.
234      */

235     public StructuredBlock[] getSubBlocks() {
236         return subBlocks;
237     }
238
239     /**
240      * Determines if there is a sub block, that flows through to the end
241      * of this block. If this returns true, you know that jump is null.
242      * @return true, if the jump may be safely changed.
243      */

244     public boolean jumpMayBeChanged() {
245         return (subBlocks[1].jump != null || subBlocks[1].jumpMayBeChanged());
246     }
247 }
248
Popular Tags