First new Flow version

git-svn-id: https://svn.code.sf.net/p/jode/code/trunk@24 379699f6-c40d-0410-875b-85095c16579e
stable
jochen 26 years ago
parent 80463e085e
commit ceaf716503
  1. 234
      jode/jode/bytecode/Opcodes.java
  2. 98
      jode/jode/decompiler/CodeAnalyzer.java
  3. 34
      jode/jode/decompiler/LocalInfo.java
  4. 220
      jode/jode/decompiler/LocalVariableAnalyzer.java
  5. 19
      jode/jode/expr/IIncOperator.java
  6. 21
      jode/jode/expr/LocalLoadOperator.java
  7. 19
      jode/jode/expr/LocalStoreOperator.java
  8. 4
      jode/jode/expr/LocalVarOperator.java
  9. 71
      jode/jode/flow/BreakBlock.java
  10. 74
      jode/jode/flow/BreakableBlock.java
  11. 113
      jode/jode/flow/ConditionalBlock.java
  12. 72
      jode/jode/flow/ContinueBlock.java
  13. 75
      jode/jode/flow/CreateExpression.java
  14. 19
      jode/jode/flow/EmptyBlock.java
  15. 7
      jode/jode/flow/FinallyBlock.java
  16. 678
      jode/jode/flow/FlowBlock.java
  17. 37
      jode/jode/flow/IfThenElseBlock.java
  18. 45
      jode/jode/flow/InstructionBlock.java
  19. 34
      jode/jode/flow/InstructionContainer.java
  20. 26
      jode/jode/flow/Jump.java
  21. 156
      jode/jode/flow/LoopBlock.java
  22. 10
      jode/jode/flow/RawTryCatchBlock.java
  23. 85
      jode/jode/flow/RemoveEmpty.java
  24. 42
      jode/jode/flow/ReturnBlock.java
  25. 28
      jode/jode/flow/SequentialBlock.java
  26. 170
      jode/jode/flow/StructuredBlock.java
  27. 72
      jode/jode/flow/SwitchBlock.java
  28. 42
      jode/jode/flow/ThrowBlock.java
  29. 24
      jode/jode/flow/Transformation.java
  30. 13
      jode/jode/flow/VariableSet.java

