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

@ -19,15 +19,19 @@
package jode; package jode;
import sun.tools.java.*; import sun.tools.java.*;
import java.util.Stack;
import java.io.*; import java.io.*;
import jode.flow.FlowBlock;
public class CodeAnalyzer implements Analyzer, Constants { public class CodeAnalyzer implements Analyzer, Constants {
BinaryCode bincode; BinaryCode bincode;
MethodInstructionHeader methodHeader; FlowBlock methodHeader;
MethodAnalyzer method; MethodAnalyzer method;
public JodeEnvironment env; public JodeEnvironment env;
LocalVariableTable lvt;
/** /**
* Get the method. * Get the method.
@ -39,20 +43,34 @@ public class CodeAnalyzer implements Analyzer, Constants {
throws ClassFormatError throws ClassFormatError
{ {
byte[] code = bincode.getCode(); byte[] code = bincode.getCode();
InstructionHeader[] instr = new InstructionHeader[code.length]; FlowBlock[] instr = new FlowBlock[code.length];
int returnCount; int returnCount;
try { try {
DataInputStream stream = DataInputStream stream =
new DataInputStream(new ByteArrayInputStream(code)); new DataInputStream(new ByteArrayInputStream(code));
for (int addr = 0; addr < code.length; ) { for (int addr = 0; addr < code.length; ) {
instr[addr] = Opcodes.readOpcode(addr, stream, this); instr[addr] = Opcodes.readOpcode(addr, stream, this);
addr = instr[addr].getNextAddr(); addr = instr[addr].getNextAddr();
} }
} catch (IOException ex) { } catch (IOException ex) {
throw new ClassFormatError(ex.toString()); throw new ClassFormatError(ex.toString());
} }
BinaryExceptionHandler[] handlers = bincode.getExceptionHandlers(); 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(); readCode();
} }
static Transformation[] exprTrafos = { static jode.flow.Transformation[] exprTrafos = {
new RemoveNop(), new jode.flow.RemoveEmpty(),
new CombineCatchLocal(), // new CombineCatchLocal(),
new CreateExpression(), new jode.flow.CreateExpression(),
new CreatePostIncExpression(), // new CreatePostIncExpression(),
new CreateAssignExpression(), // new CreateAssignExpression(),
new CreateNewConstructor(), // new CreateNewConstructor(),
new CombineIfGotoExpressions(), // new CombineIfGotoExpressions(),
new CreateIfThenElseOperator(), // new CreateIfThenElseOperator(),
new CreateConstantArray() // new CreateConstantArray()
}; };
static Transformation[] simplifyTrafos = { new SimplifyExpression() }; static Transformation[] simplifyTrafos = { new SimplifyExpression() };
@ -101,9 +119,57 @@ public class CodeAnalyzer implements Analyzer, Constants {
public void analyze() public void analyze()
{ {
methodHeader.doTransformations(exprTrafos); /* XXX optimize */
methodHeader.doTransformations(simplifyTrafos); Stack todo = new Stack();
methodHeader.doTransformations(blockTrafos); 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) { public String getTypeString(Type type) {

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

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

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

@ -22,12 +22,11 @@ import sun.tools.java.Type;
public class LocalLoadOperator extends ConstOperator public class LocalLoadOperator extends ConstOperator
implements LocalVarOperator { implements LocalVarOperator {
int slot;
LocalInfo local; LocalInfo local;
public LocalLoadOperator(Type type, int slot) { public LocalLoadOperator(Type type, LocalInfo local) {
super(type, ""); super(type, "");
this.slot = slot; this.local = local;
} }
public boolean isRead() { public boolean isRead() {
@ -38,10 +37,10 @@ implements LocalVarOperator {
return false; return false;
} }
public void setLocalInfo(LocalInfo local) { // public void setLocalInfo(LocalInfo local) {
local.setType(type); // local.setType(type);
this.local = local; // this.local = local;
} // }
public LocalInfo getLocalInfo() { public LocalInfo getLocalInfo() {
return local; return local;
@ -57,9 +56,9 @@ implements LocalVarOperator {
return super.setType(local.setType(type)); return super.setType(local.setType(type));
} }
public int getSlot() { // public int getSlot() {
return slot; // return slot;
} // }
public String toString(String[] operands) { public String toString(String[] operands) {
return local.getName().toString(); return local.getName().toString();
@ -67,7 +66,7 @@ implements LocalVarOperator {
public boolean equals(Object o) { public boolean equals(Object o) {
return (o instanceof LocalLoadOperator && 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 public class LocalStoreOperator extends StoreInstruction
implements LocalVarOperator { implements LocalVarOperator {
int slot;
LocalInfo local; LocalInfo local;
public LocalStoreOperator(Type lvalueType, int slot, int operator) { public LocalStoreOperator(Type lvalueType, LocalInfo local, int operator) {
super(lvalueType, operator); super(lvalueType, operator);
this.slot = slot; this.local = local;
} }
public boolean isRead() { public boolean isRead() {
@ -38,10 +37,10 @@ implements LocalVarOperator {
return true; return true;
} }
public void setLocalInfo(LocalInfo local) { // public void setLocalInfo(LocalInfo local) {
local.setType(lvalueType); // local.setType(lvalueType);
this.local = local; // this.local = local;
} // }
public LocalInfo getLocalInfo() { public LocalInfo getLocalInfo() {
return local; return local;
@ -58,9 +57,9 @@ implements LocalVarOperator {
(local.setType(MyType.tSuperType(type))); (local.setType(MyType.tSuperType(type)));
} }
public int getSlot() { // public int getSlot() {
return slot; // return slot;
} // }
public boolean matches(Operator loadop) { public boolean matches(Operator loadop) {
return loadop instanceof LocalLoadOperator && return loadop instanceof LocalLoadOperator &&

@ -22,9 +22,9 @@ package jode;
public interface LocalVarOperator { public interface LocalVarOperator {
public boolean isRead(); public boolean isRead();
public boolean isWrite(); public boolean isWrite();
public int getSlot(); // public int getSlot();
public LocalInfo getLocalInfo(); 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$ * $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 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; Operator op;
Expression exprs[]; Expression exprs[];
int params; 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 { try {
op = (Operator) block.getInstruction(); SequentialBlock sequBlock;
block = flow.lastModified;
op = (Operator) ((InstructionContainer)block).getInstruction();
params = op.getOperandCount(); params = op.getOperandCount();
exprs = new Expression[params]; exprs = new Expression[params];
for (int i = params-1; i>=0; i--) { for (int i = params-1; i>=0; i--) {
block = block.getSimpleUniquePredecessor(); sequBlock = (SequentialBlock)block.outer;
exprs[i] = (Expression) ih.getInstruction(); 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 (exprs[i].isVoid()) {
if (i == params-1) if (i == params-1)
return null; return false;
Expression e = exprs[i+1].tryToCombine(exprs[i]); Expression e = exprs[i+1].tryToCombine(exprs[i]);
if (e == null) if (e == null)
return null; return false;
i++; i++;
SequentialBlock subExprBlock =
(SequentialBlock) sequBlock.getSubBlocks()[1];
subExprBlock.replace(sequBlock);
sequBlock = subExprBlock;
((InstructionContainer)subExprBlock.getSubBlocks()[0]).
setInstruction(e);
exprs[i] = e; exprs[i] = e;
ih = ih.combine(2, e);
} }
block = sequBlock;
} }
} catch (NullPointerException ex) { } catch (NullPointerException ex) {
return null; return false;
} catch (ClassCastException ex) { } catch (ClassCastException ex) {
return null; return false;
} }
if(Decompiler.isVerbose && params > 0) if(jode.Decompiler.isVerbose && params > 0)
System.err.print("x"); 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; package jode.flow;
import jode.TabbedPrintWriter;
/** /**
* This is the structured block for an empty block. * This is the structured block for an empty block.
*/ */
public class EmptyBlock extends StructuredBlock { public class EmptyBlock extends StructuredBlock {
Instruction instr; public EmptyBlock() {
}
SimpleInstruction(Instruction instr) { public EmptyBlock(Jump jump) {
in = new Vector(); setJump(jump);
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 void dumpSource(TabbedPrintWriter writer) public void dumpInstruction(TabbedPrintWriter writer)
throws java.io.IOException throws java.io.IOException
{ {
writer.println("/* empty */"); writer.println("/* empty */");

@ -17,6 +17,7 @@
*/ */
package jode.flow; package jode.flow;
import jode.TabbedPrintWriter;
/** /**
* A FinallyBlock represents the instructions and try catch regions * 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. * 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; 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 * A flow block is the structure of which the flow graph consists. A
@ -30,12 +33,24 @@ package jode.flow;
*/ */
public class FlowBlock { 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 * The starting address of this flow block. This is mainly used
* to produce the source code in code order. * to produce the source code in code order.
*/ */
int addr; int addr;
/**
* The length of the structured block, only needed at the beginning.
*/
int length;
/** /**
* The outermost structructed block in this flow block. * The outermost structructed block in this flow block.
*/ */
@ -57,6 +72,25 @@ public class FlowBlock {
* moved into the preceding flow block. * moved into the preceding flow block.
*/ */
Vector predecessors; 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. * This method optimizes the jumps to successor.
@ -65,109 +99,188 @@ public class FlowBlock {
public StructuredBlock optimizeJumps(FlowBlock successor, public StructuredBlock optimizeJumps(FlowBlock successor,
StructuredBlock appendBlock) { StructuredBlock appendBlock) {
Enumeration enum = successors.elements(); Enumeration enum = successors.elements();
next_jump:
while (enum.hasMoreElements()) { while (enum.hasMoreElements()) {
Jump jump = (Jump) enum.nextElement(); Jump jump = (Jump) enum.nextElement();
if (jump == null || jump.destination != successor) 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 the jump is the jump of the appendBlock, skip it.
*/ */
if (jump == appendBlock.jump) if (jump.prev == appendBlock)
continue; continue next_jump;
/* Note: jump.parent.outer != null, since appendBlock is /* Note: jump.prev.outer != null, since appendBlock is
* an outer block of jump.parent * an outer block of jump.prev
*/ */
/* remove all jumps to the successor which have the successor /* remove all jumps to the successor which have the successor
* as getNextFlowBlock(). */ * as getNextFlowBlock().
if (jump.parent.outer.getNextFlowBlock(jump.parent) == successor) */
jump.parent.removeJump(); if (jump.prev.outer.getNextFlowBlock(jump.prev) == successor) {
jump.prev.removeJump();
continue next_jump;
}
/* replace all conditional jumps to the successor, which /* replace all conditional jumps to the successor, which
* are followed by a block which has the end of the block * are followed by a block which has the end of the block
* as normal successor, with "if (not condition) block". * as normal successor, with "if (not condition) block".
*/ */
if (jump.parent instanceof ConditionalBlock && if (jump.prev instanceof EmptyBlock &&
jump.parent.outer instanceof SequentialBlock && jump.prev.outer instanceof ConditionalBlock) {
jump.parent.outer.getSubBlocks()[0] = jump.parent &&
jump.parent.outer.getNextFlowBlock() == successor) {
ConditionalBlock cb = (ConditionalBlock) jump.parent; StructuredBlock prev = jump.prev;
cb.removeJump(); ConditionalBlock cb = (ConditionalBlock) prev.outer;
jode.Instruction instr = cb.getInstruction();
SequentialBlock sequBlock =
(SequentialBlock) cb.outer;
IfThenElseBlock newIfBlock = if ((cb == appendBlock ||
new IfThenElseBlock(cb.getCondition().negate(), cb.outer.getNextFlowBlock(cb) == successor
sequBlock.getSubBlocks()[1], null); /*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) /* cb.outer is not null,
appendBlock = newIfBlock; * since appendBlock outers cb */
continue;
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 /* if the successor is the dummy return instruction, replace all
* jumps with a return. * jumps with a return.
*/ */
if (successor.block.instanceof ReturnBlock) { if (successor == END_OF_METHOD) {
SequentialBlock sequBlock = new SequentialBlock(); SequentialBlock sequBlock = new SequentialBlock();
StructuredBlock prevBlock = jump.parent; StructuredBlock prevBlock = jump.prev;
prevBlock.removeJump(); prevBlock.removeJump();
sequBlock.replace(prevBlock); sequBlock.replace(prevBlock);
sequBlock.setFirst(prevBlock); sequBlock.setFirst(prevBlock);
sequBlock.setSecond(new ReturnBlock()); sequBlock.setSecond(new ReturnBlock());
continue; continue next_jump;
} }
/* If this is a conditional jump, the first instruction of /* If this is a conditional jump, the first instruction of
* a while and the condition of the while is true, use * a while and the condition of the while is true, use
* the condition as while condition. * the condition as while condition.
*/ */
if (jump.prev instanceof EmptyBlock &&
/* This is the first instruction in a while block */ jump.prev.outer instanceof ConditionalBlock &&
if (jump.parent instanceof ConditionalBlock && jump.prev.outer.jump == null) {
jump.parent.outer instanceof SequentialBlock &&
jump.parent.outer.getSubBlocks()[0] == this && StructuredBlock prev = jump.prev;
jump.parent.outer.outer instanceof LoopBlock) { ConditionalBlock cb = (ConditionalBlock) prev.outer;
ConditionalBlock cb = (ConditionalBlock) jump.parent; jode.Instruction instr = cb.getInstruction();
LoopBlock loopBlock = (LoopBlock) cb.outer.outer;
if (loopBlock.getCondition() == LoopBlock.TRUE && /* This is the first instruction in a while block */
loopBlock.getType() != LoopBlock.DOWHILE && if (cb.outer instanceof SequentialBlock &&
loopBlock.getNextFlowBlock() == successor) { cb.outer.getSubBlocks()[0] == cb &&
cb.outer.outer instanceof LoopBlock) {
cb.removeJump();
loopBlock.setCondition(cb); LoopBlock loopBlock = (LoopBlock) cb.outer.outer;
cb.outer.getSubBlocks()[1].replace(cb.outer); if (loopBlock.getCondition() == LoopBlock.TRUE &&
/* cb and cb.outer are not used any more */ loopBlock.getType() != LoopBlock.DOWHILE &&
/* Note that cb.outer != appendBlock because loopBlock.getNextFlowBlock() == successor &&
* appendBlock contains loopBlock 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 /* Now the same for the empty loop. In this case there is
* no sequential block. * no sequential block.
*/ */
if (jump.parent instanceof ConditionalBlock && if (cb.outer instanceof LoopBlock) {
jump.parent.outer instanceof LoopBlock) { LoopBlock loopBlock = (LoopBlock) cb.outer;
ConditionalBlock cb = (ConditionalBlock) jump.parent; if (loopBlock.getCondition() == LoopBlock.TRUE &&
LoopBlock loopBlock = (LoopBlock) cb.outer; loopBlock.getType() != LoopBlock.DOWHILE &&
if (loopBlock.getCondition() == LoopBlock.TRUE && loopBlock.getNextFlowBlock() == successor &&
loopBlock.getType() != LoopBlock.DOWHILE && instr instanceof Expression) {
loopBlock.getNextFlowBlock() == successor) {
prev.removeJump();
cb.removeJump(); loopBlock.setCondition(((Expression)instr).negate());
loopBlock.setCondition(cb);
EmptyBlock empty = new EmptyBlock(); EmptyBlock empty = new EmptyBlock();
empty.replace(cb); empty.replace(cb);
/* cb is not used any more */ /* cb is not used any more */
continue next_jump;
}
} }
} }
/* if there are jumps in a while block or switch block and the /* 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 * while/switch block is followed by a jump to successor or has
* successor as getNextFlowBlock(), replace jump with break to * successor as getNextFlowBlock(), replace jump with break to
@ -178,91 +291,62 @@ public class FlowBlock {
* succesor, so that the above succeeds. * succesor, so that the above succeeds.
*/ */
int breaklevel = 0; int breaklevel = 0;
for (StructuredBlock surrounder = jump.parent.outer; for (StructuredBlock surrounder = jump.prev.outer;
surrounder != null; surrounder = surrounder.outer) { surrounder != null && surrounder != appendBlock.outer;
surrounder = surrounder.outer) {
if (surrounder instanceof BreakableBlock) { if (surrounder instanceof BreakableBlock) {
breaklevel++; breaklevel++;
if (surrounder.getNextFlowBlock() == successor || if (surrounder.getNextFlowBlock() == successor ||
surrounder.jumpMayBeChanged()) { surrounder.jumpMayBeChanged()) {
SequentialBlock sequBlock = new SequentialBlock(); SequentialBlock sequBlock = new SequentialBlock();
StructuredBlock prevBlock = jump.parent; StructuredBlock prevBlock = jump.prev;
if (surrounder.getNextFlowBlock() != successor) { if (surrounder.getNextFlowBlock() != successor)
surrounder.jump = jump; surrounder.moveJump(prevBlock);
prevBlock.jump = null; else
jump.parent = surrounder;
} else {
prevBlock.removeJump(); prevBlock.removeJump();
}
sequBlock.replace(prevBlock); sequBlock.replace(prevBlock);
sequBlock.setFirst(prevBlock); sequBlock.setFirst(prevBlock);
sequBlock.setSecond(new BreakBlock(surrounder, sequBlock.setSecond
breaklevel > 1)); (new BreakBlock((BreakableBlock) surrounder,
continue; breaklevel > 1));
continue next_jump;
} }
} }
} }
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;
}
}
} }
return appendBlock; return appendBlock;
} }
/** /**
* Updates the in/out-Vectors of the structured block of the * Updates the in/out-Vectors of the structured block of the
* successing flow block simultanous to a T1 transformation. * successing flow block simultanous to a T1 transformation.
* @param successor The flow block which is unified with this flow * @param successor The flow block which is unified with this flow
* block. * block.
*/ */
void updateInOut (FlowBlock successor, boolean t1Transformation) { void updateInOut (FlowBlock successor, boolean t1Transformation) {
/* First get the out vectors of all jumps to successor and /* First get the out vectors of all jumps to successor and
* calculate the intersection. * calculate the intersection.
*/ */
VariableSet allOuts = new VariableSet(); VariableSet allOuts = new VariableSet();
VariableSet intersectOut = null; VariableSet intersectOut = null;
Enumeration enum = successors; Enumeration enum = successors.elements();
while (enum.hasMoreElement()) { while (enum.hasMoreElements()) {
Jump jump = (Jump) enum.nextElement(); Jump jump = (Jump) enum.nextElement();
if (jump == null || jump.destination != successor) if (jump == null || jump.destination != successor)
continue; continue;
allOuts.union(jump.parent.out); allOuts.union(jump.prev.out);
if (intersectOut == null) if (intersectOut == null)
intersectOut = jump.parent.out; intersectOut = jump.prev.out;
else else
intersectOut = intersectOut.intersect(jump.parent.out); intersectOut = intersectOut.intersect(jump.prev.out);
} }
/* Now work on each block of the successor */ /* Now work on each block of the successor */
Stack todo = new Stack(); Stack todo = new Stack();
todo.push(successor.block); todo.push(successor.block);
@ -271,7 +355,7 @@ public class FlowBlock {
StructuredBlock[] subBlocks = block.getSubBlocks(); StructuredBlock[] subBlocks = block.getSubBlocks();
for (int i=0; i<subBlocks.length; i++) for (int i=0; i<subBlocks.length; i++)
todo.push(subBlocks[i]); todo.push(subBlocks[i]);
/* Merge the locals used in successing block with those written /* Merge the locals used in successing block with those written
* by this blocks * by this blocks
*/ */
@ -284,7 +368,7 @@ public class FlowBlock {
} }
} }
} }
/* Special cases: /* Special cases:
* *
@ -350,7 +434,12 @@ public class FlowBlock {
* return_n * 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. */ /* search successor with smallest addr. */
Enumeration enum = successors.elements(); Enumeration enum = successors.elements();
FlowBlock succ = null; FlowBlock succ = null;
@ -363,27 +452,78 @@ public class FlowBlock {
succ = fb; succ = fb;
} }
} }
if (succ == null) { return succ;
/* There are no successors at all */ }
return false;
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. */ * Do a T1 transformation with succ if possible. It is possible,
if (succ.predecessors.size() != 1) * 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; return false;
/* First find the innermost block that contains all jumps to this try {
* successor and the last modified block. 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(); Enumeration enum = successors.elements();
StructuredBlock appendBlock = lastModified; StructuredBlock appendBlock = lastModified;
while(enum.hasMoreElements()) { while(enum.hasMoreElements()) {
Jump jump = (Jump) enum.nextElement(); Jump jump = (Jump) enum.nextElement();
if (jump == null || jump.destination != successors) if (jump == null || jump.destination != succ)
continue; continue;
while (!appendBlock.contains(jump.parent)) while (!appendBlock.contains(jump.prev))
appendBlock = appendBlock.outer; appendBlock = appendBlock.outer;
/* appendBlock can't be null now, because the /* appendBlock can't be null now, because the
* outermost block contains every structured block. * outermost block contains every structured block.
@ -391,14 +531,19 @@ public class FlowBlock {
} }
/* Update the in/out-Vectors now */ /* Update the in/out-Vectors now */
updateInOut(successor, true); updateInOut(succ, true);
/* The switch "fall through" case: if the appendBlock is a /* The switch "fall through" case: if the appendBlock is a
* switch, and the successor is the address of a case, and all * switch, and the successor is the address of a case, and all
* other successors are inside the block preceding that case. * other successors are inside the block preceding that case.
*/ */
if (case != null) { StructuredBlock precedingcase = null;
SwitchBlock switchBlock = (StructuredBlock) appendBlock; 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. /* Now put the succ.block into the next case.
*/ */
@ -408,52 +553,120 @@ public class FlowBlock {
/* Do the following modifications on the struct block. */ /* Do the following modifications on the struct block. */
appendBlock = precedingcase; appendBlock = precedingcase;
succ.block.setFlowBlock(this);
} else { } else {
/* Prepare the unification of the blocks: Make sure that /* Prepare the unification of the blocks: Make sure if
* appendBlock has a successor outside of this block. This is * possible that appendBlock has a successor outside of
* always possible, because it contains lastModified. * 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) { if (appendBlock.jump == null) {
/* assert(appendBlock.jump.getNextFlowBlock() != null) */ Jump jump = new Jump(succ);
appendBlock.setJump(appendBlock.getNextFlowBlock()); appendBlock.setJump(jump);
successors.addElement(jump);
} }
/* Now unify the blocks: Create a new SequentialBlock /* Now unify the blocks: Create a new SequentialBlock
* containing appendBlock and successor.block. Then replace * containing appendBlock and successor.block. Then replace
* appendBlock with the new sequential block. * appendBlock with the new sequential block.
*/ */
StructuredBlock outer = appendBlock.outer; SequentialBlock sequBlock =
StructuredBlock sequBlock = new SequentialBlock();
new SequentialBlock(appendBlock, switchBlock); sequBlock.replace(appendBlock);
outer.replaceSubBlock(appendBlock, sequBlock); sequBlock.setFirst(appendBlock);
sequBlock.outer = outer; 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. /* Now remove the jump of the appendBlock if it points to successor.
*/ */
if (appendBlock.jump != null &&
if (appendBlock.jump == succ) appendBlock.jump.destination == succ)
appendBlock.removeJump(); appendBlock.removeJump();
/* If there are further jumps, put a do/while(0) block around /* If there are further jumps, put a do/while(0) block around
* appendBlock and replace every remaining jump with a break * appendBlock and replace every remaining jump with a break
* to the do/while block. * to the do/while block.
*/ */
LoopBlock doWhileFalse = null;
/* Merge the sucessors from the successing flow block enum = successors.elements();
*/
enum = succ.successors.elements();
while (enum.hasMoreElements()) { 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 /* Believe it or not: Now the rule, that the first part of a
* SequentialBlock shouldn't be another SequentialBlock is * SequentialBlock shouldn't be another SequentialBlock is
* fulfilled. <p> * fulfilled. <p>
@ -466,6 +679,22 @@ public class FlowBlock {
/* Set last modified to correct value. */ /* Set last modified to correct value. */
lastModified = succ.lastModified; 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() { public boolean doT2() {
@ -474,9 +703,21 @@ public class FlowBlock {
* considered yet, return false. The second condition make * considered yet, return false. The second condition make
* sure that the while isn't created up to the first continue. * 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 */ /* 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 /* If there is only one jump to the beginning and it is the
* last jump and (there is a do/while(0) block surrounding * 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 * do/while(0) with a for(;;last_instr) resp. create a new one
* and replace breaks to do/while with continue to for. * and replace breaks to do/while with continue to for.
*/ */
/* XXX implement above */
/* XXX condition for do/while(cond) blocks */
{ {
/* Otherwise: */ /* Otherwise: */
/* create a new while(true) block. /* 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. /* 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. /* 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 /* if there are further jumps to this, replace every jump with a
* continue to while block and return true. * 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) { public void removeSuccessor(Jump jump) {
successors.setElementAt(null, successors.indexOf(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$ * $Id$
*/ */
package jode.flow; package jode.flow;
import jode.Instruction;
import jode.TabbedPrintWriter;
/** /**
* An IfThenElseBlock is the structured block representing an if * An IfThenElseBlock is the structured block representing an if
@ -53,6 +55,7 @@ public class IfThenElseBlock extends StructuredBlock {
public void setThenBlock(StructuredBlock thenBlock) { public void setThenBlock(StructuredBlock thenBlock) {
this.thenBlock = thenBlock; this.thenBlock = thenBlock;
thenBlock.outer = this; thenBlock.outer = this;
thenBlock.setFlowBlock(flowBlock);
} }
/** /**
@ -62,6 +65,7 @@ public class IfThenElseBlock extends StructuredBlock {
public void setElseBlock(StructuredBlock elseBlock) { public void setElseBlock(StructuredBlock elseBlock) {
this.elseBlock = elseBlock; this.elseBlock = elseBlock;
elseBlock.outer = this; elseBlock.outer = this;
elseBlock.setFlowBlock(flowBlock);
} }
/* The implementation of getNext[Flow]Block is the standard /* The implementation of getNext[Flow]Block is the standard
@ -73,7 +77,7 @@ public class IfThenElseBlock extends StructuredBlock {
* @param newBlock the new sub block. * @param newBlock the new sub block.
* @return false, if oldBlock wasn't a direct sub block. * @return false, if oldBlock wasn't a direct sub block.
*/ */
boolean replaceSubBlock(StructuredBlock oldBlock, public boolean replaceSubBlock(StructuredBlock oldBlock,
StructuredBlock newBlock) { StructuredBlock newBlock) {
if (thenBlock == oldBlock) if (thenBlock == oldBlock)
thenBlock = newBlock; thenBlock = newBlock;
@ -89,21 +93,28 @@ public class IfThenElseBlock extends StructuredBlock {
* called only once, because it remembers which local variables * called only once, because it remembers which local variables
* were declared. * were declared.
*/ */
public void dumpSource(TabbedPrintWriter writer) public void dumpInstruction(TabbedPrintWriter writer)
throws java.io.IOException throws java.io.IOException
{ {
boolean needBrace = ! (thenBlock instanceof InstructionBlock); boolean needBrace = ! (thenBlock instanceof InstructionBlock);
writer.println("if ("+cond.toString()+")"+needBrace?" {":""); writer.println("if ("+cond.toString()+")"+(needBrace?" {":""));
writer.tab(); writer.tab();
thenBlock.dumpSource(writer); thenBlock.dumpSource(writer);
writer.untab(); writer.untab();
if (elseBlock != null) { if (elseBlock != null) {
writer.print(needBrace?"} ":""); writer.print(needBrace ? "} " : "");
needBrace = ! (thenBlock instanceof InstructionBlock); if (elseBlock instanceof IfThenElseBlock
writer.println("else"+needBrace?" {":""); /* XXX && No variables are declared XXX*/) {
writer.tab(); needBrace = false;
elseBlock.dumpSource(writer); writer.print("else ");
writer.untab(); elseBlock.dumpSource(writer);
} else {
needBrace = ! (elseBlock instanceof InstructionBlock);
writer.println("else" + (needBrace ? " {" : ""));
writer.tab();
elseBlock.dumpSource(writer);
writer.untab();
}
} }
if (needBrace) if (needBrace)
writer.println("}"); writer.println("}");
@ -112,12 +123,12 @@ public class IfThenElseBlock extends StructuredBlock {
/** /**
* Returns all sub block of this structured block. * Returns all sub block of this structured block.
*/ */
StructuredBlock[] getSubBlocks() { public StructuredBlock[] getSubBlocks() {
if (elseBlock == null) { if (elseBlock == null) {
StructuredBlock result = { thenBlock }; StructuredBlock[] result = { thenBlock };
return result; return result;
} else { } else {
StructuredBlock result = { thenBlock, elseBlock }; StructuredBlock[] result = { thenBlock, elseBlock };
return result; return result;
} }
} }
@ -132,7 +143,7 @@ public class IfThenElseBlock extends StructuredBlock {
return false; return false;
if (elseBlock != null && elseBlock.jump == null && if (elseBlock != null && elseBlock.jump == null &&
!elseBlock.jumpMayBeChanged) !elseBlock.jumpMayBeChanged())
return false; return false;
return true; return true;
} }

@ -16,33 +16,52 @@
* $Id$ * $Id$
*/ */
package jode.flow; package jode.flow;
import jode.*;
/** /**
* This is the structured block for atomic instructions. * This is the structured block for atomic instructions.
*/ */
public class InstructionBlock extends StructuredBlock { public class InstructionBlock extends StructuredBlock
implements InstructionContainer {
Instruction instr; Instruction instr;
InstructionBlock(Instruction instr) { public InstructionBlock(Instruction instr) {
in = new Vector();
out = new Vector();
this.instr = instr; this.instr = instr;
if (instr instanceof LocalVarOperator) { if (instr instanceof LocalVarOperator) {
LocalVarOperator varOp = (LocalVarOperator) instr; LocalVarOperator varOp = (LocalVarOperator) instr;
if (varOp.isRead()) if (varOp.isRead()) {
in.addElement(varOp.getLocalInfo()); 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 throws java.io.IOException
{ {
if (!(instr instanceof NopOperator)) { if (instr.getType() != MyType.tVoid)
if (instr.getType() != MyType.tVoid) writer.print("push ");
writer.print("push "); writer.println(instr.toString()+";");
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. * The structured block that precedes this jump.
*/ */
StructuredBlock prev; StructuredBlock prev;
/**
* The flow block, where this jump lies in
*/
FlowBlock parent;
/** /**
* The destination block of this jump. * The destination block of this jump.
*/ */
FlowBlock destination; 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. * Returns true if this jump has jsr or monitorexit attachments.
*/ */
boolean hasAttachments() { 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; package jode.flow;
import jode.TabbedPrintWriter;
/** /**
* A RawTryCatchBlock is created for each exception in the * A RawTryCatchBlock is created for each exception in the
@ -39,7 +40,7 @@ package jode.flow;
* @see SynchronizedBlock * @see SynchronizedBlock
*/ */
public RawTryCatchBlock extends StructuredBlock { public class RawTryCatchBlock extends StructuredBlock {
/** /**
* An unconditional jump to the EndBlock. * 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 * The type of the exception that is catched. This is null for a
* synchronized/finally block * 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$ * $Id$
*/ */
package jode.flow; package jode.flow;
import jode.TabbedPrintWriter;
/** /**
* A sequential block combines exactly two structured blocks to a new * 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 * condition is temporarily violated, while the t1 transformation is
* done. * done.
*/ */
public class SequentialBlock { public class SequentialBlock extends StructuredBlock {
StructuredBlock[] subBlocks; StructuredBlock[] subBlocks;
public SequentialBlock() { public SequentialBlock() {
subBlocks = new StructuredBlock[2]; subBlocks = new StructuredBlock[2];
} }
public setFirst(StructuredBlock sb) { public void setFirst(StructuredBlock sb) {
subBlocks[0] = sb; subBlocks[0] = sb;
sb.outer = this; sb.outer = this;
sb.setFlowBlock(flowBlock);
} }
public setSecond(StructuredBlock sb) { public void setSecond(StructuredBlock sb) {
subBlocks[1] = sb; subBlocks[1] = sb;
sb.outer = this; sb.outer = this;
sb.setFlowBlock(flowBlock);
} }
/** /**
@ -48,25 +51,32 @@ public class SequentialBlock {
* SwitchBlock). If this isn't called with a direct sub block, * SwitchBlock). If this isn't called with a direct sub block,
* the behaviour is undefined, so take care. * the behaviour is undefined, so take care.
* @return null, if the control flows to another FlowBlock. */ * @return null, if the control flows to another FlowBlock. */
StructuredBlock getNextBlock(StructuredBlock subBlock) { public StructuredBlock getNextBlock(StructuredBlock subBlock) {
if (subBlock == subBlocks[0]) if (subBlock == subBlocks[0])
return subBlocks[1]; return subBlocks[1];
return getNextBlock(); return getNextBlock();
} }
FlowBlock getNextFlowBlock(StructuredBlock subBlock) { public FlowBlock getNextFlowBlock(StructuredBlock subBlock) {
if (subBlock == subBlocks[0]) if (subBlock == subBlocks[0])
return null; return null;
return getNextFlowBlock(); 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. * Replaces the given sub block with a new block.
* @param oldBlock the old sub block. * @param oldBlock the old sub block.
* @param newBlock the new sub block. * @param newBlock the new sub block.
* @return false, if oldBlock wasn't a direct sub block. * @return false, if oldBlock wasn't a direct sub block.
*/ */
boolean replaceSubBlock(StructuredBlock oldBlock, public boolean replaceSubBlock(StructuredBlock oldBlock,
StructuredBlock newBlock) { StructuredBlock newBlock) {
for (int i=0; i<2; i++) { for (int i=0; i<2; i++) {
if (subBlocks[i] == oldBlock) { if (subBlocks[i] == oldBlock) {
@ -80,7 +90,7 @@ public class SequentialBlock {
/** /**
* Returns all sub block of this structured block. * Returns all sub block of this structured block.
*/ */
StructuredBlock[] getSubBlocks() { public StructuredBlock[] getSubBlocks() {
return subBlocks; return subBlocks;
} }
@ -93,7 +103,3 @@ public class SequentialBlock {
return (subBlocks[1].jump != null || subBlocks[1].jumpMayBeChanged()); return (subBlocks[1].jump != null || subBlocks[1].jumpMayBeChanged());
} }
} }

@ -18,6 +18,7 @@
*/ */
package jode.flow; package jode.flow;
import jode.TabbedPrintWriter;
/** /**
* A structured block is the building block of the source programm. * A structured block is the building block of the source programm.
@ -49,8 +50,8 @@ package jode.flow;
public abstract class StructuredBlock { public abstract class StructuredBlock {
/* Invariants: /* Invariants:
* in.intersection(out) = empty * in.intersection(out) = empty
* outer != null => flowblock = outer.flowblock * outer != null => flowBlock = outer.flowBlock
* outer == null => flowblock.block = this * outer == null => flowBlock.block = this
* jump == null => outer != null * jump == null => outer != null
* either getNextBlock() != null * either getNextBlock() != null
* or getNextFlowBlock() != null or outer == 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 * path from the start of the current flow block, on which the
* local variable is never assigned * local variable is never assigned
*/ */
VariableSet in; VariableSet in = new VariableSet();
/** /**
* The out locals. This are the locals, which must be overwritten * 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 * structured block contain a (unconditional) assignment to this
* local * local
*/ */
VariableSet out; VariableSet out = new VariableSet();
/** /**
* The variable set containing all variables that must be defined * The variable set containing all variables that must be defined
* in this block (or maybe an outer block, this changes as the * in this block (or maybe an outer block, this changes as the
* blocks are put together). * blocks are put together).
*/ */
VariableSet defineHere; VariableSet defineHere = new VariableSet();
/** /**
* The surrounding structured block. If this is the outermost * 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. * 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 * 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 * Returns the block where the control will normally flow to, when
* this block is finished (not ignoring the jump after this block). * this block is finished (not ignoring the jump after this block).
*/ */
StructuredBlock getNextBlock() { public StructuredBlock getNextBlock() {
if (jump != null) if (jump != null)
return null; return null;
if (outer != null) if (outer != null)
outer.getNextBlock(this); return outer.getNextBlock(this);
else return null;
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 * @return null, if the control flows into a non empty structured
* block or if this is the outermost block. * block or if this is the outermost block.
*/ */
FlowBlock getNextFlowBlock() { public FlowBlock getNextFlowBlock() {
if (jump != null) if (jump != null)
return jump.destination; return jump.destination;
if (outer != null) if (outer != null)
outer.getNextFlowBlock(this); return outer.getNextFlowBlock(this);
else return null;
return null;
} }
/** /**
@ -135,13 +139,12 @@ public abstract class StructuredBlock {
* @return null, if everything is okay, and a diagnostic message that * @return null, if everything is okay, and a diagnostic message that
* should be put in a comment otherwise. * should be put in a comment otherwise.
*/ */
String checkJump(Jump jump) { public String checkJump(Jump jump) {
if (outer != null) if (outer != null)
return outer.checkJump(jump); return outer.checkJump(jump);
else if (jump.hasAttachments()) if (jump.hasAttachments())
return "Unknown attachments: "+jump.describeAttachments() return "Unknown attachments: "+jump.describeAttachments();
else return null;
return null;
} }
/** /**
@ -151,11 +154,11 @@ public abstract class StructuredBlock {
* SwitchBlock). If this isn't called with a direct sub block, * SwitchBlock). If this isn't called with a direct sub block,
* the behaviour is undefined, so take care. * the behaviour is undefined, so take care.
* @return null, if the control flows to another FlowBlock. */ * @return null, if the control flows to another FlowBlock. */
StructuredBlock getNextBlock(StructuredBlock subBlock) { public StructuredBlock getNextBlock(StructuredBlock subBlock) {
return getNextBlock(); return getNextBlock();
} }
FlowBlock getNextFlowBlock(StructuredBlock subBlock) { public FlowBlock getNextFlowBlock(StructuredBlock subBlock) {
return getNextFlowBlock(); return getNextFlowBlock();
} }
@ -165,15 +168,15 @@ public abstract class StructuredBlock {
* @param newBlock the new sub block. * @param newBlock the new sub block.
* @return false, if oldBlock wasn't a direct sub block. * @return false, if oldBlock wasn't a direct sub block.
*/ */
boolean replaceSubBlock(StructuredBlock oldBlock, public boolean replaceSubBlock(StructuredBlock oldBlock,
StructuredBlock newBlock) { StructuredBlock newBlock) {
return false; return false;
} }
/** /**
* Returns all sub block of this structured block. * Returns all sub block of this structured block.
*/ */
StructuredBlock[] getSubBlocks() { public StructuredBlock[] getSubBlocks() {
return new StructuredBlock[0]; return new StructuredBlock[0];
} }
@ -182,19 +185,21 @@ public abstract class StructuredBlock {
* @param child the block which should be contained by this block. * @param child the block which should be contained by this block.
* @return false, if child is null, or is not contained in 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) while (child != this && child != null)
child = child.outer; child = child.outer;
return (child == this); return (child == this);
} }
/** /**
* Removes the jump after this structured block. This does also update * Removes the given jump if it is our jump. This does also
* the successors vector of the flow block. * update the successors vector of the flow block.
*
* @param jump The jump that should be removed.
*/ */
public void removeJump() { public void removeJump() {
if (jump != null) { if (jump != null) {
jump.prev = null;
flowBlock.removeSuccessor(jump); flowBlock.removeSuccessor(jump);
jump = null; jump = null;
} }
@ -202,24 +207,17 @@ public abstract class StructuredBlock {
/** /**
* This function replaces sb with this block. It copies outer and * This function replaces sb with this block. It copies outer and
* the following jump from sb, and updates them, so they know that * from sb, and updates the outer block, so it knows that sb was
* sb was replaced. * replaced. You have to replace sb.outer or mustn't use sb
* The jump field of sb is removed afterwards. You have to replace * anymore.
* sb.outer or mustn't use sb anymore. * @param sb The structured block that should be replaced. */
* @param sb The structured block that should be replaced.
*/
public void replace(StructuredBlock sb) { public void replace(StructuredBlock sb) {
in = sb.in; in = sb.in;
out = sb.out; out = sb.out;
defineHere = sb.defineHere; defineHere = sb.defineHere;
outer = sb.outer; outer = sb.outer;
flowBlock = sb.flowBlock; flowBlock = sb.flowBlock;
jump = sb.jump;
if (jump != null) {
jump.parent = this;
sb.jump = null;
}
if (outer != null) { if (outer != null) {
outer.replaceSubBlock(sb, this); outer.replaceSubBlock(sb, this);
} else { } 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 * 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. * of this block. If this returns true, you know that jump is null.
@ -236,25 +247,78 @@ public abstract class StructuredBlock {
return false; 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 * Set the flow block of this block and all sub blocks.
* @return the predecessor or null if there isn't a such a thing * @param flowBlock the new flow block
*/ */
public StructuredBlock getSimpleUniquePredecessor() { public void setFlowBlock(FlowBlock flowBlock) {
SequentialBlock sequ; if (this.flowBlock != flowBlock) {
if (outer instanceof SequentialBlock) { this.flowBlock = flowBlock;
if (outer.getSubBlocks()[1] == this) StructuredBlock[] subs = getSubBlocks();
return outer.getSubBlocks()[0]; for (int i=0; i<subs.length; i++) {
else if (outer.outer instanceof SequentialBlock) subs[i].setFlowBlock(flowBlock);
return outer.outer.getSubBlocks[0]; }
}
}
/**
* 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 * Print the source code for this structured block. This handles
* called only once, because it remembers which local variables * everything that is unique for all structured blocks and calls
* were declared. */ * dumpInstruction afterwards.
public abstract void dumpSource(TabbedPrintWriter writer) * @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; 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$ * $Id$
*/ */
package jode.Flow; package jode.flow;
import jode.LocalInfo;
/** /**
* This class represents a set of Variables, which are mainly used in * 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. * Adds a local variable to the variable set.
* @param li The local variable of type LocalInfo. * @param li The local variable of type LocalInfo.
*/ */
public addElement(LocalInfo li) { public void addElement(LocalInfo li) {
super.addElement((Object)li); super.addElement((Object)li);
} }
@ -54,7 +55,7 @@ public class VariableSet extends java.util.Vector {
LocalInfo li1 = ((LocalInfo) elementData[i]).getLocalInfo(); LocalInfo li1 = ((LocalInfo) elementData[i]).getLocalInfo();
for (int j=0; j<vs.elementCount; j++) { for (int j=0; j<vs.elementCount; j++) {
LocalInfo li2 = ((LocalInfo) vs.elementData[j]).getLocalInfo(); LocalInfo li2 = ((LocalInfo) vs.elementData[j]).getLocalInfo();
if (li1.getSlot() = li2.getSlot()) { if (li1.getSlot() == li2.getSlot()) {
li1.combineWith(li2); li1.combineWith(li2);
} }
} }
@ -72,7 +73,7 @@ public class VariableSet extends java.util.Vector {
LocalInfo li1 = ((LocalInfo) elementData[i]).getLocalInfo(); LocalInfo li1 = ((LocalInfo) elementData[i]).getLocalInfo();
for (int j=0; j<vs.elementCount; j++) { for (int j=0; j<vs.elementCount; j++) {
LocalInfo li2 = ((LocalInfo) vs.elementData[j]).getLocalInfo(); LocalInfo li2 = ((LocalInfo) vs.elementData[j]).getLocalInfo();
if (li1.getSlot() = li2.getSlot()) { if (li1.getSlot() == li2.getSlot()) {
if (!intersection.contains(li1)) if (!intersection.contains(li1))
intersection.addElement(li1); intersection.addElement(li1);
if (!intersection.contains(li2)) 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 * Add the other variable set to the current, except when the slot
* is already in the current set. * is already in the current set.
*/ */
public void union(VariableSet vs) { public void add(VariableSet vs) {
int oldSize = elementCount; int oldSize = elementCount;
iloop: iloop:
for (int i=0; i< vs.elementCount; i++) { 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. /* We count from top to bottom to have easier reorganization.
* Note, that the variables have not to be in any particular * Note, that the variables have not to be in any particular
* order. */ * order. */
int newCount = elementCount int newCount = elementCount;
for (int i=newCount-1; i>=0; i--) { for (int i=newCount-1; i>=0; i--) {
LocalInfo li1 = (LocalInfo) elementData[i]; LocalInfo li1 = (LocalInfo) elementData[i];
for (int j=0; j<vs.elementCount; j++) { for (int j=0; j<vs.elementCount; j++) {

Loading…
Cancel
Save