Mirror of the JODE repository
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 
jode/jode/src/net/sf/jode/flow/CatchBlock.java

240 lines
7.2 KiB

/* CatchBlock Copyright (C) 1998-2002 Jochen Hoenicke.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; see the file COPYING.LESSER. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id$
*/
package net.sf.jode.flow;
import net.sf.jode.type.Type;
import net.sf.jode.decompiler.LocalInfo;
import net.sf.jode.decompiler.Declarable;
import net.sf.jode.expr.Expression;
import net.sf.jode.expr.LocalLoadOperator;
import net.sf.jode.expr.LocalStoreOperator;
import net.sf.jode.expr.NopOperator;
import net.sf.jode.expr.Operator;
import net.sf.jode.expr.StoreInstruction;
///#def COLLECTIONS java.util
import java.util.Collections;
import java.util.Iterator;
import java.util.Set;
///#enddef
/**
*
* @author Jochen Hoenicke
*/
public class CatchBlock extends StructuredBlock {
/**
* The catch block.
*/
StructuredBlock catchBlock;
/**
* The type of the exception.
*/
Type exceptionType;
/**
* The local containing the exception. May be null.
*/
LocalInfo exceptionLocal;
public CatchBlock(Type type) {
exceptionType = type;
}
public Type getExceptionType() {
return exceptionType;
}
public LocalInfo getLocal() {
return exceptionLocal;
}
/**
* Sets the catch block.
* @param catchBlock the catch block.
*/
public void setCatchBlock(StructuredBlock catchBlock) {
this.catchBlock = catchBlock;
catchBlock.outer = this;
catchBlock.setFlowBlock(flowBlock);
if (exceptionLocal == null)
combineLocal();
}
/* The implementation of getNext[Flow]Block is the standard
* implementation */
/**
* Replaces the given sub block with a new block.
* @param oldBlock the old sub block.
* @param newBlock the new sub block.
* @return false, if oldBlock wasn't a direct sub block.
*/
public boolean replaceSubBlock(StructuredBlock oldBlock,
StructuredBlock newBlock) {
if (catchBlock == oldBlock)
catchBlock = newBlock;
else
return false;
return true;
}
/**
* Returns all sub block of this structured block.
*/
public StructuredBlock[] getSubBlocks() {
return new StructuredBlock[] { catchBlock };
}
LocalInfo pushedLocal;
/**
* A catch block pushes the exception on the stack, iff a local
* doesn't exists.
* @param stack the stack before the instruction is called
* @return stack the stack afterwards.
*/
public VariableStack mapStackToLocal(VariableStack stack) {
VariableStack newStack;
if (exceptionLocal == null) {
pushedLocal = new LocalInfo();
pushedLocal.setType(exceptionType);
newStack = stack.push(pushedLocal);
} else
newStack = stack;
return super.mapStackToLocal(newStack);
}
public void removePush() {
if (pushedLocal != null)
exceptionLocal = pushedLocal;
super.removePush();
}
public Set getDeclarables() {
if (exceptionLocal != null)
return Collections.singleton(exceptionLocal);
return Collections.EMPTY_SET;
}
/**
* Make the declarations, i.e. initialize the declare variable
* to correct values. This will declare every variable that
* is marked as used, but not done.
* @param done The set of the already declare variables.
*/
public void makeDeclaration(Set done) {
super.makeDeclaration(done);
/* Normally we have to declare our exceptionLocal. This
* is automatically done in dumpSource.
*
* If we are unlucky the exceptionLocal is used outside of
* this block. In that case we do a transformation.
*/
if (exceptionLocal != null) {
if (declare.contains(exceptionLocal))
declare.remove(exceptionLocal);
else {
LocalInfo dummyLocal = new LocalInfo();
Expression store = new StoreInstruction
(new LocalStoreOperator
(exceptionLocal.getType(), exceptionLocal)).addOperand
(new LocalLoadOperator(dummyLocal.getType(),
null, dummyLocal));
InstructionBlock ib = new InstructionBlock(store);
ib.setFlowBlock(flowBlock);
ib.appendBlock(catchBlock);
catchBlock = ib;
exceptionLocal = dummyLocal;
String localName = dummyLocal.guessName();
Iterator doneIter = done.iterator();
while (doneIter.hasNext()) {
Declarable previous = (Declarable) doneIter.next();
if (localName.equals(previous.getName())) {
/* A name conflict happened. */
dummyLocal.makeNameUnique();
break;
}
}
}
}
}
public void dumpInstruction(net.sf.jode.decompiler.TabbedPrintWriter writer)
throws java.io.IOException {
writer.closeBraceContinue();
writer.print("catch (");
writer.printType(exceptionType);
writer.print(" " + (exceptionLocal != null
? exceptionLocal.getName() : "PUSH") + ")");
writer.openBrace();
writer.tab();
catchBlock.dumpSource(writer);
writer.untab();
}
/**
* Determines if there is a sub block, that flows through to the end
* of this block. If this returns true, you know that jump is null.
* @return true, if the jump may be safely changed.
*/
public boolean jumpMayBeChanged() {
return (catchBlock.jump != null || catchBlock.jumpMayBeChanged());
}
/**
* Check if this is an local store instruction to a not yet declared
* variable. In that case mark this as declaration and return the
* variable.
*/
public boolean combineLocal() {
StructuredBlock firstInstr = (catchBlock instanceof SequentialBlock)
? catchBlock.getSubBlocks()[0] : catchBlock;
if (firstInstr instanceof SpecialBlock
&& ((SpecialBlock) firstInstr).type == SpecialBlock.POP
&& ((SpecialBlock) firstInstr).count == 1) {
/* The exception is ignored. Create a dummy local for it */
exceptionLocal = new LocalInfo();
exceptionLocal.setType(exceptionType);
firstInstr.removeBlock();
return true;
} else if (firstInstr instanceof InstructionBlock) {
Expression instr =
((InstructionBlock) firstInstr).getInstruction();
if (instr instanceof StoreInstruction) {
StoreInstruction store = (StoreInstruction) instr;
if (store.getOperatorIndex() == Operator.OPASSIGN_OP
&& store.getSubExpressions()[1] instanceof NopOperator
&& store.getLValue() instanceof LocalStoreOperator) {
/* The exception is stored in a local variable */
exceptionLocal = ((LocalStoreOperator) store.getLValue())
.getLocalInfo();
exceptionLocal.setType(exceptionType);
firstInstr.removeBlock();
return true;
}
}
}
return false;
}
}