@ -18,14 +18,15 @@
*/
package jode;
import jode.flow.*;
import java.io.*;
import sun.tools.java.*;
/**
* This is an abstract class which creates InstructionHeader for the
* opcodes in an byte stream.
* This is an abstract class which creates flow blocks for the
* opcodes in a byte stream.
*/
public abstract class Opcodes implements RuntimeConstants{
public abstract class Opcodes implements RuntimeConstants {
public final static Type ALL_INT_TYPE = MyType.tUInt;
public final static Type INT_TYPE = Type.tInt;
@ -47,62 +48,97 @@ public abstract class Opcodes implements RuntimeConstants{
};
public static FlowBlock createNormal(int addr, int length,
Instruction instr)
{
return new FlowBlock(addr, length,
new InstructionBlock(instr,
new Jump(addr+length)));
}
public static FlowBlock createGoto(int addr, int length,
int destAddr)
{
return new FlowBlock(addr, length, new EmptyBlock(new Jump(destAddr)));
}
public static FlowBlock createIfGoto(int addr, int length,
int destAddr, Instruction instr)
{
ConditionalBlock ifBlock =
new ConditionalBlock(instr,
new Jump(destAddr),
new Jump(addr+length));
return new FlowBlock(addr, length, ifBlock);
}
public static FlowBlock createSwitch(int addr, int length,
int[] cases, int[] dests)
{
return new FlowBlock(addr, length, new SwitchBlock(cases, dests));
}
public static FlowBlock createBlock(int addr, int length,
StructuredBlock block)
{
return new FlowBlock(addr, length, block);
}
/**
* Read an opcode out of a data input stream containing the bytecode.
* @param addr The current address.
* @param stream The stream containing the java byte code.
* @param ca The Code Analyzer
* (where further information can be get from).
* @return The InstructionHeader representing this opcode
* @return The FlowBlock representing this opcode
* or null if the stream is empty.
* @exception IOException if an read error occured.
* @exception ClassFormatError if an invalid opcode is detected.
*/
public static
InstructionHeader readOpcode(int addr, DataInputStream stream,
CodeAnalyzer ca)
throws IOException, ClassFormatError
public static FlowBlock readOpcode(int addr, DataInputStream stream,
CodeAnalyzer ca)
throws IOException, ClassFormatError
{
try {
int opcode = stream.readUnsignedByte();
switch (opcode) {
case opc_nop:
return InstructionHeader.createNormal(addr, 1, new NopOperator());
return createNormal(addr, 1, new NopOperator());
case opc_aconst_null:
return InstructionHeader.createNormal
return createNormal
(addr, 1, new ConstOperator(OBJECT_TYPE, "null"));
case opc_iconst_m1:
case opc_iconst_0: case opc_iconst_1: case opc_iconst_2:
case opc_iconst_3: case opc_iconst_4: case opc_iconst_5:
return InstructionHeader.createNormal
return createNormal
(addr, 1, new ConstOperator
(ALL_INT_TYPE, Integer.toString(opcode - opc_iconst_0)));
case opc_lconst_0: case opc_lconst_1:
return InstructionHeader.createNormal
return createNormal
(addr, 1, new ConstOperator
(LONG_TYPE,
Integer.toString(opcode - opc_lconst_0) + "L"));
case opc_fconst_0: case opc_fconst_1: case opc_fconst_2:
return InstructionHeader.createNormal
return createNormal
(addr, 1, new ConstOperator
(FLOAT_TYPE,
Integer.toString(opcode - opc_fconst_0) + ".0F"));
case opc_dconst_0: case opc_dconst_1:
return InstructionHeader.createNormal
return createNormal
(addr, 1, new ConstOperator
(DOUBLE_TYPE,
Integer.toString(opcode - opc_dconst_0) + ".0"));
case opc_bipush:
return InstructionHeader.createNormal
return createNormal
(addr, 2, new ConstOperator
(ALL_INT_TYPE, Integer.toString(stream.readByte())));
case opc_sipush:
return InstructionHeader.createNormal
return createNormal
(addr, 3, new ConstOperator
(ALL_INT_TYPE, Integer.toString(stream.readShort())));
case opc_ldc: {
int index = stream.readUnsignedByte();
return InstructionHeader.createNormal
return createNormal
(addr, 2, new ConstOperator
(ca.env.getConstantType(index),
ca.env.getConstant(index).toString()));
@ -110,38 +146,38 @@ public abstract class Opcodes implements RuntimeConstants{
case opc_ldc_w:
case opc_ldc2_w: {
int index = stream.readUnsignedShort();
return InstructionHeader.createNormal
return createNormal
(addr, 3, new ConstOperator
(ca.env.getConstantType(index),
ca.env.getConstant(index).toString()));
}
case opc_iload: case opc_lload:
case opc_fload: case opc_dload: case opc_aload:
return InstructionHeader.createNormal
return createNormal
(addr, 2, new LocalLoadOperator
(types[0][opcode-opc_iload],
stream.readUnsignedByte()));
new LocalInfo(stream.readUnsignedByte())));
case opc_iload_0: case opc_iload_1: case opc_iload_2: case opc_iload_3:
case opc_lload_0: case opc_lload_1: case opc_lload_2: case opc_lload_3:
case opc_fload_0: case opc_fload_1: case opc_fload_2: case opc_fload_3:
case opc_dload_0: case opc_dload_1: case opc_dload_2: case opc_dload_3:
case opc_aload_0: case opc_aload_1: case opc_aload_2: case opc_aload_3:
return InstructionHeader.createNormal
return createNormal
(addr, 1, new LocalLoadOperator
(types[0][(opcode-opc_iload_0)/4],
(opcode-opc_iload_0) & 3));
new LocalInfo((opcode-opc_iload_0) & 3)));
case opc_iaload: case opc_laload:
case opc_faload: case opc_daload: case opc_aaload:
case opc_baload: case opc_caload: case opc_saload:
return InstructionHeader.createNormal
return createNormal
(addr, 1, new ArrayLoadOperator
(types[1][opcode - opc_iaload]));
case opc_istore: case opc_lstore:
case opc_fstore: case opc_dstore: case opc_astore:
return InstructionHeader.createNormal
return createNormal
(addr, 2, new LocalStoreOperator
(types[0][opcode-opc_istore],
stream.readUnsignedByte(),
new LocalInfo(stream.readUnsignedByte()),
Operator.ASSIGN_OP));
case opc_istore_0: case opc_istore_1:
case opc_istore_2: case opc_istore_3:
@ -153,51 +189,51 @@ public abstract class Opcodes implements RuntimeConstants{
case opc_dstore_2: case opc_dstore_3:
case opc_astore_0: case opc_astore_1:
case opc_astore_2: case opc_astore_3:
return InstructionHeader.createNormal
return createNormal
(addr, 1, new LocalStoreOperator
(types[0][(opcode-opc_istore_0)/4],
(opcode-opc_istore_0) & 3,
new LocalInfo((opcode-opc_istore_0) & 3),
Operator.ASSIGN_OP));
case opc_iastore: case opc_lastore:
case opc_fastore: case opc_dastore: case opc_aastore:
case opc_bastore: case opc_castore: case opc_sastore:
return InstructionHeader.createNormal
return createNormal
(addr, 1, new ArrayStoreOperator
(types[1][opcode - opc_iastore]));
case opc_pop: case opc_pop2:
return InstructionHeader.createNormal
return createNormal
(addr, 1, new PopOperator(opcode - opc_pop + 1));
case opc_dup: case opc_dup_x1: case opc_dup_x2:
case opc_dup2: case opc_dup2_x1: case opc_dup2_x2:
return InstructionHeader.createNormal
return createNormal
(addr, 1, new DupOperator
((opcode - opc_dup)%3, (opcode - opc_dup)/3+1));
case opc_swap:
return InstructionHeader.createNormal(addr, 1, new SwapOperator());
return createNormal(addr, 1, new SwapOperator());
case opc_iadd: case opc_ladd: case opc_fadd: case opc_dadd:
case opc_isub: case opc_lsub: case opc_fsub: case opc_dsub:
case opc_imul: case opc_lmul: case opc_fmul: case opc_dmul:
case opc_idiv: case opc_ldiv: case opc_fdiv: case opc_ddiv:
case opc_irem: case opc_lrem: case opc_frem: case opc_drem:
return InstructionHeader.createNormal
return createNormal
(addr, 1, new BinaryOperator
(types[0][(opcode - opc_iadd)%4],
(opcode - opc_iadd)/4+Operator.ADD_OP));
case opc_ineg: case opc_lneg: case opc_fneg: case opc_dneg:
return InstructionHeader.createNormal
return createNormal
(addr, 1, new UnaryOperator
(types[0][opcode - opc_ineg], Operator.NEG_OP));
case opc_ishl: case opc_lshl:
case opc_ishr: case opc_lshr:
case opc_iushr: case opc_lushr:
return InstructionHeader.createNormal
return createNormal
(addr, 1, new ShiftOperator
(types[0][(opcode - opc_ishl)%2],
(opcode - opc_ishl)/2 + Operator.SHIFT_OP));
case opc_iand: case opc_land:
case opc_ior : case opc_lor :
case opc_ixor: case opc_lxor:
return InstructionHeader.createNormal
return createNormal
(addr, 1, new BinaryOperator
(types[0][(opcode - opc_iand)%2],
(opcode - opc_iand)/2 + Operator.AND_OP));
@ -209,9 +245,10 @@ public abstract class Opcodes implements RuntimeConstants{
value = -value;
operation = Operator.NEG_OP;
}
return InstructionHeader.createNormal
LocalInfo li = new LocalInfo(local);
return createNormal
(addr, 3, new IIncOperator
(local, Integer.toString(value),
(li, Integer.toString(value),
operation + Operator.OPASSIGN_OP));
}
case opc_i2l: case opc_i2f: case opc_i2d:
@ -222,48 +259,48 @@ public abstract class Opcodes implements RuntimeConstants{
int to = (opcode-opc_i2l)%3;
if (to >= from)
to++;
return InstructionHeader.createNormal
return createNormal
(addr, 1, new ConvertOperator(types[0][from],
types[0][to]));
}
case opc_i2b: case opc_i2c: case opc_i2s:
return InstructionHeader.createNormal
return createNormal
(addr, 1, new ConvertOperator
(ALL_INT_TYPE, types[1][(opcode-opc_i2b)+5]));
case opc_lcmp:
case opc_fcmpl: case opc_fcmpg:
case opc_dcmpl: case opc_dcmpg:
return InstructionHeader.createNormal
return createNormal
(addr, 1, new CompareToIntOperator
(types[0][(opcode-opc_lcmp+3)/2], (opcode-opc_lcmp+3)%2));
case opc_ifeq: case opc_ifne:
case opc_iflt: case opc_ifge: case opc_ifgt: case opc_ifle:
return InstructionHeader.createIfGoto
return createIfGoto
(addr, 3, addr+stream.readShort(),
new CompareUnaryOperator
(ALL_INT_TYPE, opcode - opc_ifeq+Operator.COMPARE_OP));
case opc_if_icmpeq: case opc_if_icmpne: case opc_if_icmplt:
case opc_if_icmpge: case opc_if_icmpgt: case opc_if_icmple:
return InstructionHeader.createIfGoto
return createIfGoto
(addr, 3, addr+stream.readShort(),
new CompareBinaryOperator
(ALL_INT_TYPE, opcode - opc_if_icmpeq+Operator.COMPARE_OP));
case opc_if_acmpeq: case opc_if_acmpne:
return InstructionHeader.createIfGoto
return createIfGoto
(addr, 3, addr+stream.readShort(),
new CompareBinaryOperator
(OBJECT_TYPE, opcode - opc_if_acmpeq+Operator.COMPARE_OP));
case opc_goto:
return InstructionHeader.createGoto
return createGoto
(addr, 3, addr+stream.readShort());
case opc_jsr:
return InstructionHeader.createGoto //XXX
(addr, 3, addr+stream.readShort());
case opc_ret:
return InstructionHeader.createReturn //XXX
(addr, 2,
new LocalLoadOperator
(OBJECT_TYPE, stream.readUnsignedByte()));
// case opc_jsr:
// return createGoto //XXX
// (addr, 3, addr+stream.readShort());
// case opc_ret:
// return createReturn //XXX
// (addr, 2,
// new LocalLoadOperator
// (OBJECT_TYPE, new LocalInfo(stream.readUnsignedByte())));
case opc_tableswitch: {
int length = 3-(addr % 4);
stream.skip(length);
@ -278,8 +315,8 @@ public abstract class Opcodes implements RuntimeConstants{
}
dests[cases.length] = def;
length += 13 + 4 * cases.length;
return InstructionHeader.createSwitch
(addr, length, new NopOperator(), cases, dests);
return createSwitch
(addr, length, cases, dests);
}
case opc_lookupswitch: {
int length = 3-(addr % 4);
@ -294,31 +331,31 @@ public abstract class Opcodes implements RuntimeConstants{
}
dests[npairs] = def;
length += 9 + 8 * npairs;
return InstructionHeader.createSwitch
(addr, length, new NopOperator(), cases, dests);
return createSwitch
(addr, length, cases, dests);
}
case opc_ireturn: case opc_lreturn:
case opc_freturn: case opc_dreturn: case opc_areturn: {
Type retType = MyType.intersection
(ca.getMethod().mdef.getType().getReturnType(),
types[0][opcode-opc_ireturn]);
return InstructionHeader.createReturn
(addr, 1, new ReturnOperator(retType));
return createBlock
(addr, 1, new ReturnBlock(new NopOperator(retType)));
}
case opc_return: {
return InstructionHeader.createReturn
(addr, 1, null);
}
case opc_return:
/* Address -1 is interpreted as end of method */
return createBlock
(addr, 1, new EmptyBlock(new Jump(-1)));
case opc_getstatic:
case opc_getfield:
return InstructionHeader.createNormal
return createNormal
(addr, 3, new GetFieldOperator
(ca, opcode == opc_getstatic,
(FieldDefinition)ca.env.getConstant
(stream.readUnsignedShort())));
case opc_putstatic:
case opc_putfield:
return InstructionHeader.createNormal
return createNormal
(addr, 3, new PutFieldOperator
(ca, opcode == opc_putstatic,
(FieldDefinition)ca.env.getConstant
@ -326,26 +363,26 @@ public abstract class Opcodes implements RuntimeConstants{
case opc_invokevirtual:
case opc_invokespecial:
case opc_invokestatic :
return InstructionHeader.createNormal
return createNormal
(addr, 3, new InvokeOperator
(ca,
opcode == opc_invokestatic, opcode == opc_invokespecial,
(FieldDefinition)ca.env.getConstant
(stream.readUnsignedShort())));
case opc_invokeinterface: {
InstructionHeader ih = InstructionHeader.createNormal
FlowBlock fb = createNormal
(addr, 5, new InvokeOperator
(ca, false, false,
(FieldDefinition)ca.env.getConstant
(stream.readUnsignedShort())));
int reserved = stream.readUnsignedShort();
return ih;
return fb;
}
case opc_new: {
ClassDeclaration cldec = (ClassDeclaration)
ca.env.getConstant(stream.readUnsignedShort());
Type type = MyType.tClassOrArray(cldec.getName());
return InstructionHeader.createNormal
return createNormal
(addr, 3, new NewOperator(type, ca.env.getTypeString(type)));
}
case opc_newarray: {
@ -362,7 +399,7 @@ public abstract class Opcodes implements RuntimeConstants{
default:
throw new ClassFormatError("Invalid newarray operand");
}
return InstructionHeader.createNormal
return createNormal
(addr, 2,
new NewArrayOperator(MyType.tArray(type),
type.toString(), 1));
@ -372,21 +409,22 @@ public abstract class Opcodes implements RuntimeConstants{
(stream.readUnsignedShort());
Identifier ident = cldec.getName();
Type type = MyType.tClassOrArray(cldec.getName());
return InstructionHeader.createNormal
return createNormal
(addr, 3, new NewArrayOperator
(MyType.tArray(type), ca.env.getTypeString(type),1));
}
case opc_arraylength:
return InstructionHeader.createNormal
return createNormal
(addr, 1, new ArrayLengthOperator());
case opc_athrow:
return InstructionHeader.createReturn
(addr, 1, new ThrowOperator());
return createBlock
(addr, 1,
new ThrowBlock(new NopOperator(MyType.tUObject)));
case opc_checkcast: {
ClassDeclaration cldec = (ClassDeclaration) ca.env.getConstant
(stream.readUnsignedShort());
Type type = MyType.tClassOrArray(cldec.getName());
return InstructionHeader.createNormal
return createNormal
(addr, 3, new CheckCastOperator
(type, ca.env.getTypeString(type)));
}
@ -394,31 +432,33 @@ public abstract class Opcodes implements RuntimeConstants{
ClassDeclaration cldec = (ClassDeclaration) ca.env.getConstant
(stream.readUnsignedShort());
Type type = MyType.tClassOrArray(cldec.getName());
return InstructionHeader.createNormal
return createNormal
(addr, 3,
new InstanceOfOperator(type, ca.env.getTypeString(type)));
}
case opc_monitorenter:
return InstructionHeader.createNormal(addr, 1,
return createNormal(addr, 1,
new MonitorEnterOperator());
case opc_monitorexit:
return InstructionHeader.createNormal(addr, 1,
return createNormal(addr, 1,
new MonitorExitOperator());
case opc_wide: {
switch (opcode=stream.readUnsignedByte()) {
case opc_iload: case opc_lload:
case opc_fload: case opc_dload: case opc_aload:
return InstructionHeader.createNormal
return createNormal
(addr, 4,
new LocalLoadOperator(types[0][opcode-opc_iload],
stream.readUnsignedShort()));
new LocalInfo
(stream.readUnsignedShort())));
case opc_istore: case opc_lstore:
case opc_fstore: case opc_dstore: case opc_astore:
return InstructionHeader.createNormal
return createNormal
(addr, 4,
new LocalStoreOperator(types[0][opcode-opc_istore],
stream.readUnsignedShort(),
Operator.ASSIGN_OP));
new LocalStoreOperator
(types[0][opcode-opc_istore],
new LocalInfo(stream.readUnsignedShort()),
Operator.ASSIGN_OP));
case opc_iinc: {
int local = stream.readUnsignedShort();
int value = stream.readShort();
@ -427,16 +467,18 @@ public abstract class Opcodes implements RuntimeConstants{
value = -value;
operation = Operator.NEG_OP;
}
return InstructionHeader.createNormal
LocalInfo li = new LocalInfo(local);
return createNormal
(addr, 6, new IIncOperator
(local, Integer.toString(value),
(li, Integer.toString(value),
operation + Operator.OPASSIGN_OP));
}
case opc_ret:
return new RetInstructionHeader
(addr, 4,
new LocalLoadOperator
(INT_TYPE, stream.readUnsignedShort()));
// case opc_ret:
// return new RetInstructionHeader
// (addr, 4,
// new LocalLoadOperator
// (INT_TYPE,
// new LocalInfo(stream.readUnsignedShort())));
default:
throw new ClassFormatError("Invalid wide opcode "+opcode);
}
@ -449,22 +491,22 @@ public abstract class Opcodes implements RuntimeConstants{
Type baseType = type;
for (int i=0; i<dimension; i++)
baseType = baseType.getElementType();
return InstructionHeader.createNormal
return createNormal
(addr, 4,
new NewArrayOperator
(type, ca.env.getTypeString(baseType), dimension));
}
case opc_ifnull: case opc_ifnonnull:
return InstructionHeader.createIfGoto
return createIfGoto
(addr, 3, addr+stream.readShort(),
new CompareUnaryOperator
(OBJECT_TYPE, opcode - opc_ifnull+Operator.COMPARE_OP));
case opc_goto_w:
return InstructionHeader.createGoto
return createGoto
(addr, 5, addr + stream.readInt());
case opc_jsr_w:
return InstructionHeader.createGoto
(addr, 5, addr+stream.readInt()); // XXX
// case opc_jsr_w:
// return createGoto
// (addr, 5, addr+stream.readInt()); // XXX
default:
throw new ClassFormatError("Invalid opcode "+opcode);
}

@ -19,15 +19,19 @@
package jode;
import sun.tools.java.*;
import java.util.Stack;
import java.io.*;
import jode.flow.FlowBlock;
public class CodeAnalyzer implements Analyzer, Constants {
BinaryCode bincode;
MethodInstructionHeader methodHeader;
FlowBlock methodHeader;
MethodAnalyzer method;
public JodeEnvironment env;
LocalVariableTable lvt;
/**
* Get the method.
@ -39,20 +43,34 @@ public class CodeAnalyzer implements Analyzer, Constants {
throws ClassFormatError
{
byte[] code = bincode.getCode();
InstructionHeader[] instr = new InstructionHeader[code.length];
FlowBlock[] instr = new FlowBlock[code.length];
int returnCount;
try {
DataInputStream stream =
new DataInputStream(new ByteArrayInputStream(code));
for (int addr = 0; addr < code.length; ) {
instr[addr] = Opcodes.readOpcode(addr, stream, this);
addr = instr[addr].getNextAddr();
}
} catch (IOException ex) {
throw new ClassFormatError(ex.toString());
}
BinaryExceptionHandler[] handlers = bincode.getExceptionHandlers();
methodHeader = new MethodInstructionHeader(env, instr, handlers);
for (int addr=0; addr<instr.length; ) {
instr[addr].resolveJumps(instr);
//XXX
// if (instr[addr].getBlock() instanceof ReturnBlock) {
// ReturnBlock block = (ReturnBlock) instr[addr].getBlock();
// if (block.getInstruction() == null) {
// EmptyBlock empty = new EmptyBlock(dummyReturn);
// empty.replace(block);
// }
// }
addr = instr[addr].getNextAddr();
}
methodHeader = instr[0];
/* XXX do something with handlers */
}
/*
@ -77,16 +95,16 @@ public class CodeAnalyzer implements Analyzer, Constants {
readCode();
}
static Transformation[] exprTrafos = {
new RemoveNop(),
new CombineCatchLocal(),
new CreateExpression(),
new CreatePostIncExpression(),
new CreateAssignExpression(),
new CreateNewConstructor(),
new CombineIfGotoExpressions(),
new CreateIfThenElseOperator(),
new CreateConstantArray()
static jode.flow.Transformation[] exprTrafos = {
new jode.flow.RemoveEmpty(),
// new CombineCatchLocal(),
new jode.flow.CreateExpression(),
// new CreatePostIncExpression(),
// new CreateAssignExpression(),
// new CreateNewConstructor(),
// new CombineIfGotoExpressions(),
// new CreateIfThenElseOperator(),
// new CreateConstantArray()
};
static Transformation[] simplifyTrafos = { new SimplifyExpression() };
@ -101,9 +119,57 @@ public class CodeAnalyzer implements Analyzer, Constants {
public void analyze()
{
methodHeader.doTransformations(exprTrafos);
methodHeader.doTransformations(simplifyTrafos);
methodHeader.doTransformations(blockTrafos);
/* XXX optimize */
Stack todo = new Stack();
FlowBlock flow = methodHeader;
while (true) {
/* First do some non flow transformations. */
int i=0;
while (i < exprTrafos.length) {
if (exprTrafos[i].transform(flow))
i = 0;
else
i++;
}
if (flow.doT2()) {
/* T2 transformation succeeded. This may
* make another T1 analysis in the previous
* block possible.
*/
if (!todo.isEmpty())
flow = (FlowBlock) todo.pop();
}
FlowBlock succ = flow.getSuccessor();
if (succ != null) {
if (!flow.doT1(succ)) {
/* T1 transformation failed, now succeed with
* successor and put flow on the stack.
*/
if (todo.contains(succ)) {
/* This is a sign that the flow graph is not
* reducible. We give up immediately!
*/
break;
}
todo.push(flow);
flow = succ;
}
} else {
/* Block has no successor.
*
* If everything is okay the stack should be empty now,
* and the program is transformed correctly.
*
* Otherwise flow transformation didn't succeeded.
*/
break;
}
}
}
public String getTypeString(Type type) {

@ -63,9 +63,13 @@ public class LocalInfo {
* @param li the local info that we want to shadow.
*/
public void combineWith(LocalInfo li) {
if (shadow != null)
shadow.combineWith(li);
li = li.getLocalInfo();
if (shadow != null) {
while (shadow.shadow != null) {
shadow = shadow.shadow;
}
shadow.combineWith(li);
}
if (this != li) {
shadow = li;
li.setType(type);
@ -77,8 +81,12 @@ public class LocalInfo {
* current object if this is a shadow local info.
*/
public LocalInfo getLocalInfo() {
if (shadow != null)
if (shadow != null) {
while (shadow.shadow != null) {
shadow = shadow.shadow;
}
return shadow.getLocalInfo();
}
return this;
}
@ -86,8 +94,12 @@ public class LocalInfo {
* Get the name of this local.
*/
public Identifier getName() {
if (shadow != null)
if (shadow != null) {
while (shadow.shadow != null) {
shadow = shadow.shadow;
}
return shadow.getName();
}
if (name == null)
name = Identifier.lookup("local_"+slot+"__"+serialnr++);
return name;
@ -96,7 +108,7 @@ public class LocalInfo {
/**
* Get the slot of this local.
*/
public Identifier getSlot() {
public int getSlot() {
/* The slot does not change when shadowing */
return slot;
}
@ -115,8 +127,12 @@ public class LocalInfo {
* Get the type of this local.
*/
public Type getType() {
if (shadow != null)
if (shadow != null) {
while (shadow.shadow != null) {
shadow = shadow.shadow;
}
return shadow.getType();
}
return type;
}
@ -127,8 +143,12 @@ public class LocalInfo {
* @return The new type of the local.
*/
public Type setType(Type newType) {
if (shadow != null)
if (shadow != null) {
while (shadow.shadow != null) {
shadow = shadow.shadow;
}
return shadow.setType(newType);
}
this.type = MyType.intersection(this.type, newType);
if (this.type == MyType.tError)
System.err.println("Type error in "+getName());

@ -79,131 +79,131 @@ public class LocalVariableAnalyzer {
return li2.getLocalInfo();
}
public void analyze(MethodInstructionHeader mih) {
{
Type[] paramTypes = mdef.getType().getArgumentTypes();
int length = (mdef.isStatic() ? 0 : 1) + paramTypes.length;
argLocals = new LocalInfo[length];
int offset = 0;
if (!mdef.isStatic()) {
argLocals[0] = new LocalInfo(0);
argLocals[0].setType(mdef.getClassDefinition().getType());
offset++;
}
for (int i=0; i< paramTypes.length; i++) {
argLocals[offset+i] = new LocalInfo(i+offset);
argLocals[offset+i].setType(paramTypes[i]);
}
}
Hashtable done = new Hashtable();
Stack instrStack = new Stack();
Stack readsStack = new Stack();
LocalInfo[] reads = new LocalInfo[maxlocals];
Enumeration predec = mih.getReturns().elements();
while (predec.hasMoreElements()) {
instrStack.push(predec.nextElement());
readsStack.push(reads);
}
while (!instrStack.empty()) {
InstructionHeader instr =
(InstructionHeader) instrStack.pop();
LocalInfo[] prevReads =
(LocalInfo[]) done.get(instr);
reads = (LocalInfo[]) readsStack.pop();
// System.err.println("");
// System.err.print("Addr: "+instr.getAddress()+ " [");
// for (int i=0; i< maxlocals; i++) {
// if (reads[i] != null)
// System.err.print(", "+reads[i].getName().toString());
// public void analyze(MethodInstructionHeader mih) {
// {
// Type[] paramTypes = mdef.getType().getArgumentTypes();
// int length = (mdef.isStatic() ? 0 : 1) + paramTypes.length;
// argLocals = new LocalInfo[length];
// int offset = 0;
// if (!mdef.isStatic()) {
// argLocals[0] = new LocalInfo(0);
// argLocals[0].setType(mdef.getClassDefinition().getType());
// offset++;
// }
// System.err.print("] ");
if (prevReads != null) {
boolean changed = false;
for (int i=0; i<maxlocals; i++) {
if (reads[i] != null) {
reads[i] = reads[i].getLocalInfo();
if (prevReads[i] == null) {
changed = true;
} else if (prevReads[i].getLocalInfo() != reads[i]) {
prevReads[i].combineWith(reads[i]);
changed = true;
}
}
}
if (!changed)
continue;
}
// for (int i=0; i< paramTypes.length; i++) {
// argLocals[offset+i] = new LocalInfo(i+offset);
// argLocals[offset+i].setType(paramTypes[i]);
// }
// }
// Hashtable done = new Hashtable();
// Stack instrStack = new Stack();
// Stack readsStack = new Stack();
// LocalInfo[] reads = new LocalInfo[maxlocals];
// Enumeration predec = mih.getReturns().elements();
// while (predec.hasMoreElements()) {
// instrStack.push(predec.nextElement());
// readsStack.push(reads);
// }
// while (!instrStack.empty()) {
// InstructionHeader instr =
// (InstructionHeader) instrStack.pop();
// LocalInfo[] prevReads =
// (LocalInfo[]) done.get(instr);
// reads = (LocalInfo[]) readsStack.pop();
// // System.err.println("");
// // System.err.print("Addr: "+instr.getAddress()+ " [");
// // for (int i=0; i< maxlocals; i++) {
// // if (reads[i] != null)
// // System.err.print(", "+reads[i].getName().toString());
// // }
// // System.err.print("] ");
// if (prevReads != null) {
// boolean changed = false;
// for (int i=0; i<maxlocals; i++) {
// if (reads[i] != null) {
// reads[i] = reads[i].getLocalInfo();
// if (prevReads[i] == null) {
// changed = true;
// } else if (prevReads[i].getLocalInfo() != reads[i]) {
// prevReads[i].combineWith(reads[i]);
// changed = true;
// }
// }
// }
// if (!changed)
// continue;
// }
if (instr instanceof MethodInstructionHeader) {
/* This is the first instruction
*/
for (int i=0; i < argLocals.length; i++) {
if (reads[i] != null)
argLocals[i].combineWith(reads[i]);
}
} else if (instr.getInstruction() instanceof LocalVarOperator) {
if (Decompiler.isVerbose)
System.err.print(".");
LocalVarOperator op =
(LocalVarOperator)instr.getInstruction();
int slot = op.getSlot();
// if (instr instanceof MethodInstructionHeader) {
// /* This is the first instruction
// */
// for (int i=0; i < argLocals.length; i++) {
// if (reads[i] != null)
// argLocals[i].combineWith(reads[i]);
// }
// } else if (instr.getInstruction() instanceof LocalVarOperator) {
// if (Decompiler.isVerbose)
// System.err.print(".");
// LocalVarOperator op =
// (LocalVarOperator)instr.getInstruction();
// int slot = op.getSlot();
LocalInfo li = combine(slot, op.getLocalInfo(),
reads[slot]);
// LocalInfo li = combine(slot, op.getLocalInfo(),
// reads[slot]);
LocalInfo[] newReads = new LocalInfo[maxlocals];
System.arraycopy(reads, 0, newReads, 0, maxlocals);
// LocalInfo[] newReads = new LocalInfo[maxlocals];
// System.arraycopy(reads, 0, newReads, 0, maxlocals);
op.setLocalInfo(li);
if (op.isRead())
newReads[slot] = li;
else
newReads[slot] = null;
// op.setLocalInfo(li);
// if (op.isRead())
// newReads[slot] = li;
// else
// newReads[slot] = null;
reads = newReads;
done.put(instr, reads);
}
// reads = newReads;
// done.put(instr, reads);
// }
predec = instr.getPredecessors().elements();
while (predec.hasMoreElements()) {
instrStack.push(predec.nextElement());
readsStack.push(reads);
}
}
if (!mdef.isStatic())
argLocals[0].setName(Constants.idThis);
}
// predec = instr.getPredecessors().elements();
// while (predec.hasMoreElements()) {
// instrStack.push(predec.nextElement());
// readsStack.push(reads);
// }
// }
// if (!mdef.isStatic())
// argLocals[0].setName(Constants.idThis);
// }
public void createLocalInfo(CodeAnalyzer code) {
// System.err.println("createLocalInfo");
MethodInstructionHeader mih = code.methodHeader;
if (lvt == null)
analyze(mih);
else {
// MethodInstructionHeader mih = code.methodHeader;
// if (lvt == null)
// analyze(mih);
// else {
int length = (mdef.isStatic() ? 0 : 1) +
mdef.getType().getArgumentTypes().length;
argLocals = new LocalInfo[length];
for (int i=0; i < length; i++)
argLocals[i] = lvt.getLocal(i).getInfo(-1);
for (InstructionHeader ih = mih.getFirst();
ih != null; ih = ih.getNextInstruction()) {
if (ih.getInstruction() instanceof LocalVarOperator) {
LocalVarOperator op =
(LocalVarOperator)ih.getInstruction();
int slot = op.getSlot();
LocalInfo li =
lvt.getLocal(slot).getInfo(ih.getAddress());
op.setLocalInfo(li);
}
}
}
// for (InstructionHeader ih = mih.getFirst();
// ih != null; ih = ih.getNextInstruction()) {
// if (ih.getInstruction() instanceof LocalVarOperator) {
// LocalVarOperator op =
// (LocalVarOperator)ih.getInstruction();
// int slot = op.getSlot();
// LocalInfo li =
// lvt.getLocal(slot).getInfo(ih.getAddress());
// op.setLocalInfo(li);
// }
// }
// }
}
public LocalInfo getLocal(int i) {

@ -22,13 +22,12 @@ import sun.tools.java.Type;
public class IIncOperator extends NoArgOperator
implements LocalVarOperator {
int slot;
String value;
LocalInfo local;
public IIncOperator(int slot, String value, int operator) {
public IIncOperator(LocalInfo local, String value, int operator) {
super(MyType.tVoid, operator);
this.slot = slot;
this.local = local;
this.value = value;
}
@ -44,18 +43,18 @@ implements LocalVarOperator {
return true;
}
public void setLocalInfo(LocalInfo local) {
local.setType(MyType.tUIndex);
this.local = local;
}
// public void setLocalInfo(LocalInfo local) {
// local.setType(MyType.tUIndex);
// this.local = local;
// }
public LocalInfo getLocalInfo() {
return local;
}
public int getSlot() {
return slot;
}
// public int getSlot() {
// return slot;
// }
public int getPriority() {
return 100;

@ -22,12 +22,11 @@ import sun.tools.java.Type;
public class LocalLoadOperator extends ConstOperator
implements LocalVarOperator {
int slot;
LocalInfo local;
public LocalLoadOperator(Type type, int slot) {
public LocalLoadOperator(Type type, LocalInfo local) {
super(type, "");
this.slot = slot;
this.local = local;
}
public boolean isRead() {
@ -38,10 +37,10 @@ implements LocalVarOperator {
return false;
}
public void setLocalInfo(LocalInfo local) {
local.setType(type);
this.local = local;
}
// public void setLocalInfo(LocalInfo local) {
// local.setType(type);
// this.local = local;
// }
public LocalInfo getLocalInfo() {
return local;
@ -57,9 +56,9 @@ implements LocalVarOperator {
return super.setType(local.setType(type));
}
public int getSlot() {
return slot;
}
// public int getSlot() {
// return slot;
// }
public String toString(String[] operands) {
return local.getName().toString();
@ -67,7 +66,7 @@ implements LocalVarOperator {
public boolean equals(Object o) {
return (o instanceof LocalLoadOperator &&
((LocalLoadOperator) o).slot == slot);
((LocalLoadOperator) o).local.getSlot() == local.getSlot());
}
}

@ -22,12 +22,11 @@ import sun.tools.java.Type;
public class LocalStoreOperator extends StoreInstruction
implements LocalVarOperator {
int slot;
LocalInfo local;
public LocalStoreOperator(Type lvalueType, int slot, int operator) {
public LocalStoreOperator(Type lvalueType, LocalInfo local, int operator) {
super(lvalueType, operator);
this.slot = slot;
this.local = local;
}
public boolean isRead() {
@ -38,10 +37,10 @@ implements LocalVarOperator {
return true;
}
public void setLocalInfo(LocalInfo local) {
local.setType(lvalueType);
this.local = local;
}
// public void setLocalInfo(LocalInfo local) {
// local.setType(lvalueType);
// this.local = local;
// }
public LocalInfo getLocalInfo() {
return local;
@ -58,9 +57,9 @@ implements LocalVarOperator {
(local.setType(MyType.tSuperType(type)));
}
public int getSlot() {
return slot;
}
// public int getSlot() {
// return slot;
// }
public boolean matches(Operator loadop) {
return loadop instanceof LocalLoadOperator &&

@ -22,9 +22,9 @@ package jode;
public interface LocalVarOperator {
public boolean isRead();
public boolean isWrite();
public int getSlot();
// public int getSlot();
public LocalInfo getLocalInfo();
public void setLocalInfo(LocalInfo li);
// public void setLocalInfo(LocalInfo li);
}

@ -0,0 +1,71 @@
/* BreakBlock (c) 1998 Jochen Hoenicke
*
* You may distribute under the terms of the GNU General Public License.
*
* IN NO EVENT SHALL JOCHEN HOENICKE BE LIABLE TO ANY PARTY FOR DIRECT,
* INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF
* THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF JOCHEN HOENICKE
* HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* JOCHEN HOENICKE SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
* PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS"
* BASIS, AND JOCHEN HOENICKE HAS NO OBLIGATION TO PROVIDE MAINTENANCE,
* SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*
* $Id$
*/
package jode.flow;
import jode.TabbedPrintWriter;
/**
*
*/
public class BreakBlock extends StructuredBlock {
StructuredBlock breaksBlock;
String label;
public BreakBlock(BreakableBlock breaksBlock, boolean needsLabel) {
this.breaksBlock = breaksBlock;
breaksBlock.mayChangeJump = false;
if (needsLabel)
label = breaksBlock.getLabel();
else
label = null;
}
public void checkConsistent() {
super.checkConsistent();
StructuredBlock sb = outer;
while (sb != breaksBlock) {
if (sb == null)
throw new RuntimeException("Inconsistency");
sb = sb.outer;
}
}
/**
* Returns the block where the control will normally flow to, when
* this block is finished.
*/
public StructuredBlock getNextBlock() {
return breaksBlock.getNextBlock();
}
/**
* Returns the flow block where the control will normally flow to,
* when this block is finished (not ignoring the jump after this
* block).
* @return null, if the control flows into a non empty structured
* block or if this is the outermost block.
*/
public FlowBlock getNextFlowBlock() {
return breaksBlock.getNextFlowBlock();
}
public void dumpInstruction(TabbedPrintWriter writer)
throws java.io.IOException
{
writer.println("break"+(label == null ? "" : " "+label) + ";");
}
}

@ -0,0 +1,74 @@
/* BreakableBlock (c) 1998 Jochen Hoenicke
*
* You may distribute under the terms of the GNU General Public License.
*
* IN NO EVENT SHALL JOCHEN HOENICKE BE LIABLE TO ANY PARTY FOR DIRECT,
* INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF
* THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF JOCHEN HOENICKE
* HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* JOCHEN HOENICKE SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
* PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS"
* BASIS, AND JOCHEN HOENICKE HAS NO OBLIGATION TO PROVIDE MAINTENANCE,
* SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*
* $Id$
*/
package jode.flow;
import jode.TabbedPrintWriter;
/**
* This is a structured block, that supports break.
*/
public abstract class BreakableBlock extends StructuredBlock {
boolean mayChangeJump = true;
/**
* Print the source code for this structured block. This handles
* everything that is unique for all structured blocks and calls
* dumpInstruction afterwards.
* @param writer The tabbed print writer, where we print to.
*/
public void dumpSource(TabbedPrintWriter writer)
throws java.io.IOException
{
if (label != null) {
writer.untab();
writer.println(label+":");
writer.tab();
}
super.dumpSource(writer);
}
/**
* The serial number for labels.
*/
static int serialno = 0;
/**
* The label of this instruction, or null if it needs no label.
*/
String label = null;
/**
* Returns the label of this block and creates a new label, if
* there wasn't a label previously.
*/
public String getLabel() {
if (label == null)
label = "label_"+(serialno++)+"_";
return label;
}
/**
* 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 mayChangeJump;
}
}

@ -0,0 +1,113 @@
/* ConditionalBlock (c) 1998 Jochen Hoenicke
*
* You may distribute under the terms of the GNU General Public License.
*
* IN NO EVENT SHALL JOCHEN HOENICKE BE LIABLE TO ANY PARTY FOR DIRECT,
* INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF
* THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF JOCHEN HOENICKE
* HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* JOCHEN HOENICKE SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
* PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS"
* BASIS, AND JOCHEN HOENICKE HAS NO OBLIGATION TO PROVIDE MAINTENANCE,
* SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*
* $Id$
*/
package jode.flow;
import jode.Instruction;
import jode.LocalVarOperator;
import jode.TabbedPrintWriter;
/**
* An ConditionalBlock is the structured block representing an if
* instruction. The else part may be null.
*/
public class ConditionalBlock extends StructuredBlock
implements InstructionContainer {
/**
* The condition. Must be of boolean type.
*/
Instruction cond;
StructuredBlock trueBlock;
/**
* Creates a new if then else block. The method setThenBlock must
* be called shortly after the creation.
*/
public ConditionalBlock(Instruction cond, Jump condJump, Jump elseJump) {
this.cond = cond;
if (cond instanceof LocalVarOperator) {
LocalVarOperator varOp = (LocalVarOperator) cond;
if (varOp.isRead()) {
in.addElement(varOp.getLocalInfo());
}
out.addElement(varOp.getLocalInfo());
}
this.jump = elseJump;
elseJump.prev = this;
trueBlock = new EmptyBlock(condJump);
trueBlock.outer = this;
}
public Instruction getInstruction() {
return cond;
}
/**
* Change the underlying instruction.
* @param instr the new underlying instruction.
*/
public void setInstruction(Instruction instr) {
this.cond = instr;
}
public Instruction getCondition(Jump forJump) {
/*XXX*/
return cond;
}
/* The implementation of getNext[Flow]Block is the standard
* implementation
*/
/**
* Returns all sub block of this structured block.
*/
public StructuredBlock[] getSubBlocks() {
StructuredBlock[] result = { trueBlock };
return result;
}
/**
* 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 (trueBlock == oldBlock)
trueBlock = newBlock;
else
return false;
return true;
}
/**
* Print the source code for this structured block. This may be
* called only once, because it remembers which local variables
* were declared.
*/
public void dumpInstruction(TabbedPrintWriter writer)
throws java.io.IOException
{
writer.println("IF ("+cond.toString()+")");
writer.tab();
trueBlock.dumpSource(writer);
writer.untab();
}
}

@ -0,0 +1,72 @@
/* ContinueBlock (c) 1998 Jochen Hoenicke
*
* You may distribute under the terms of the GNU General Public License.
*
* IN NO EVENT SHALL JOCHEN HOENICKE BE LIABLE TO ANY PARTY FOR DIRECT,
* INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF
* THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF JOCHEN HOENICKE
* HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* JOCHEN HOENICKE SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
* PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS"
* BASIS, AND JOCHEN HOENICKE HAS NO OBLIGATION TO PROVIDE MAINTENANCE,
* SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*
* $Id$
*/
package jode.flow;
import jode.TabbedPrintWriter;
/**
*
*/
public class ContinueBlock extends StructuredBlock {
StructuredBlock continuesBlock;
String continueLabel;
public ContinueBlock(LoopBlock continuesBlock, boolean needsLabel) {
this.continuesBlock = continuesBlock;
if (needsLabel)
continueLabel = continuesBlock.getLabel();
else
continueLabel = null;
}
public void checkConsistent() {
super.checkConsistent();
StructuredBlock sb = outer;
while (sb != continuesBlock) {
if (sb == null)
throw new RuntimeException("Inconsistency");
sb = sb.outer;
}
}
/**
* Returns the block where the control will normally flow to, when
* this block is finished (not ignoring the jump after this block).
*/
public StructuredBlock getNextBlock() {
/* This continues to continuesBlock. */
return continuesBlock;
}
/**
* Returns the flow block where the control will normally flow to,
* when this block is finished (not ignoring the jump after this
* block).
* @return null, if the control flows into a non empty structured
* block or if this is the outermost block.
*/
public FlowBlock getNextFlowBlock() {
return null;
}
public void dumpInstruction(TabbedPrintWriter writer)
throws java.io.IOException
{
writer.println("continue"+
(continueLabel == null ? "" : " "+continueLabel) + ";");
}
}

@ -17,39 +17,90 @@
* $Id$
*/
package jode;
package jode.flow;
import jode.Operator;
import jode.Expression;
/**
* This transformation creates expressions. It transforms
* <pre>
* Sequ[expr_1, Sequ[expr_2, ..., Sequ[expr_n, op] ...]]
* </pre>
* to
* <pre>
* expr(op, [ expr_1, ..., expr_n ])
* </pre>
*/
public class CreateExpression implements Transformation {
public StructuredBlock transform(StructuredBlock block) {
/**
* This does the transformation.
* @param FlowBlock the flow block to transform.
* @return true if flow block was simplified.
*/
public boolean transform(FlowBlock flow) {
Operator op;
Expression exprs[];
int params;
StructuredBlock block;
try {
jode.TabbedPrintWriter writer =
new jode.TabbedPrintWriter(System.err, " ");
writer.tab();
System.err.println("Transformation on: "+flow.getLabel());
flow.block.dumpSource(writer);
flow.checkConsistent();
System.err.println("; lastModified is: ");
flow.lastModified.dumpSource(writer);
} catch (java.io.IOException ex) {}
try {
op = (Operator) block.getInstruction();
SequentialBlock sequBlock;
block = flow.lastModified;
op = (Operator) ((InstructionContainer)block).getInstruction();
params = op.getOperandCount();
exprs = new Expression[params];
for (int i = params-1; i>=0; i--) {
block = block.getSimpleUniquePredecessor();
exprs[i] = (Expression) ih.getInstruction();
sequBlock = (SequentialBlock)block.outer;
if (i == params-1 &&
sequBlock.getSubBlocks()[1] != block)
return false;
block = sequBlock.getSubBlocks()[0];
if (block.jump != null)
return false;
exprs[i] =
(Expression) ((InstructionBlock)block).getInstruction();
if (exprs[i].isVoid()) {
if (i == params-1)
return null;
return false;
Expression e = exprs[i+1].tryToCombine(exprs[i]);
if (e == null)
return null;
return false;
i++;
SequentialBlock subExprBlock =
(SequentialBlock) sequBlock.getSubBlocks()[1];
subExprBlock.replace(sequBlock);
sequBlock = subExprBlock;
((InstructionContainer)subExprBlock.getSubBlocks()[0]).
setInstruction(e);
exprs[i] = e;
ih = ih.combine(2, e);
}
block = sequBlock;
}
} catch (NullPointerException ex) {
return null;
return false;
} catch (ClassCastException ex) {
return null;
return false;
}
if(Decompiler.isVerbose && params > 0)
if(jode.Decompiler.isVerbose && params > 0)
System.err.print("x");
return ih.combine(params+1, new Expression(op, exprs));
((InstructionContainer) flow.lastModified).setInstruction
(new Expression(op, exprs));
flow.lastModified.replace(block);
return true;
}
}

@ -18,27 +18,20 @@
*/
package jode.flow;
import jode.TabbedPrintWriter;
/**
* This is the structured block for an empty block.
*/
public class EmptyBlock extends StructuredBlock {
Instruction instr;
public EmptyBlock() {
}
SimpleInstruction(Instruction instr) {
in = new Vector();
out = new Vector();
this.instr = instr;
if (instr instanceof LocalVarOperator) {
LocalVarOperator varOp = (LocalVarOperator) instr;
if (varOp.isRead())
in.addElement(varOp.getLocalInfo());
else /* if (varOp.isWrite()) */
out.addElement(varOp.getLocalInfo());
}
public EmptyBlock(Jump jump) {
setJump(jump);
}
public void dumpSource(TabbedPrintWriter writer)
public void dumpInstruction(TabbedPrintWriter writer)
throws java.io.IOException
{
writer.println("/* empty */");

@ -17,6 +17,7 @@
*/
package jode.flow;
import jode.TabbedPrintWriter;
/**
* A FinallyBlock represents the instructions and try catch regions
@ -28,5 +29,9 @@ package jode.flow;
* region, so we have to take care of this.
*/
public FinallyBlock extends StructuredBlock {
public class FinallyBlock extends StructuredBlock {
public void dumpInstruction(TabbedPrintWriter writer)
throws java.io.IOException {
writer.println("IMPLEMENT FINALLY");
}
}

@ -18,6 +18,9 @@
*/
package jode.flow;
import java.util.*;
import jode.TabbedPrintWriter;
import jode.Expression;
/**
* A flow block is the structure of which the flow graph consists. A
@ -30,12 +33,24 @@ package jode.flow;
*/
public class FlowBlock {
static FlowBlock END_OF_METHOD =
new FlowBlock(Integer.MAX_VALUE, 0, new EmptyBlock());
static {
END_OF_METHOD.label = "END_OF_METHOD";
}
/**
* The starting address of this flow block. This is mainly used
* to produce the source code in code order.
*/
int addr;
/**
* The length of the structured block, only needed at the beginning.
*/
int length;
/**
* The outermost structructed block in this flow block.
*/
@ -57,6 +72,25 @@ public class FlowBlock {
* moved into the preceding flow block.
*/
Vector predecessors;
/**
* The default constructor. Creates a new flowblock containing
* only the given structured block.
*/
public FlowBlock(int addr, int length, StructuredBlock block) {
this.addr = addr;
this.length = length;
this.block = block;
lastModified = block;
predecessors = new Vector(); // filled in later
successors = new Vector();
block.setFlowBlock(this);
block.fillSuccessors(successors);
}
public int getNextAddr() {
return addr+length;
}
/**
* This method optimizes the jumps to successor.
@ -65,109 +99,188 @@ public class FlowBlock {
public StructuredBlock optimizeJumps(FlowBlock successor,
StructuredBlock appendBlock) {
Enumeration enum = successors.elements();
next_jump:
while (enum.hasMoreElements()) {
Jump jump = (Jump) enum.nextElement();
if (jump == null || jump.destination != successor)
continue;
continue next_jump;
same_jump: while(true) {
/* if the jump is the jump of the appendBlock, skip it.
*/
if (jump == appendBlock.jump)
continue;
if (jump.prev == appendBlock)
continue next_jump;
/* Note: jump.parent.outer != null, since appendBlock is
* an outer block of jump.parent
/* Note: jump.prev.outer != null, since appendBlock is
* an outer block of jump.prev
*/
/* remove all jumps to the successor which have the successor
* as getNextFlowBlock(). */
if (jump.parent.outer.getNextFlowBlock(jump.parent) == successor)
jump.parent.removeJump();
* as getNextFlowBlock().
*/
if (jump.prev.outer.getNextFlowBlock(jump.prev) == successor) {
jump.prev.removeJump();
continue next_jump;
}
/* replace all conditional jumps to the successor, which
* are followed by a block which has the end of the block
* as normal successor, with "if (not condition) block".
*/
if (jump.parent instanceof ConditionalBlock &&
jump.parent.outer instanceof SequentialBlock &&
jump.parent.outer.getSubBlocks()[0] = jump.parent &&
jump.parent.outer.getNextFlowBlock() == successor) {
if (jump.prev instanceof EmptyBlock &&
jump.prev.outer instanceof ConditionalBlock) {
ConditionalBlock cb = (ConditionalBlock) jump.parent;
cb.removeJump();
StructuredBlock prev = jump.prev;
ConditionalBlock cb = (ConditionalBlock) prev.outer;
jode.Instruction instr = cb.getInstruction();
SequentialBlock sequBlock =
(SequentialBlock) cb.outer;
IfThenElseBlock newIfBlock =
new IfThenElseBlock(cb.getCondition().negate(),
sequBlock.getSubBlocks()[1], null);
if ((cb == appendBlock ||
cb.outer.getNextFlowBlock(cb) == successor
/*XXX jumpMayBeChanged()??? */) &&
instr instanceof jode.Expression) {
newIfBlock.replace(sequBlock);
cb.setInstruction(((jode.Expression)instr).negate());
prev.removeJump();
prev.moveJump(cb);
continue next_jump;
}
if (appendBlock == sequBlock)
appendBlock = newIfBlock;
continue;
/* cb.outer is not null,
* since appendBlock outers cb */
if (cb.outer instanceof SequentialBlock &&
cb.outer.getSubBlocks()[0] == cb &&
(cb.outer.getNextFlowBlock() == successor ||
cb.outer.jumpMayBeChanged()) &&
instr instanceof jode.Expression) {
SequentialBlock sequBlock =
(SequentialBlock) cb.outer;
IfThenElseBlock newIfBlock =
new IfThenElseBlock(((jode.Expression)instr).negate());
newIfBlock.replace(sequBlock);
newIfBlock.setThenBlock(sequBlock.getSubBlocks()[1]);
newIfBlock.moveJump(sequBlock);
if (appendBlock == sequBlock)
appendBlock = newIfBlock;
if (newIfBlock.getNextFlowBlock() != successor &&
newIfBlock != appendBlock) {
newIfBlock.moveJump(prev);
continue same_jump;
} else {
prev.removeJump();
continue next_jump;
}
}
}
/* if there are jumps in an if-then block, which
* have as normal successor the end of the if-then block, and
* the if-then block is followed by a single block, then replace
* the if-then block with a if-then-else block and remove the
* unconditional jump.
*/
StructuredBlock elseBlock =
jump.prev.outer.getNextBlock(jump.prev);
if (elseBlock != null &&
elseBlock.outer != null &&
elseBlock.outer instanceof SequentialBlock &&
elseBlock.outer.getSubBlocks()[0] instanceof IfThenElseBlock &&
(elseBlock.outer.getNextFlowBlock() == successor ||
elseBlock.outer.jumpMayBeChanged())) {
IfThenElseBlock ifBlock =
(IfThenElseBlock)elseBlock.outer.getSubBlocks()[0];
if (ifBlock.getSubBlocks().length == 1) {
elseBlock.outer.removeJump();
ifBlock.replace(elseBlock.outer);
if (appendBlock == elseBlock.outer)
appendBlock = ifBlock;
ifBlock.moveJump(jump.prev);
ifBlock.setElseBlock(elseBlock);
continue same_jump;
}
}
/* if the successor is the dummy return instruction, replace all
* jumps with a return.
*/
if (successor.block.instanceof ReturnBlock) {
if (successor == END_OF_METHOD) {
SequentialBlock sequBlock = new SequentialBlock();
StructuredBlock prevBlock = jump.parent;
StructuredBlock prevBlock = jump.prev;
prevBlock.removeJump();
sequBlock.replace(prevBlock);
sequBlock.setFirst(prevBlock);
sequBlock.setSecond(new ReturnBlock());
continue;
continue next_jump;
}
/* If this is a conditional jump, the first instruction of
* a while and the condition of the while is true, use
* the condition as while condition.
*/
/* This is the first instruction in a while block */
if (jump.parent instanceof ConditionalBlock &&
jump.parent.outer instanceof SequentialBlock &&
jump.parent.outer.getSubBlocks()[0] == this &&
jump.parent.outer.outer instanceof LoopBlock) {
ConditionalBlock cb = (ConditionalBlock) jump.parent;
LoopBlock loopBlock = (LoopBlock) cb.outer.outer;
if (loopBlock.getCondition() == LoopBlock.TRUE &&
loopBlock.getType() != LoopBlock.DOWHILE &&
loopBlock.getNextFlowBlock() == successor) {
cb.removeJump();
loopBlock.setCondition(cb);
cb.outer.getSubBlocks()[1].replace(cb.outer);
/* cb and cb.outer are not used any more */
/* Note that cb.outer != appendBlock because
* appendBlock contains loopBlock
*/
if (jump.prev instanceof EmptyBlock &&
jump.prev.outer instanceof ConditionalBlock &&
jump.prev.outer.jump == null) {
StructuredBlock prev = jump.prev;
ConditionalBlock cb = (ConditionalBlock) prev.outer;
jode.Instruction instr = cb.getInstruction();
/* This is the first instruction in a while block */
if (cb.outer instanceof SequentialBlock &&
cb.outer.getSubBlocks()[0] == cb &&
cb.outer.outer instanceof LoopBlock) {
LoopBlock loopBlock = (LoopBlock) cb.outer.outer;
if (loopBlock.getCondition() == LoopBlock.TRUE &&
loopBlock.getType() != LoopBlock.DOWHILE &&
loopBlock.getNextFlowBlock() == successor &&
instr instanceof Expression) {
prev.removeJump();
loopBlock.setCondition(((Expression)instr).negate());
if (cb.outer.jump != null) {
if (cb.outer.getSubBlocks()[1].jump != null)
cb.outer.removeJump();
else
cb.outer.getSubBlocks()[1].moveJump(cb.outer);
}
cb.outer.getSubBlocks()[1].replace(cb.outer);
/* cb and cb.outer are not used any more */
/* Note that cb.outer != appendBlock because
* appendBlock contains loopBlock
*/
continue next_jump;
}
}
}
/* Now the same for the empty loop. In this case there is
* no sequential block.
*/
if (jump.parent instanceof ConditionalBlock &&
jump.parent.outer instanceof LoopBlock) {
ConditionalBlock cb = (ConditionalBlock) jump.parent;
LoopBlock loopBlock = (LoopBlock) cb.outer;
if (loopBlock.getCondition() == LoopBlock.TRUE &&
loopBlock.getType() != LoopBlock.DOWHILE &&
loopBlock.getNextFlowBlock() == successor) {
cb.removeJump();
loopBlock.setCondition(cb);
EmptyBlock empty = new EmptyBlock();
empty.replace(cb);
/* cb is not used any more */
/* Now the same for the empty loop. In this case there is
* no sequential block.
*/
if (cb.outer instanceof LoopBlock) {
LoopBlock loopBlock = (LoopBlock) cb.outer;
if (loopBlock.getCondition() == LoopBlock.TRUE &&
loopBlock.getType() != LoopBlock.DOWHILE &&
loopBlock.getNextFlowBlock() == successor &&
instr instanceof Expression) {
prev.removeJump();
loopBlock.setCondition(((Expression)instr).negate());
EmptyBlock empty = new EmptyBlock();
empty.replace(cb);
/* cb is not used any more */
continue next_jump;
}
}
}
/* if there are jumps in a while block or switch block and the
* while/switch block is followed by a jump to successor or has
* successor as getNextFlowBlock(), replace jump with break to
@ -178,91 +291,62 @@ public class FlowBlock {
* succesor, so that the above succeeds.
*/
int breaklevel = 0;
for (StructuredBlock surrounder = jump.parent.outer;
surrounder != null; surrounder = surrounder.outer) {
for (StructuredBlock surrounder = jump.prev.outer;
surrounder != null && surrounder != appendBlock.outer;
surrounder = surrounder.outer) {
if (surrounder instanceof BreakableBlock) {
breaklevel++;
if (surrounder.getNextFlowBlock() == successor ||
surrounder.jumpMayBeChanged()) {
SequentialBlock sequBlock = new SequentialBlock();
StructuredBlock prevBlock = jump.parent;
if (surrounder.getNextFlowBlock() != successor) {
surrounder.jump = jump;
prevBlock.jump = null;
jump.parent = surrounder;
} else {
StructuredBlock prevBlock = jump.prev;
if (surrounder.getNextFlowBlock() != successor)
surrounder.moveJump(prevBlock);
else
prevBlock.removeJump();
}
sequBlock.replace(prevBlock);
sequBlock.setFirst(prevBlock);
sequBlock.setSecond(new BreakBlock(surrounder,
breaklevel > 1));
continue;
sequBlock.setSecond
(new BreakBlock((BreakableBlock) surrounder,
breaklevel > 1));
continue next_jump;
}
}
}
/* if there are jumps in an if-then block, which
* have as normal successor the end of the if-then block, and
* the if-then block is followed by a single block, then replace
* the if-then block with a if-then-else block and remove the
* unconditional jump.
*/
StructuredBlock elseBlock =
jump.parent.outer.getNextBlock(jump.parent);
if (elseBlock != null &&
elseBlock.outer != null &&
elseBlock.outer instanceof SequentialBlock &&
elseBlock.outer.getSubBlocks()[0] instanceof IfThenElseBlock &&
(elseBlock.outer.getNextFlowBlock() == successor ||
elseBlock.outer.jumpMayBeChanged())) {
IfThenElseBlock ifBlock =
(IfThenElseBlock)elseBlock.outer.getSubBlocks()[0];
if (ifBlock.getElseBlock() == null) {
if (elseBlock.getNextFlowBlock() != successor) {
elseBlock.outer.jump = jump;
jump.parent.jump = null;
jump.parent = elseBlock.outer;
} else {
jump.parent.removeJump();
}
ifBlock.replace(elseBlock.outer);
ifBlock.setElseBlock(elseBlock);
if (appendBlock = elseBlock.outer)
appendBlock = ifBlock;
}
}
continue next_jump;
}
}
return appendBlock;
}
/**
* Updates the in/out-Vectors of the structured block of the
* successing flow block simultanous to a T1 transformation.
* @param successor The flow block which is unified with this flow
* block.
*/
* successing flow block simultanous to a T1 transformation.
* @param successor The flow block which is unified with this flow
* block.
*/
void updateInOut (FlowBlock successor, boolean t1Transformation) {
/* First get the out vectors of all jumps to successor and
* calculate the intersection.
*/
VariableSet allOuts = new VariableSet();
VariableSet intersectOut = null;
Enumeration enum = successors;
while (enum.hasMoreElement()) {
Enumeration enum = successors.elements();
while (enum.hasMoreElements()) {
Jump jump = (Jump) enum.nextElement();
if (jump == null || jump.destination != successor)
continue;
allOuts.union(jump.parent.out);
allOuts.union(jump.prev.out);
if (intersectOut == null)
intersectOut = jump.parent.out;
intersectOut = jump.prev.out;
else
intersectOut = intersectOut.intersect(jump.parent.out);
intersectOut = intersectOut.intersect(jump.prev.out);
}
/* Now work on each block of the successor */
Stack todo = new Stack();
todo.push(successor.block);
@ -271,7 +355,7 @@ public class FlowBlock {
StructuredBlock[] subBlocks = block.getSubBlocks();
for (int i=0; i<subBlocks.length; i++)
todo.push(subBlocks[i]);
/* Merge the locals used in successing block with those written
* by this blocks
*/
@ -284,7 +368,7 @@ public class FlowBlock {
}
}
}
/* Special cases:
*
@ -350,7 +434,12 @@ public class FlowBlock {
* return_n
*/
public boolean doT1 {
/**
* Search for an apropriate successor.
* @return the successor with smallest address
* or null if there isn't a successor at all.
*/
public FlowBlock getSuccessor() {
/* search successor with smallest addr. */
Enumeration enum = successors.elements();
FlowBlock succ = null;
@ -363,27 +452,78 @@ public class FlowBlock {
succ = fb;
}
}
if (succ == null) {
/* There are no successors at all */
return false;
return succ;
}
public void checkConsistent() {
if (block.outer != null || block.flowBlock != this) {
throw new RuntimeException("Inconsistency");
}
block.checkConsistent();
Enumeration enum = successors.elements();
while (enum.hasMoreElements()) {
Jump jump = (Jump) enum.nextElement();
if (jump == null)
continue;
if (jump.prev.flowBlock != this ||
jump.prev.jump != jump)
throw new RuntimeException("Inconsistency");
StructuredBlock sb = jump.prev;
while (sb != block) {
if (sb.outer == null)
throw new RuntimeException("Inconsistency");
StructuredBlock[] blocks = sb.outer.getSubBlocks();
int i;
for (i=0; i<blocks.length; i++)
if (blocks[i] == sb)
break;
if (i == blocks.length)
throw new RuntimeException("Inconsistency");
sb = sb.outer;
}
}
}
/* check if this successor has only this block as predecessor. */
/* if not, return false. */
if (succ.predecessors.size() != 1)
/**
* Do a T1 transformation with succ if possible. It is possible,
* iff succ has exactly this block as predecessor.
* @param succ the successor block, must be a valid successor of this
* block, i.e. not null
*/
public boolean doT1(FlowBlock succ) {
/* check if this successor has only this block as predecessor.
* if the predecessor is not unique, return false. */
if (succ != END_OF_METHOD &&
(succ.predecessors.size() != 1 ||
succ.predecessors.elementAt(0) != this))
return false;
/* First find the innermost block that contains all jumps to this
* successor and the last modified block.
*/
try {
TabbedPrintWriter writer =
new TabbedPrintWriter(System.err, " ");
writer.tab();
System.err.println("doing T1 analysis on: "+getLabel());
block.dumpSource(writer);
checkConsistent();
System.err.println("and "+succ.getLabel());
succ.block.dumpSource(writer);
succ.checkConsistent();
} catch (java.io.IOException ex) {}
/* First find the innermost block that contains all jumps to this
* successor and the last modified block.
*/
Enumeration enum = successors.elements();
StructuredBlock appendBlock = lastModified;
while(enum.hasMoreElements()) {
Jump jump = (Jump) enum.nextElement();
if (jump == null || jump.destination != successors)
if (jump == null || jump.destination != succ)
continue;
while (!appendBlock.contains(jump.parent))
while (!appendBlock.contains(jump.prev))
appendBlock = appendBlock.outer;
/* appendBlock can't be null now, because the
* outermost block contains every structured block.
@ -391,14 +531,19 @@ public class FlowBlock {
}
/* Update the in/out-Vectors now */
updateInOut(successor, true);
updateInOut(succ, true);
/* The switch "fall through" case: if the appendBlock is a
* switch, and the successor is the address of a case, and all
* other successors are inside the block preceding that case.
*/
if (case != null) {
SwitchBlock switchBlock = (StructuredBlock) appendBlock;
* switch, and the successor is the address of a case, and all
* other successors are inside the block preceding that case.
*/
StructuredBlock precedingcase = null;
StructuredBlock nextcase = null;
/*XXX*/
if (succ == END_OF_METHOD) {
} else if (nextcase != null) {
SwitchBlock switchBlock = (SwitchBlock) appendBlock;
/* Now put the succ.block into the next case.
*/
@ -408,52 +553,120 @@ public class FlowBlock {
/* Do the following modifications on the struct block. */
appendBlock = precedingcase;
succ.block.setFlowBlock(this);
} else {
/* Prepare the unification of the blocks: Make sure that
* appendBlock has a successor outside of this block. This is
* always possible, because it contains lastModified.
*/
/* Prepare the unification of the blocks: Make sure if
* possible that appendBlock has a successor outside of
* this block.
*
* This doesn't change the semantics, since appendBlock
* is the last block that could be modified.
* XXX (is this true for switches)*/
if (appendBlock.jump == null) {
/* assert(appendBlock.jump.getNextFlowBlock() != null) */
appendBlock.setJump(appendBlock.getNextFlowBlock());
Jump jump = new Jump(succ);
appendBlock.setJump(jump);
successors.addElement(jump);
}
/* Now unify the blocks: Create a new SequentialBlock
* containing appendBlock and successor.block. Then replace
* appendBlock with the new sequential block.
*/
StructuredBlock outer = appendBlock.outer;
StructuredBlock sequBlock =
new SequentialBlock(appendBlock, switchBlock);
outer.replaceSubBlock(appendBlock, sequBlock);
sequBlock.outer = outer;
SequentialBlock sequBlock =
new SequentialBlock();
sequBlock.replace(appendBlock);
sequBlock.setFirst(appendBlock);
sequBlock.setSecond(succ.block);
succ.block.setFlowBlock(this);
}
/* Try to eliminate as many jumps as possible.
/* Merge the sucessors from the successing flow block
*/
enum = succ.successors.elements();
while (enum.hasMoreElements()) {
Jump jump = (Jump) enum.nextElement();
if (jump == null)
continue;
successors.addElement(jump);
if (jump.destination.predecessors.contains(succ)) {
/*XXX comment and make clearer, better etc.*/
jump.destination.predecessors.removeElement(succ);
if (!jump.destination.predecessors.contains(this))
jump.destination.predecessors.addElement(this);
}
}
optimizeJumps(succ, appendBlock);
try {
TabbedPrintWriter writer =
new TabbedPrintWriter(System.err, " ");
writer.tab();
System.err.println("before optimizeJump: "+getLabel());
block.dumpSource(writer);
checkConsistent();
} catch (java.io.IOException ex) {}
checkConsistent();
/* Try to eliminate as many jumps as possible.
*/
appendBlock = optimizeJumps(succ, appendBlock);
try {
TabbedPrintWriter writer =
new TabbedPrintWriter(System.err, " ");
writer.tab();
System.err.println("after optimizeJump: "+getLabel());
block.dumpSource(writer);
checkConsistent();
} catch (java.io.IOException ex) {}
System.err.println("XXX");
checkConsistent();
/* Now remove the jump of the appendBlock if it points to successor.
*/
if (appendBlock.jump == succ)
if (appendBlock.jump != null &&
appendBlock.jump.destination == succ)
appendBlock.removeJump();
/* If there are further jumps, put a do/while(0) block around
* appendBlock and replace every remaining jump with a break
* to the do/while block.
*/
/* Merge the sucessors from the successing flow block
*/
enum = succ.successors.elements();
LoopBlock doWhileFalse = null;
enum = successors.elements();
while (enum.hasMoreElements()) {
successors.addElement(enum.nextElement());
Jump jump = (Jump) enum.nextElement();
if (jump == null || jump.destination != succ)
continue;
if (doWhileFalse == null)
doWhileFalse = new LoopBlock(LoopBlock.DOWHILE,
LoopBlock.FALSE);
int breaklevel = 1;
for (StructuredBlock surrounder = jump.prev.outer;
surrounder != appendBlock.outer;
surrounder = surrounder.outer) {
if (surrounder instanceof BreakableBlock) {
breaklevel++;
}
}
SequentialBlock sequBlock = new SequentialBlock();
StructuredBlock prevBlock = jump.prev;
prevBlock.removeJump();
sequBlock.replace(prevBlock);
sequBlock.setFirst(prevBlock);
sequBlock.setSecond(new BreakBlock(doWhileFalse, breaklevel > 1));
}
if (doWhileFalse != null) {
doWhileFalse.replace(appendBlock);
doWhileFalse.setBody(appendBlock);
}
/* Believe it or not: Now the rule, that the first part of a
* SequentialBlock shouldn't be another SequentialBlock is
* fulfilled. <p>
@ -466,6 +679,22 @@ public class FlowBlock {
/* Set last modified to correct value. */
lastModified = succ.lastModified;
/* Set addr+length to (semi-)correct value */
if (succ.addr < addr)
addr = succ.addr;
length += succ.length;
/* T1 transformation succeeded */
try {
TabbedPrintWriter writer =
new TabbedPrintWriter(System.err, " ");
writer.tab();
System.err.println("T1 succeeded:");
block.dumpSource(writer);
checkConsistent();
} catch (java.io.IOException ex) {}
return true;
}
public boolean doT2() {
@ -474,9 +703,21 @@ public class FlowBlock {
* considered yet, return false. The second condition make
* sure that the while isn't created up to the first continue.
*/
if (!predecessors.contains(this)
/* || complicated second condition XXX */ )
return false;
try {
TabbedPrintWriter writer =
new TabbedPrintWriter(System.err, " ");
writer.tab();
System.err.println("doing T2 analysis on: "+getLabel());
block.dumpSource(writer);
checkConsistent();
} catch (java.io.IOException ex) {}
/* Update the in/out-Vectors now */
updateInOut(successor, false);
updateInOut(this, false);
/* If there is only one jump to the beginning and it is the
* last jump and (there is a do/while(0) block surrounding
@ -485,26 +726,145 @@ public class FlowBlock {
* do/while(0) with a for(;;last_instr) resp. create a new one
* and replace breaks to do/while with continue to for.
*/
/* XXX implement above */
/* XXX condition for do/while(cond) blocks */
{
/* Otherwise: */
/* create a new while(true) block.
*/
StructuredBlock bodyBlock = block;
/* Prepare the unification of the blocks: Make sure that
* bodyBlock has a jump. */
if (bodyBlock.jump == null) {
Jump jump = new Jump(this);
bodyBlock.setJump(jump);
successors.addElement(jump);
}
LoopBlock whileBlock =
new LoopBlock(LoopBlock.WHILE, LoopBlock.TRUE);
whileBlock.replace(bodyBlock);
whileBlock.setBody(bodyBlock);
/* Try to eliminate as many jumps as possible.
*/
optimizeJumps(this, block);
bodyBlock = optimizeJumps(this, bodyBlock);
/* Now remove the jump of block if it points to this.
*/
if (bodyBlock.jump != null &&
bodyBlock.jump.destination == this)
bodyBlock.removeJump();
/* if there are further jumps to this, replace every jump with a
* continue to while block and return true.
*/
Enumeration enum = successors.elements();
while (enum.hasMoreElements()) {
Jump jump = (Jump) enum.nextElement();
if (jump == null || jump.destination != this)
continue;
int continuelevel = 1;
for (StructuredBlock surrounder = jump.prev.outer;
surrounder != null;
surrounder = surrounder.outer) {
if (surrounder instanceof LoopBlock) {
continuelevel++;
}
}
SequentialBlock sequBlock = new SequentialBlock();
StructuredBlock prevBlock = jump.prev;
prevBlock.removeJump();
sequBlock.replace(prevBlock);
sequBlock.setFirst(prevBlock);
sequBlock.setSecond(new ContinueBlock(whileBlock,
continuelevel > 1));
}
lastModified = whileBlock;
}
/* remove ourself from the predecessor list.
*/
predecessors.removeElement(this);
/* T2 analysis succeeded */
try {
TabbedPrintWriter writer =
new TabbedPrintWriter(System.err, " ");
writer.tab();
System.err.println("T2 succeded:");
block.dumpSource(writer);
checkConsistent();
} catch (java.io.IOException ex) {}
return true;
}
/**
* Resolves the destinations of all jumps.
*/
public void resolveJumps(FlowBlock[] instr) {
Enumeration enum = successors.elements();
while (enum.hasMoreElements()) {
Jump jump = (Jump) enum.nextElement();
if (jump.destAddr == -1)
jump.destination = END_OF_METHOD;
else
jump.destination = instr[jump.destAddr];
if (!jump.destination.predecessors.contains(this))
jump.destination.predecessors.addElement(this);
}
}
public void removeSuccessor(Jump jump) {
successors.setElementAt(null, successors.indexOf(jump));
}
/**
* Print the source code for this structured block. This handles
* everything that is unique for all structured blocks and calls
* dumpInstruction afterwards.
* @param writer The tabbed print writer, where we print to.
*/
public void dumpSource(TabbedPrintWriter writer)
throws java.io.IOException
{
if (label != null) {
writer.untab();
writer.println(label+":");
writer.tab();
}
block.dumpSource(writer);
FlowBlock succ = getSuccessor();
if (succ != null)
succ.dumpSource(writer);
}
/**
* The serial number for labels.
*/
static int serialno = 0;
/**
* The label of this instruction, or null if it needs no label.
*/
String label = null;
/**
* Returns the label of this block and creates a new label, if
* there wasn't a label previously.
*/
public String getLabel() {
if (label == null)
label = "flow_"+(serialno++)+"_";
return label;
}
}

@ -16,6 +16,8 @@
* $Id$
*/
package jode.flow;
import jode.Instruction;
import jode.TabbedPrintWriter;
/**
* An IfThenElseBlock is the structured block representing an if
@ -53,6 +55,7 @@ public class IfThenElseBlock extends StructuredBlock {
public void setThenBlock(StructuredBlock thenBlock) {
this.thenBlock = thenBlock;
thenBlock.outer = this;
thenBlock.setFlowBlock(flowBlock);
}
/**
@ -62,6 +65,7 @@ public class IfThenElseBlock extends StructuredBlock {
public void setElseBlock(StructuredBlock elseBlock) {
this.elseBlock = elseBlock;
elseBlock.outer = this;
elseBlock.setFlowBlock(flowBlock);
}
/* The implementation of getNext[Flow]Block is the standard
@ -73,7 +77,7 @@ public class IfThenElseBlock extends StructuredBlock {
* @param newBlock the new sub block.
* @return false, if oldBlock wasn't a direct sub block.
*/
boolean replaceSubBlock(StructuredBlock oldBlock,
public boolean replaceSubBlock(StructuredBlock oldBlock,
StructuredBlock newBlock) {
if (thenBlock == oldBlock)
thenBlock = newBlock;
@ -89,21 +93,28 @@ public class IfThenElseBlock extends StructuredBlock {
* called only once, because it remembers which local variables
* were declared.
*/
public void dumpSource(TabbedPrintWriter writer)
public void dumpInstruction(TabbedPrintWriter writer)
throws java.io.IOException
{
boolean needBrace = ! (thenBlock instanceof InstructionBlock);
writer.println("if ("+cond.toString()+")"+needBrace?" {":"");
writer.println("if ("+cond.toString()+")"+(needBrace?" {":""));
writer.tab();
thenBlock.dumpSource(writer);
writer.untab();
if (elseBlock != null) {
writer.print(needBrace?"} ":"");
needBrace = ! (thenBlock instanceof InstructionBlock);
writer.println("else"+needBrace?" {":"");
writer.tab();
elseBlock.dumpSource(writer);
writer.untab();
writer.print(needBrace ? "} " : "");
if (elseBlock instanceof IfThenElseBlock
/* XXX && No variables are declared XXX*/) {
needBrace = false;
writer.print("else ");
elseBlock.dumpSource(writer);
} else {
needBrace = ! (elseBlock instanceof InstructionBlock);
writer.println("else" + (needBrace ? " {" : ""));
writer.tab();
elseBlock.dumpSource(writer);
writer.untab();
}
}
if (needBrace)
writer.println("}");
@ -112,12 +123,12 @@ public class IfThenElseBlock extends StructuredBlock {
/**
* Returns all sub block of this structured block.
*/
StructuredBlock[] getSubBlocks() {
public StructuredBlock[] getSubBlocks() {
if (elseBlock == null) {
StructuredBlock result = { thenBlock };
StructuredBlock[] result = { thenBlock };
return result;
} else {
StructuredBlock result = { thenBlock, elseBlock };
StructuredBlock[] result = { thenBlock, elseBlock };
return result;
}
}
@ -132,7 +143,7 @@ public class IfThenElseBlock extends StructuredBlock {
return false;
if (elseBlock != null && elseBlock.jump == null &&
!elseBlock.jumpMayBeChanged)
!elseBlock.jumpMayBeChanged())
return false;
return true;
}

@ -16,33 +16,52 @@
* $Id$
*/
package jode.flow;
import jode.*;
/**
* This is the structured block for atomic instructions.
*/
public class InstructionBlock extends StructuredBlock {
public class InstructionBlock extends StructuredBlock
implements InstructionContainer {
Instruction instr;
InstructionBlock(Instruction instr) {
in = new Vector();
out = new Vector();
public InstructionBlock(Instruction instr) {
this.instr = instr;
if (instr instanceof LocalVarOperator) {
LocalVarOperator varOp = (LocalVarOperator) instr;
if (varOp.isRead())
if (varOp.isRead()) {
in.addElement(varOp.getLocalInfo());
else /* if (varOp.isWrite()) */
out.addElement(varOp.getLocalInfo());
}
out.addElement(varOp.getLocalInfo());
}
}
public void dumpSource(TabbedPrintWriter writer)
public InstructionBlock(Instruction instr, Jump jump) {
this(instr);
setJump(jump);
}
/**
* Get the underlying instruction.
* @return the underlying instruction.
*/
public Instruction getInstruction() {
return instr;
}
/**
* Change the underlying instruction.
* @param instr the new underlying instruction.
*/
public void setInstruction(Instruction instr) {
this.instr = instr;
}
public void dumpInstruction(TabbedPrintWriter writer)
throws java.io.IOException
{
if (!(instr instanceof NopOperator)) {
if (instr.getType() != MyType.tVoid)
writer.print("push ");
writer.println(instr.toString()+";");
}
if (instr.getType() != MyType.tVoid)
writer.print("push ");
writer.println(instr.toString()+";");
}
}

@ -0,0 +1,34 @@
/* InstructionContainer (c) 1998 Jochen Hoenicke
*
* You may distribute under the terms of the GNU General Public License.
*
* IN NO EVENT SHALL JOCHEN HOENICKE BE LIABLE TO ANY PARTY FOR DIRECT,
* INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF
* THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF JOCHEN HOENICKE
* HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* JOCHEN HOENICKE SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
* PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS"
* BASIS, AND JOCHEN HOENICKE HAS NO OBLIGATION TO PROVIDE MAINTENANCE,
* SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*
* $Id$
*/
package jode.flow;
/**
* This is a method for block containing a single instruction.
*/
public interface InstructionContainer {
/**
* Get the contained instruction.
* @return the contained instruction.
*/
public jode.Instruction getInstruction();
/**
* Set the contained instruction.
* @param instr the new instruction.
*/
public void setInstruction(jode.Instruction instr);
}

@ -25,19 +25,35 @@ public class Jump {
* The structured block that precedes this jump.
*/
StructuredBlock prev;
/**
* The flow block, where this jump lies in
*/
FlowBlock parent;
/**
* The destination block of this jump.
*/
FlowBlock destination;
/**
* The destination address, in case the destination block is not yet
* known.
*/
int destAddr;
public Jump (int destAddr) {
this.destAddr = destAddr;
}
public Jump (FlowBlock dest) {
this.destination = dest;
}
/**
* Returns true if this jump has jsr or monitorexit attachments.
*/
boolean hasAttachments() {
return false;
}
}
/**
* Returns a string describing the jsr or monitorexit attachments.
*/
String describeAttachments() {
return "";
}
}

@ -0,0 +1,156 @@
/*
* LoopBlock (c) 1998 Jochen Hoenicke
*
* You may distribute under the terms of the GNU General Public License.
*
* IN NO EVENT SHALL JOCHEN HOENICKE BE LIABLE TO ANY PARTY FOR DIRECT,
* INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF
* THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF JOCHEN HOENICKE
* HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* JOCHEN HOENICKE SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
* PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS"
* BASIS, AND JOCHEN HOENICKE HAS NO OBLIGATION TO PROVIDE MAINTENANCE,
* SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*
* $Id$
*/
package jode.flow;
import jode.*;
/**
* This is the structured block for an Loop block.
*/
public class LoopBlock extends BreakableBlock {
public static final int WHILE = 0;
public static final int DOWHILE = 1;
public static final int FOR = 2;
public static final Instruction TRUE =
new Expression(new ConstOperator(MyType.tBoolean, "1"),
new Expression[0]);
public static final Instruction FALSE =
new Expression(new ConstOperator(MyType.tBoolean, "0"),
new Expression[0]);
/**
* The condition. Must be of boolean type.
*/
Instruction cond;
/**
* The init instruction, only valid if type == FOR.
*/
Instruction init;
/**
* The increase instruction, only valid if type == FOR.
*/
Instruction incr;
/**
* The type of the loop. This must be one of DOWHILE, WHILE or FOR.
*/
int type;
/**
* The body of this loop. This is always a valid block and not null
*/
StructuredBlock bodyBlock;
/**
* Returns the block where the control will normally flow to, when
* the given sub block is finished (<em>not</em> ignoring the jump
* after this block). (This is overwritten by SequentialBlock and
* SwitchBlock). If this isn't called with a direct sub block,
* the behaviour is undefined, so take care.
* @return null, if the control flows to another FlowBlock. */
public StructuredBlock getNextBlock(StructuredBlock subBlock) {
return this;
}
public FlowBlock getNextFlowBlock(StructuredBlock subBlock) {
return null;
}
public LoopBlock(int type, Instruction cond) {
this.type = type;
this.cond = cond;
this.mayChangeJump = (cond == TRUE);
}
public void setBody(StructuredBlock body) {
bodyBlock = body;
bodyBlock.outer = this;
body.setFlowBlock(flowBlock);
}
public Instruction getCondition() {
return cond;
}
public void setCondition(Instruction cond) {
this.cond = cond;
mayChangeJump = false;
}
public int getType() {
return type;
}
public void setType(int type) {
this.type = type;
}
/**
* 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 (bodyBlock == oldBlock)
bodyBlock = newBlock;
else
return false;
return true;
}
/**
* Returns all sub block of this structured block.
*/
public StructuredBlock[] getSubBlocks() {
StructuredBlock[] result = { bodyBlock };
return result;
}
public void dumpInstruction(TabbedPrintWriter writer)
throws java.io.IOException
{
boolean needBrace = ! (bodyBlock instanceof InstructionBlock);
switch (type) {
case WHILE:
writer.print("while ("+cond.toString()+")");
break;
case DOWHILE:
writer.print("do");
break;
case FOR:
writer.print("for ("+(init != null ? init.toString() : "") +
"; "+cond.toString()+"; "+incr.toString()+")");
break;
}
writer.println( needBrace?" {": "");
writer.tab();
bodyBlock.dumpSource(writer);
writer.untab();
if (type == DOWHILE)
writer.println((needBrace?"} ": "")+
"while ("+cond.toString()+")");
else if (needBrace)
writer.println("}");
}
}

@ -17,6 +17,7 @@
*/
package jode.flow;
import jode.TabbedPrintWriter;
/**
* A RawTryCatchBlock is created for each exception in the
@ -39,7 +40,7 @@ package jode.flow;
* @see SynchronizedBlock
*/
public RawTryCatchBlock extends StructuredBlock {
public class RawTryCatchBlock extends StructuredBlock {
/**
* An unconditional jump to the EndBlock.
@ -55,5 +56,10 @@ public RawTryCatchBlock extends StructuredBlock {
* The type of the exception that is catched. This is null for a
* synchronized/finally block
*/
Type type;
jode.MyType type;
public void dumpInstruction(TabbedPrintWriter writer)
throws java.io.IOException {
writer.println("IMPLEMENT FINALLY");
}
}

@ -0,0 +1,85 @@
/*
* RemoveEmpty (c) 1998 Jochen Hoenicke
*
* You may distribute under the terms of the GNU General Public License.
*
* IN NO EVENT SHALL JOCHEN HOENICKE BE LIABLE TO ANY PARTY FOR DIRECT,
* INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF
* THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF JOCHEN HOENICKE
* HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* JOCHEN HOENICKE SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
* PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS"
* BASIS, AND JOCHEN HOENICKE HAS NO OBLIGATION TO PROVIDE MAINTENANCE,
* SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*
* $Id$
*/
package jode.flow;
import jode.Instruction;
import jode.NopOperator;
public class RemoveEmpty implements Transformation {
public boolean transform (FlowBlock fb) {
return (removeNop(fb) || removeEmpty(fb));
}
public boolean removeNop(FlowBlock flow) {
StructuredBlock block;
SequentialBlock sequBlock;
Instruction instr;
try {
block = flow.lastModified;
if (!(((InstructionContainer)block).getInstruction()
instanceof NopOperator))
return false;
sequBlock = (SequentialBlock)block.outer;
if (sequBlock.getSubBlocks()[1] != block)
return false;
InstructionBlock prev =
(InstructionBlock) sequBlock.getSubBlocks()[0];
if (prev.jump != null)
return false;
instr = (Instruction) prev.getInstruction();
} catch (NullPointerException ex) {
return false;
} catch (ClassCastException ex) {
return false;
}
((InstructionContainer)block).setInstruction(instr);
block.replace(sequBlock);
flow.lastModified = block;
return true;
}
public boolean removeEmpty(FlowBlock flow) {
StructuredBlock lastBlock = flow.lastModified;
if (lastBlock instanceof EmptyBlock &&
lastBlock.outer instanceof SequentialBlock &&
lastBlock.outer.getSubBlocks()[1] == lastBlock) {
StructuredBlock block = lastBlock.outer.getSubBlocks()[0];
block.replace(block.outer);
if (block.jump == null)
block.moveJump(lastBlock);
else
lastBlock.removeJump();
flow.lastModified = block;
return true;
}
if (lastBlock.outer instanceof SequentialBlock &&
lastBlock.outer.getSubBlocks()[0] instanceof EmptyBlock &&
lastBlock.outer.getSubBlocks()[0].jump == null) {
lastBlock.replace(lastBlock.outer);
flow.lastModified = lastBlock;
return true;
}
return false;
}
}

@ -0,0 +1,42 @@
/*
* ReturnBlock (c) 1998 Jochen Hoenicke
*
* You may distribute under the terms of the GNU General Public License.
*
* IN NO EVENT SHALL JOCHEN HOENICKE BE LIABLE TO ANY PARTY FOR DIRECT,
* INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF
* THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF JOCHEN HOENICKE
* HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* JOCHEN HOENICKE SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
* PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS"
* BASIS, AND JOCHEN HOENICKE HAS NO OBLIGATION TO PROVIDE MAINTENANCE,
* SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*
* $Id$
*/
package jode.flow;
import jode.TabbedPrintWriter;
import jode.Instruction;
/**
* This is the structured block for an Return block.
*/
public class ReturnBlock extends StructuredBlock {
Instruction instr = null;
public ReturnBlock() {
}
public ReturnBlock(Instruction instr) {
this.instr = instr;
}
public void dumpInstruction(TabbedPrintWriter writer)
throws java.io.IOException
{
writer.println("return" + (instr == null ? "" : " " + instr) + ";");
}
}

@ -16,6 +16,7 @@
* $Id$
*/
package jode.flow;
import jode.TabbedPrintWriter;
/**
* A sequential block combines exactly two structured blocks to a new
@ -24,21 +25,23 @@ package jode.flow;
* condition is temporarily violated, while the t1 transformation is
* done.
*/
public class SequentialBlock {
public class SequentialBlock extends StructuredBlock {
StructuredBlock[] subBlocks;
public SequentialBlock() {
subBlocks = new StructuredBlock[2];
}
public setFirst(StructuredBlock sb) {
public void setFirst(StructuredBlock sb) {
subBlocks[0] = sb;
sb.outer = this;
sb.setFlowBlock(flowBlock);
}
public setSecond(StructuredBlock sb) {
public void setSecond(StructuredBlock sb) {
subBlocks[1] = sb;
sb.outer = this;
sb.setFlowBlock(flowBlock);
}
/**
@ -48,25 +51,32 @@ public class SequentialBlock {
* SwitchBlock). If this isn't called with a direct sub block,
* the behaviour is undefined, so take care.
* @return null, if the control flows to another FlowBlock. */
StructuredBlock getNextBlock(StructuredBlock subBlock) {
public StructuredBlock getNextBlock(StructuredBlock subBlock) {
if (subBlock == subBlocks[0])
return subBlocks[1];
return getNextBlock();
}
FlowBlock getNextFlowBlock(StructuredBlock subBlock) {
public FlowBlock getNextFlowBlock(StructuredBlock subBlock) {
if (subBlock == subBlocks[0])
return null;
return getNextFlowBlock();
}
public void dumpInstruction(TabbedPrintWriter writer)
throws java.io.IOException
{
subBlocks[0].dumpSource(writer);
subBlocks[1].dumpSource(writer);
}
/**
* 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.
*/
boolean replaceSubBlock(StructuredBlock oldBlock,
public boolean replaceSubBlock(StructuredBlock oldBlock,
StructuredBlock newBlock) {
for (int i=0; i<2; i++) {
if (subBlocks[i] == oldBlock) {
@ -80,7 +90,7 @@ public class SequentialBlock {
/**
* Returns all sub block of this structured block.
*/
StructuredBlock[] getSubBlocks() {
public StructuredBlock[] getSubBlocks() {
return subBlocks;
}
@ -93,7 +103,3 @@ public class SequentialBlock {
return (subBlocks[1].jump != null || subBlocks[1].jumpMayBeChanged());
}
}

@ -18,6 +18,7 @@
*/
package jode.flow;
import jode.TabbedPrintWriter;
/**
* A structured block is the building block of the source programm.
@ -49,8 +50,8 @@ package jode.flow;
public abstract class StructuredBlock {
/* Invariants:
* in.intersection(out) = empty
* outer != null => flowblock = outer.flowblock
* outer == null => flowblock.block = this
* outer != null => flowBlock = outer.flowBlock
* outer == null => flowBlock.block = this
* jump == null => outer != null
* either getNextBlock() != null
* or getNextFlowBlock() != null or outer == null
@ -65,7 +66,7 @@ public abstract class StructuredBlock {
* path from the start of the current flow block, on which the
* local variable is never assigned
*/
VariableSet in;
VariableSet in = new VariableSet();
/**
* The out locals. This are the locals, which must be overwritten
@ -74,14 +75,14 @@ public abstract class StructuredBlock {
* structured block contain a (unconditional) assignment to this
* local
*/
VariableSet out;
VariableSet out = new VariableSet();
/**
* The variable set containing all variables that must be defined
* in this block (or maybe an outer block, this changes as the
* blocks are put together).
*/
VariableSet defineHere;
VariableSet defineHere = new VariableSet();
/**
* The surrounding structured block. If this is the outermost
@ -91,7 +92,7 @@ public abstract class StructuredBlock {
/**
* The flow block in which this structured block lies.
*/
FlowBlock flowblock;
FlowBlock flowBlock;
/**
* The jump that follows on this block, or null if there is no
@ -104,13 +105,17 @@ public abstract class StructuredBlock {
* Returns the block where the control will normally flow to, when
* this block is finished (not ignoring the jump after this block).
*/
StructuredBlock getNextBlock() {
public StructuredBlock getNextBlock() {
if (jump != null)
return null;
if (outer != null)
outer.getNextBlock(this);
else
return null;
return outer.getNextBlock(this);
return null;
}
public void setJump(Jump jump) {
this.jump = jump;
jump.prev = this;
}
/**
@ -120,13 +125,12 @@ public abstract class StructuredBlock {
* @return null, if the control flows into a non empty structured
* block or if this is the outermost block.
*/
FlowBlock getNextFlowBlock() {
public FlowBlock getNextFlowBlock() {
if (jump != null)
return jump.destination;
if (outer != null)
outer.getNextFlowBlock(this);
else
return null;
return outer.getNextFlowBlock(this);
return null;
}
/**
@ -135,13 +139,12 @@ public abstract class StructuredBlock {
* @return null, if everything is okay, and a diagnostic message that
* should be put in a comment otherwise.
*/
String checkJump(Jump jump) {
public String checkJump(Jump jump) {
if (outer != null)
return outer.checkJump(jump);
else if (jump.hasAttachments())
return "Unknown attachments: "+jump.describeAttachments()
else
return null;
if (jump.hasAttachments())
return "Unknown attachments: "+jump.describeAttachments();
return null;
}
/**
@ -151,11 +154,11 @@ public abstract class StructuredBlock {
* SwitchBlock). If this isn't called with a direct sub block,
* the behaviour is undefined, so take care.
* @return null, if the control flows to another FlowBlock. */
StructuredBlock getNextBlock(StructuredBlock subBlock) {
public StructuredBlock getNextBlock(StructuredBlock subBlock) {
return getNextBlock();
}
FlowBlock getNextFlowBlock(StructuredBlock subBlock) {
public FlowBlock getNextFlowBlock(StructuredBlock subBlock) {
return getNextFlowBlock();
}
@ -165,15 +168,15 @@ public abstract class StructuredBlock {
* @param newBlock the new sub block.
* @return false, if oldBlock wasn't a direct sub block.
*/
boolean replaceSubBlock(StructuredBlock oldBlock,
StructuredBlock newBlock) {
public boolean replaceSubBlock(StructuredBlock oldBlock,
StructuredBlock newBlock) {
return false;
}
/**
* Returns all sub block of this structured block.
*/
StructuredBlock[] getSubBlocks() {
public StructuredBlock[] getSubBlocks() {
return new StructuredBlock[0];
}
@ -182,19 +185,21 @@ public abstract class StructuredBlock {
* @param child the block which should be contained by this block.
* @return false, if child is null, or is not contained in this block.
*/
boolean contains(StructuredBlock child) {
public boolean contains(StructuredBlock child) {
while (child != this && child != null)
child = child.outer;
return (child == this);
}
/**
* Removes the jump after this structured block. This does also update
* the successors vector of the flow block.
* Removes the given jump if it is our jump. This does also
* update the successors vector of the flow block.
*
* @param jump The jump that should be removed.
*/
public void removeJump() {
if (jump != null) {
jump.prev = null;
flowBlock.removeSuccessor(jump);
jump = null;
}
@ -202,24 +207,17 @@ public abstract class StructuredBlock {
/**
* This function replaces sb with this block. It copies outer and
* the following jump from sb, and updates them, so they know that
* sb was replaced.
* The jump field of sb is removed afterwards. You have to replace
* sb.outer or mustn't use sb anymore.
* @param sb The structured block that should be replaced.
*/
* from sb, and updates the outer block, so it knows that sb was
* replaced. You have to replace sb.outer or mustn't use sb
* anymore.
* @param sb The structured block that should be replaced. */
public void replace(StructuredBlock sb) {
in = sb.in;
out = sb.out;
defineHere = sb.defineHere;
outer = sb.outer;
flowBlock = sb.flowBlock;
jump = sb.jump;
if (jump != null) {
jump.parent = this;
sb.jump = null;
}
if (outer != null) {
outer.replaceSubBlock(sb, this);
} else {
@ -227,6 +225,19 @@ public abstract class StructuredBlock {
}
}
/**
* This function moves the jumps from sb to this block.
* The jump field of sb is removed afterwards.
* @param sb The structured block whose jump is copied.
*/
public void moveJump(StructuredBlock sb) {
jump = sb.jump;
if (jump != null) {
jump.prev = this;
sb.jump = null;
}
}
/**
* 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.
@ -236,25 +247,78 @@ public abstract class StructuredBlock {
return false;
}
public void checkConsistent() {
StructuredBlock[] subs = getSubBlocks();
for (int i=0; i<subs.length; i++) {
if (subs[i].outer != this ||
subs[i].flowBlock != flowBlock) {
throw new RuntimeException("Inconsistency");
}
subs[i].checkConsistent();
}
if (jump != null &&
(jump.prev != this ||
!flowBlock.successors.contains(jump) ||
!jump.destination.predecessors.contains(flowBlock))) {
throw new RuntimeException("Inconsistency");
}
}
/**
* Get the unique predecessor which mustn't be a conditional jump
* @return the predecessor or null if there isn't a such a thing
* Set the flow block of this block and all sub blocks.
* @param flowBlock the new flow block
*/
public StructuredBlock getSimpleUniquePredecessor() {
SequentialBlock sequ;
if (outer instanceof SequentialBlock) {
if (outer.getSubBlocks()[1] == this)
return outer.getSubBlocks()[0];
else if (outer.outer instanceof SequentialBlock)
return outer.outer.getSubBlocks[0];
public void setFlowBlock(FlowBlock flowBlock) {
if (this.flowBlock != flowBlock) {
this.flowBlock = flowBlock;
StructuredBlock[] subs = getSubBlocks();
for (int i=0; i<subs.length; i++) {
subs[i].setFlowBlock(flowBlock);
}
}
}
/**
* Put all the successors of this block and all subblocks into
* the given vector.
* @param succs The vector, the successors should be stored to.
*/
public void fillSuccessors(java.util.Vector succs) {
succs.addElement(jump);
StructuredBlock[] subs = getSubBlocks();
for (int i=0; i<subs.length; i++) {
subs[i].fillSuccessors(succs);
}
return null;
}
/**
* Print the source code for this structured block. This may be
* called only once, because it remembers which local variables
* were declared. */
public abstract void dumpSource(TabbedPrintWriter writer)
* Print the source code for this structured block. This handles
* everything that is unique for all structured blocks and calls
* dumpInstruction afterwards.
* @param writer The tabbed print writer, where we print to.
*/
public void dumpSource(TabbedPrintWriter writer)
throws java.io.IOException
{
/* XXX declare variables needed in this block */
dumpInstruction(writer);
if (jump != null) {
if (jump.destination == null)
writer.println ("GOTO null-ptr!!!!!");
else {
writer.println("GOTO "+jump.destination.getLabel());
if (jump.prev != this)
writer.println("GOTO has wrong prev");
}
}
}
/**
* Print the instruction expressing this structured block.
* @param writer The tabbed print writer, where we print to.
*/
public abstract void dumpInstruction(TabbedPrintWriter writer)
throws java.io.IOException;
}

@ -0,0 +1,72 @@
/*
* SwitchBlock (c) 1998 Jochen Hoenicke
*
* You may distribute under the terms of the GNU General Public License.
*
* IN NO EVENT SHALL JOCHEN HOENICKE BE LIABLE TO ANY PARTY FOR DIRECT,
* INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF
* THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF JOCHEN HOENICKE
* HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* JOCHEN HOENICKE SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
* PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS"
* BASIS, AND JOCHEN HOENICKE HAS NO OBLIGATION TO PROVIDE MAINTENANCE,
* SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*
* $Id$
*/
package jode.flow;
import jode.TabbedPrintWriter;
/**
* This is the structured block for an empty block.
*/
public class SwitchBlock extends BreakableBlock {
int[] cases;
StructuredBlock[] caseBlocks;
public SwitchBlock(int[] cases, int[] dests) {
this.cases = cases;
this.caseBlocks = new StructuredBlock[dests.length];
for (int i=0; i<dests.length; i++) {
/* XXX sort the destinations, multi-cases? */
caseBlocks[i] = new EmptyBlock(new Jump(dests[i]));
}
this.jump = null;
mayChangeJump = true;
}
public void dumpInstruction(TabbedPrintWriter writer)
throws java.io.IOException
{
writer.println("switch (/* XXX implement */)");
}
/**
* Returns the block where the control will normally flow to, when
* the given sub block is finished (<em>not</em> ignoring the jump
* after this block). (This is overwritten by SequentialBlock and
* SwitchBlock). If this isn't called with a direct sub block,
* the behaviour is undefined, so take care.
* @return null, if the control flows to another FlowBlock. */
public StructuredBlock getNextBlock(StructuredBlock subBlock) {
/*XXX*/
return getNextBlock();
}
public FlowBlock getNextFlowBlock(StructuredBlock subBlock) {
/*XXX*/
return getNextFlowBlock();
}
/**
* Returns all sub block of this structured block.
*/
public StructuredBlock[] getSubBlocks() {
return caseBlocks;
}
}

@ -0,0 +1,42 @@
/*
* ThrowBlock (c) 1998 Jochen Hoenicke
*
* You may distribute under the terms of the GNU General Public License.
*
* IN NO EVENT SHALL JOCHEN HOENICKE BE LIABLE TO ANY PARTY FOR DIRECT,
* INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF
* THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF JOCHEN HOENICKE
* HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* JOCHEN HOENICKE SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
* PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS"
* BASIS, AND JOCHEN HOENICKE HAS NO OBLIGATION TO PROVIDE MAINTENANCE,
* SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*
* $Id$
*/
package jode.flow;
import jode.TabbedPrintWriter;
import jode.Instruction;
/**
* This is the structured block for an Throw block.
*/
public class ThrowBlock extends StructuredBlock {
Instruction instr = null;
public ThrowBlock() {
}
public ThrowBlock(Instruction instr) {
this.instr = instr;
}
public void dumpInstruction(TabbedPrintWriter writer)
throws java.io.IOException
{
writer.println("throw" + (instr == null ? "" : " " + instr) + ";");
}
}

@ -0,0 +1,24 @@
/*
* Transformation (c) 1998 Jochen Hoenicke
*
* You may distribute under the terms of the GNU General Public License.
*
* IN NO EVENT SHALL JOCHEN HOENICKE BE LIABLE TO ANY PARTY FOR DIRECT,
* INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF
* THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF JOCHEN HOENICKE
* HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* JOCHEN HOENICKE SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
* PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS"
* BASIS, AND JOCHEN HOENICKE HAS NO OBLIGATION TO PROVIDE MAINTENANCE,
* SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*
* $Id$
*/
package jode.flow;
public interface Transformation {
public boolean transform(FlowBlock flowBlock);
}

@ -15,7 +15,8 @@
*
* $Id$
*/
package jode.Flow;
package jode.flow;
import jode.LocalInfo;
/**
* This class represents a set of Variables, which are mainly used in
@ -39,7 +40,7 @@ public class VariableSet extends java.util.Vector {
* Adds a local variable to the variable set.
* @param li The local variable of type LocalInfo.
*/
public addElement(LocalInfo li) {
public void addElement(LocalInfo li) {
super.addElement((Object)li);
}
@ -54,7 +55,7 @@ public class VariableSet extends java.util.Vector {
LocalInfo li1 = ((LocalInfo) elementData[i]).getLocalInfo();
for (int j=0; j<vs.elementCount; j++) {
LocalInfo li2 = ((LocalInfo) vs.elementData[j]).getLocalInfo();
if (li1.getSlot() = li2.getSlot()) {
if (li1.getSlot() == li2.getSlot()) {
li1.combineWith(li2);
}
}
@ -72,7 +73,7 @@ public class VariableSet extends java.util.Vector {
LocalInfo li1 = ((LocalInfo) elementData[i]).getLocalInfo();
for (int j=0; j<vs.elementCount; j++) {
LocalInfo li2 = ((LocalInfo) vs.elementData[j]).getLocalInfo();
if (li1.getSlot() = li2.getSlot()) {
if (li1.getSlot() == li2.getSlot()) {
if (!intersection.contains(li1))
intersection.addElement(li1);
if (!intersection.contains(li2))
@ -106,7 +107,7 @@ public class VariableSet extends java.util.Vector {
* Add the other variable set to the current, except when the slot
* is already in the current set.
*/
public void union(VariableSet vs) {
public void add(VariableSet vs) {
int oldSize = elementCount;
iloop:
for (int i=0; i< vs.elementCount; i++) {
@ -132,7 +133,7 @@ public class VariableSet extends java.util.Vector {
/* We count from top to bottom to have easier reorganization.
* Note, that the variables have not to be in any particular
* order. */
int newCount = elementCount
int newCount = elementCount;
for (int i=newCount-1; i>=0; i--) {
LocalInfo li1 = (LocalInfo) elementData[i];
for (int j=0; j<vs.elementCount; j++) {

Loading…
Cancel
Save