KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > jode > flow > LoopBlock


1 /* LoopBlock 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: LoopBlock.java.in,v 4.3.2.2 2002/05/28 17:34:09 hoenicke Exp $
18  */

19
20 package jode.flow;
21 import jode.decompiler.TabbedPrintWriter;
22 import jode.type.Type;
23 import jode.decompiler.LocalInfo;
24 import jode.expr.Expression;
25 import jode.expr.ConstOperator;
26 import jode.expr.StoreInstruction;
27 import jode.expr.LocalStoreOperator;
28 import jode.expr.CombineableOperator;
29 import jode.util.SimpleSet;
30
31 import java.util.Set JavaDoc;
32
33 /**
34  * This is the structured block for an Loop block.
35  */

36 public class LoopBlock extends StructuredBlock implements BreakableBlock {
37
38     public static final int WHILE = 0;
39     public static final int DOWHILE = 1;
40     public static final int FOR = 2;
41     public static final int POSSFOR = 3;
42
43     public static final Expression TRUE =
44         new ConstOperator(Boolean.TRUE);
45     public static final Expression FALSE =
46         new ConstOperator(Boolean.FALSE);
47
48     /**
49      * The condition. Must be of boolean type.
50      */

51     Expression cond;
52     /**
53      * The stack the condition eats.
54      */

55     VariableStack condStack;
56     /**
57      * The init instruction block, only valid if type == POSSFOR
58      */

59     InstructionBlock initBlock;
60     /**
61      * The increase instruction block, only valid if type == POSSFOR.
62      */

63     InstructionBlock incrBlock;
64
65     /**
66      * The init instruction, only valid if type == FOR.
67      */

68     Expression initInstr;
69     /**
70      * The increase instruction, only valid if type == FOR.
71      */

72     Expression incrInstr;
73     
74     /**
75      * True, if the initializer is a declaration.
76      */

77     boolean isDeclaration;
78
79     /**
80      * The type of the loop. This must be one of DOWHILE, WHILE or FOR.
81      */

82     int type;
83
84     /**
85      * The body of this loop. This is always a valid block and not null.
86      */

87     StructuredBlock bodyBlock;
88
89     /**
90      * The stack after the break.
91      */

92     VariableStack breakedStack;
93
94     /**
95      * The stack at begin of the loop.
96      */

97     VariableStack continueStack;
98
99     /*{ invariant { type == POSSFOR || (incrBlock == null && initBlock == null)
100             :: "(while/do while) with incr";
101             type == FOR || (incrInstr == null && initInstr == null)
102             :: "(while/do while/poss for) with init";
103             type != POSSFOR || incrBlock != null
104             :: "possible for without incr";
105             type != FOR || incrInstr != null
106             :: "for without incr";
107             type != POSSFOR ||
108                     incrBlock.getInstruction() instanceof CombineableOperator
109             :: "possible for with invalid incr";
110             initBlock == null ||
111             (initBlock.getInstruction() instanceof CombinableOperator)
112             :: "Initializer is not combinableOperator";
113             initInstr == null ||
114             (initInstr instanceof CombinableOperator)
115             :: "Initializer is not combinableOperator";
116             cond != null && cond.getType() == Type.tBoolean
117             :: "invalid condition type";
118             type != POSSFOR || bodyBlock.contains(incr)
119             :: "incr is not in body of possible for" } }*/

120
121     /**
122      * Returns the block where the control will normally flow to, when
123      * the given sub block is finished (<em>not</em> ignoring the jump
124      * after this block). (This is overwritten by SequentialBlock and
125      * SwitchBlock). If this isn't called with a direct sub block,
126      * the behaviour is undefined, so take care.
127      * @return null, if the control flows to another FlowBlock. */

128     public StructuredBlock getNextBlock(StructuredBlock subBlock) {
129         return this;
130     }
131
132     public FlowBlock getNextFlowBlock(StructuredBlock subBlock) {
133         return null;
134     }
135     
136     public LoopBlock(int type, Expression cond) {
137         this.type = type;
138         this.cond = cond;
139         this.mayChangeJump = (cond == TRUE);
140     }
141
142     public void setBody(StructuredBlock body) {
143         bodyBlock = body;
144         bodyBlock.outer = this;
145         body.setFlowBlock(flowBlock);
146     }
147
148     public void setInit(InstructionBlock initBlock) {
149     if (type == POSSFOR) {
150         this.initBlock = initBlock;
151         } else if (type == FOR) {
152         this.initInstr = initBlock.getInstruction();
153             initBlock.removeBlock();
154     }
155     }
156
157     public boolean conditionMatches(CombineableOperator combinable) {
158         return (type == POSSFOR || cond.containsMatchingLoad(combinable));
159     }
160
161
162     public Expression getCondition() {
163         return cond;
164     }
165
166     public void setCondition(Expression cond) {
167         this.cond = cond;
168         if (type == POSSFOR) {
169             /* We can now say, if this is a for block or not.
170              */

171             if (cond.containsMatchingLoad((CombineableOperator)
172                       incrBlock.getInstruction())) {
173                 type = FOR;
174         incrInstr = incrBlock.getInstruction();
175                 incrBlock.removeBlock();
176                 if (initBlock != null) {
177                     if (cond.containsMatchingLoad
178             ((CombineableOperator) initBlock.getInstruction())) {
179             initInstr = initBlock.getInstruction();
180                         initBlock.removeBlock();
181                     }
182                 }
183             } else {
184                 /* This is not a for block, as it seems first. Make
185                  * it a while block again, and forget about init and
186                  * incr. */

187                 type = WHILE;
188             }
189         initBlock = incrBlock = null;
190         }
191         mayChangeJump = false;
192     }
193
194     public int getType() {
195         return type;
196     }
197
198     public void setType(int type) {
199         this.type = type;
200     }
201
202     /**
203      * Replaces the given sub block with a new block.
204      * @param oldBlock the old sub block.
205      * @param newBlock the new sub block.
206      * @return false, if oldBlock wasn't a direct sub block.
207      */

208     public boolean replaceSubBlock(StructuredBlock oldBlock,
209                                    StructuredBlock newBlock) {
210         if (bodyBlock == oldBlock)
211             bodyBlock = newBlock;
212         else
213             return false;
214         return true;
215     }
216
217     /**
218      * Returns all sub block of this structured block.
219      */

220     public StructuredBlock[] getSubBlocks() {
221         return new StructuredBlock[] { bodyBlock };
222     }
223
224     /**
225      * Remove all variables from set, that we can declare inside the
226      * loop-block. This is the initializer for for-blocks.
227      */

228     public void removeLocallyDeclareable(Set set) {
229     if (type == FOR && initInstr instanceof StoreInstruction) {
230         StoreInstruction storeOp = (StoreInstruction) initInstr;
231         if (storeOp.getLValue() instanceof LocalStoreOperator) {
232         LocalInfo local =
233             ((LocalStoreOperator) storeOp.getLValue()).getLocalInfo();
234         set.remove(local);
235         }
236     }
237     }
238
239     public Set getDeclarables() {
240     Set used = new SimpleSet();
241         if (type == FOR) {
242         incrInstr.fillDeclarables(used);
243         if (initInstr != null)
244         initInstr.fillDeclarables(used);
245     }
246     cond.fillDeclarables(used);
247         return used;
248     }
249
250     /**
251      * Check if this is an local store instruction to a not yet declared
252      * variable. In that case mark this as declaration and return the
253      * variable.
254      */

255     public void checkDeclaration(Set declareSet) {
256         if (initInstr instanceof StoreInstruction
257         && (((StoreInstruction)initInstr).getLValue()
258         instanceof LocalStoreOperator)) {
259         StoreInstruction storeOp = (StoreInstruction) initInstr;
260         LocalInfo local =
261         ((LocalStoreOperator) storeOp.getLValue()).getLocalInfo();
262             if (declareSet.contains(local)) {
263         /* Special case: This is a variable assignment, and
264          * the variable has not been declared before. We can
265          * change this to a initializing variable declaration.
266          */

267         isDeclaration = true;
268         declareSet.remove(local);
269         }
270     }
271     }
272
273     /**
274      * Make the declarations, i.e. initialize the declare variable
275      * to correct values. This will declare every variable that
276      * is marked as used, but not done.
277      * @param done The set of the already declare variables.
278      */

279     public void makeDeclaration(Set done) {
280     if (type == FOR) {
281         if (initInstr != null)
282         initInstr.makeDeclaration(done);
283         incrInstr.makeDeclaration(done);
284     }
285     cond.makeDeclaration(done);
286     super.makeDeclaration(done);
287         if (type == FOR && initInstr != null)
288         checkDeclaration(declare);
289     }
290
291     public void dumpSource(TabbedPrintWriter writer)
292     throws java.io.IOException JavaDoc
293     {
294         super.dumpSource(writer);
295     }
296
297     public void dumpInstruction(TabbedPrintWriter writer)
298     throws java.io.IOException JavaDoc
299     {
300         if (label != null) {
301             writer.untab();
302             writer.println(label+":");
303             writer.tab();
304         }
305         boolean needBrace = bodyBlock.needsBraces();
306         switch (type) {
307         case POSSFOR:
308             /* a possible for is now treated like a WHILE */
309         case WHILE:
310             if (cond == TRUE)
311                 /* special syntax for endless loops: */
312                 writer.print("for (;;)");
313             else {
314                 writer.print("while (");
315         cond.dumpExpression(writer.EXPL_PAREN, writer);
316         writer.print(")");
317         }
318             break;
319         case DOWHILE:
320             writer.print("do");
321             break;
322         case FOR:
323             writer.print("for (");
324         writer.startOp(writer.EXPL_PAREN, 0);
325             if (initInstr != null) {
326                 if (isDeclaration) {
327             StoreInstruction store = (StoreInstruction) initInstr;
328             LocalInfo local = ((LocalStoreOperator) store
329                        .getLValue()).getLocalInfo();
330             writer.startOp(writer.NO_PAREN, 1);
331             local.dumpDeclaration(writer);
332             writer.breakOp();
333             writer.print(" = ");
334             store.getSubExpressions()[1]
335             .makeInitializer(local.getType());
336             store.getSubExpressions()[1].dumpExpression(writer, 100);
337             writer.endOp();
338         } else
339             initInstr.dumpExpression(writer.NO_PAREN, writer);
340             } else {
341                 writer.print("/**/");
342         }
343             writer.print("; ");
344         writer.breakOp();
345         cond.dumpExpression(writer.IMPL_PAREN, writer);
346         writer.print("; ");
347         writer.breakOp();
348         incrInstr.dumpExpression(writer.NO_PAREN, writer);
349         writer.endOp();
350         writer.print(")");
351             break;
352         }
353     if (needBrace)
354         writer.openBrace();
355     else
356         writer.println();
357         writer.tab();
358         bodyBlock.dumpSource(writer);
359         writer.untab();
360         if (type == DOWHILE) {
361         if (needBrace)
362         writer.closeBraceContinue();
363             writer.print("while (");
364         cond.dumpExpression(writer.EXPL_PAREN, writer);
365         writer.println(");");
366         } else if (needBrace)
367             writer.closeBrace();
368     }
369
370     boolean mayChangeJump = true;
371
372     /**
373      * The serial number for labels.
374      */

375     static int serialno = 0;
376
377     /**
378      * The label of this instruction, or null if it needs no label.
379      */

380     String JavaDoc label = null;
381
382     /**
383      * Returns the label of this block and creates a new label, if
384      * there wasn't a label previously.
385      */

386     public String JavaDoc getLabel() {
387         if (label == null)
388             label = "while_"+(serialno++)+"_";
389         return label;
390     }
391
392     /**
393      * Is called by BreakBlock, to tell us that this block is breaked.
394      */

395     public void setBreaked() {
396     mayChangeJump = false;
397     }
398
399     /**
400      * This is called after the analysis is completely done. It
401      * will remove all PUSH/stack_i expressions, (if the bytecode
402      * is correct).
403      * @param stack the stack at begin of the block
404      * @return null if there is no way to the end of this block,
405      * otherwise the stack after the block has executed.
406      */

407     public VariableStack mapStackToLocal(VariableStack stack) {
408     if (type == DOWHILE) {
409         VariableStack afterBody = bodyBlock.mapStackToLocal(stack);
410         if (afterBody != null)
411         mergeContinueStack(afterBody);
412
413         if (continueStack != null) {
414         VariableStack newStack;
415         int params = cond.getFreeOperandCount();
416         if (params > 0) {
417             condStack = continueStack.peek(params);
418             newStack = continueStack.pop(params);
419         } else
420             newStack = continueStack;
421
422         if (cond != TRUE)
423             mergeBreakedStack(newStack);
424         if (cond != FALSE)
425             stack.merge(newStack);
426         }
427     } else {
428         continueStack = stack;
429         VariableStack newStack;
430         int params = cond.getFreeOperandCount();
431         if (params > 0) {
432         condStack = stack.peek(params);
433         newStack = stack.pop(params);
434         } else
435         newStack = stack;
436         if (cond != TRUE)
437         breakedStack = newStack;
438         VariableStack afterBody = bodyBlock.mapStackToLocal(newStack);
439         if (afterBody != null)
440         mergeContinueStack(afterBody);
441     }
442     return breakedStack;
443     }
444
445     /**
446      * Is called by BreakBlock, to tell us what the stack can be after a
447      * break.
448      * @return false if the stack is inconsistent.
449      */

450     public void mergeContinueStack(VariableStack stack) {
451     if (continueStack == null)
452         continueStack = stack;
453     else
454         continueStack.merge(stack);
455     }
456
457     /**
458      * Is called by BreakBlock, to tell us what the stack can be after a
459      * break.
460      * @return false if the stack is inconsistent.
461      */

462     public void mergeBreakedStack(VariableStack stack) {
463     if (breakedStack != null)
464         breakedStack.merge(stack);
465     else
466         breakedStack = stack;
467     }
468
469     public void removePush() {
470     if (condStack != null)
471         cond = condStack.mergeIntoExpression(cond);
472     bodyBlock.removePush();
473     }
474
475     /**
476      * This method should remove local variables that are only written
477      * and read one time directly after another. <br>
478      *
479      * This is especially important for stack locals, that are created
480      * when there are unusual swap or dup instructions, but also makes
481      * inlined functions more pretty (but not that close to the
482      * bytecode).
483      */

484     public void removeOnetimeLocals() {
485     cond = cond.removeOnetimeLocals();
486     if (type == FOR) {
487         if (initInstr != null)
488         initInstr.removeOnetimeLocals();
489         incrInstr.removeOnetimeLocals();
490     }
491     super.removeOnetimeLocals();
492     }
493
494     /**
495      * Replace all breaks to block with a continue to this.
496      * @param block the breakable block where the breaks originally
497      * breaked to (Have a break now, if you didn't understand that :-).
498      */

499     public void replaceBreakContinue(BreakableBlock block) {
500         java.util.Stack JavaDoc todo = new java.util.Stack JavaDoc();
501         todo.push(block);
502         while (!todo.isEmpty()) {
503             StructuredBlock[] subs =
504                 ((StructuredBlock)todo.pop()).getSubBlocks();
505             for (int i=0; i<subs.length; i++) {
506                 if (subs[i] instanceof BreakBlock) {
507                     BreakBlock breakblk = (BreakBlock) subs[i];
508                     if (breakblk.breaksBlock == block) {
509                         new ContinueBlock(this, breakblk.label != null)
510                             .replace(breakblk);
511                     }
512                 }
513                 todo.push(subs[i]);
514             }
515         }
516     }
517
518     /**
519      * Determines if there is a sub block, that flows through to the end
520      * of this block. If this returns true, you know that jump is null.
521      * @return true, if the jump may be safely changed.
522      */

523     public boolean jumpMayBeChanged() {
524         return mayChangeJump;
525     }
526
527     public void simplify() {
528     cond = cond.simplify();
529     if (type == FOR) {
530         incrInstr = incrInstr.simplify();
531         if (initInstr != null)
532         initInstr = initInstr.simplify();
533     }
534     super.simplify();
535     }
536
537     public boolean doTransformations() {
538         return ((initBlock == null && type == POSSFOR)
539         || (initInstr == null && type == FOR))
540             && CreateForInitializer.transform(this, flowBlock.lastModified);
541     }
542 }
543
544
Popular Tags