*** empty log message ***

git-svn-id: https://svn.code.sf.net/p/jode/code/trunk@38 379699f6-c40d-0410-875b-85095c16579e
stable
jochen 27 years ago
parent d5131c70be
commit d2f597be45
  1. 6
      jode/jode/Decompiler.java
  2. 191
      jode/jode/bytecode/Opcodes.java
  3. 3
      jode/jode/decompiler/CodeAnalyzer.java
  4. 5
      jode/jode/decompiler/LocalVariableTable.java
  5. 25
      jode/jode/expr/Expression.java
  6. 4
      jode/jode/flow/BreakBlock.java
  7. 46
      jode/jode/flow/BreakableBlock.java
  8. 65
      jode/jode/flow/FlowBlock.java
  9. 46
      jode/jode/flow/LoopBlock.java
  10. 16
      jode/jode/flow/SequentialBlock.java
  11. 18
      jode/jode/flow/StructuredBlock.java
  12. 150
      jode/jode/flow/SwitchBlock.java
  13. 20
      jode/jode/type/ClassRangeType.java
  14. 2
      jode/jode/type/MyType.java

@ -24,6 +24,8 @@ import java.lang.reflect.Modifier;
public class Decompiler {
public static boolean isVerbose = false;
public static boolean isDebugging = false;
public static boolean isTypeDebugging = false;
public static boolean showLVT = false;
public static void main(String[] params) {
JodeEnvironment env = new JodeEnvironment();
@ -32,6 +34,10 @@ public class Decompiler {
isVerbose = true;
else if (params[i].equals("-debug"))
isDebugging = true;
else if (params[i].equals("-type"))
isTypeDebugging = true;
else if (params[i].equals("-lvt"))
showLVT = true;
else
env.doClass(params[i]);
}

@ -48,40 +48,65 @@ public abstract class Opcodes implements RuntimeConstants {
};
public static FlowBlock createNormal(int addr, int length,
public static FlowBlock createNormal(CodeAnalyzer ca,
int addr, int length,
Instruction instr)
{
return new FlowBlock(addr, length,
return new FlowBlock(ca, addr, length,
new InstructionBlock(instr,
new Jump(addr+length)));
}
public static FlowBlock createGoto(int addr, int length,
public static FlowBlock createGoto(CodeAnalyzer ca,
int addr, int length,
int destAddr)
{
return new FlowBlock(addr, length, new EmptyBlock(new Jump(destAddr)));
return new FlowBlock(ca, addr, length,
new EmptyBlock(new Jump(destAddr)));
}
public static FlowBlock createIfGoto(int addr, int length,
public static FlowBlock createJsr(CodeAnalyzer ca,
int addr, int length,
int destAddr)
{
return new FlowBlock(ca, addr, length,
new JsrBlock(new Jump(addr+length),
new Jump(destAddr)));
}
public static FlowBlock createIfGoto(CodeAnalyzer ca,
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);
return new FlowBlock(ca, addr, length, ifBlock);
}
public static FlowBlock createSwitch(int addr, int length,
public static FlowBlock createSwitch(CodeAnalyzer ca,
int addr, int length,
int[] cases, int[] dests)
{
return new FlowBlock(addr, length, new SwitchBlock(cases, dests));
return new FlowBlock(ca, addr, length,
new SwitchBlock(new NopOperator(MyType.tInt),
cases, dests));
}
public static FlowBlock createBlock(int addr, int length,
public static FlowBlock createBlock(CodeAnalyzer ca,
int addr, int length,
StructuredBlock block)
{
return new FlowBlock(addr, length, block);
return new FlowBlock(ca, addr, length, block);
}
public static FlowBlock createRet(CodeAnalyzer ca,
int addr, int length,
LocalInfo local)
{
return new FlowBlock(ca, addr, length,
new RetBlock(local));
}
/**
@ -103,43 +128,43 @@ public abstract class Opcodes implements RuntimeConstants {
int opcode = stream.readUnsignedByte();
switch (opcode) {
case opc_nop:
return createNormal(addr, 1, new NopOperator());
return createNormal(ca, addr, 1, new NopOperator());
case opc_aconst_null:
return createNormal
(addr, 1, new ConstOperator(OBJECT_TYPE, "null"));
(ca, addr, 1, new ConstOperator(OBJECT_TYPE, "null"));
case opc_iconst_m1:
case opc_iconst_0: case opc_iconst_1: case opc_iconst_2:
case opc_iconst_3: case opc_iconst_4: case opc_iconst_5:
return createNormal
(addr, 1, new ConstOperator
(ca, addr, 1, new ConstOperator
(ALL_INT_TYPE, Integer.toString(opcode - opc_iconst_0)));
case opc_lconst_0: case opc_lconst_1:
return createNormal
(addr, 1, new ConstOperator
(ca, addr, 1, new ConstOperator
(LONG_TYPE,
Integer.toString(opcode - opc_lconst_0) + "L"));
case opc_fconst_0: case opc_fconst_1: case opc_fconst_2:
return createNormal
(addr, 1, new ConstOperator
(ca, addr, 1, new ConstOperator
(FLOAT_TYPE,
Integer.toString(opcode - opc_fconst_0) + ".0F"));
case opc_dconst_0: case opc_dconst_1:
return createNormal
(addr, 1, new ConstOperator
(ca, addr, 1, new ConstOperator
(DOUBLE_TYPE,
Integer.toString(opcode - opc_dconst_0) + ".0"));
case opc_bipush:
return createNormal
(addr, 2, new ConstOperator
(ca, addr, 2, new ConstOperator
(ALL_INT_TYPE, Integer.toString(stream.readByte())));
case opc_sipush:
return createNormal
(addr, 3, new ConstOperator
(ca, addr, 3, new ConstOperator
(ALL_INT_TYPE, Integer.toString(stream.readShort())));
case opc_ldc: {
int index = stream.readUnsignedByte();
return createNormal
(addr, 2, new ConstOperator
(ca, addr, 2, new ConstOperator
(ca.env.getConstantType(index),
ca.env.getConstant(index).toString()));
}
@ -147,14 +172,14 @@ public abstract class Opcodes implements RuntimeConstants {
case opc_ldc2_w: {
int index = stream.readUnsignedShort();
return createNormal
(addr, 3, new ConstOperator
(ca, addr, 3, new ConstOperator
(ca.env.getConstantType(index),
ca.env.getConstant(index).toString()));
}
case opc_iload: case opc_lload:
case opc_fload: case opc_dload: case opc_aload:
return createNormal
(addr, 2, new LocalLoadOperator
(ca, addr, 2, new LocalLoadOperator
(types[0][opcode-opc_iload],
ca.getLocalInfo(addr, stream.readUnsignedByte())));
case opc_iload_0: case opc_iload_1: case opc_iload_2: case opc_iload_3:
@ -163,19 +188,19 @@ public abstract class Opcodes implements RuntimeConstants {
case opc_dload_0: case opc_dload_1: case opc_dload_2: case opc_dload_3:
case opc_aload_0: case opc_aload_1: case opc_aload_2: case opc_aload_3:
return createNormal
(addr, 1, new LocalLoadOperator
(ca, addr, 1, new LocalLoadOperator
(types[0][(opcode-opc_iload_0)/4],
ca.getLocalInfo(addr, (opcode-opc_iload_0) & 3)));
case opc_iaload: case opc_laload:
case opc_faload: case opc_daload: case opc_aaload:
case opc_baload: case opc_caload: case opc_saload:
return createNormal
(addr, 1, new ArrayLoadOperator
(ca, addr, 1, new ArrayLoadOperator
(types[1][opcode - opc_iaload]));
case opc_istore: case opc_lstore:
case opc_fstore: case opc_dstore: case opc_astore:
return createNormal
(addr, 2, new LocalStoreOperator
(ca, addr, 2, new LocalStoreOperator
(types[0][opcode-opc_istore],
ca.getLocalInfo(addr, stream.readUnsignedByte()),
Operator.ASSIGN_OP));
@ -190,7 +215,7 @@ public abstract class Opcodes implements RuntimeConstants {
case opc_astore_0: case opc_astore_1:
case opc_astore_2: case opc_astore_3:
return createNormal
(addr, 1, new LocalStoreOperator
(ca, addr, 1, new LocalStoreOperator
(types[0][(opcode-opc_istore_0)/4],
ca.getLocalInfo(addr, (opcode-opc_istore_0) & 3),
Operator.ASSIGN_OP));
@ -198,43 +223,43 @@ public abstract class Opcodes implements RuntimeConstants {
case opc_fastore: case opc_dastore: case opc_aastore:
case opc_bastore: case opc_castore: case opc_sastore:
return createNormal
(addr, 1, new ArrayStoreOperator
(ca, addr, 1, new ArrayStoreOperator
(types[1][opcode - opc_iastore]));
case opc_pop: case opc_pop2:
return createNormal
(addr, 1, new PopOperator(opcode - opc_pop + 1));
(ca, addr, 1, new PopOperator(opcode - opc_pop + 1));
case opc_dup: case opc_dup_x1: case opc_dup_x2:
case opc_dup2: case opc_dup2_x1: case opc_dup2_x2:
return createNormal
(addr, 1, new DupOperator
(ca, addr, 1, new DupOperator
((opcode - opc_dup)%3, (opcode - opc_dup)/3+1));
case opc_swap:
return createNormal(addr, 1, new SwapOperator());
return createNormal(ca, addr, 1, new SwapOperator());
case opc_iadd: case opc_ladd: case opc_fadd: case opc_dadd:
case opc_isub: case opc_lsub: case opc_fsub: case opc_dsub:
case opc_imul: case opc_lmul: case opc_fmul: case opc_dmul:
case opc_idiv: case opc_ldiv: case opc_fdiv: case opc_ddiv:
case opc_irem: case opc_lrem: case opc_frem: case opc_drem:
return createNormal
(addr, 1, new BinaryOperator
(ca, addr, 1, new BinaryOperator
(types[0][(opcode - opc_iadd)%4],
(opcode - opc_iadd)/4+Operator.ADD_OP));
case opc_ineg: case opc_lneg: case opc_fneg: case opc_dneg:
return createNormal
(addr, 1, new UnaryOperator
(ca, addr, 1, new UnaryOperator
(types[0][opcode - opc_ineg], Operator.NEG_OP));
case opc_ishl: case opc_lshl:
case opc_ishr: case opc_lshr:
case opc_iushr: case opc_lushr:
return createNormal
(addr, 1, new ShiftOperator
(ca, addr, 1, new ShiftOperator
(types[0][(opcode - opc_ishl)%2],
(opcode - opc_ishl)/2 + Operator.SHIFT_OP));
case opc_iand: case opc_land:
case opc_ior : case opc_lor :
case opc_ixor: case opc_lxor:
return createNormal
(addr, 1, new BinaryOperator
(ca, addr, 1, new BinaryOperator
(types[0][(opcode - opc_iand)%2],
(opcode - opc_iand)/2 + Operator.AND_OP));
case opc_iinc: {
@ -247,7 +272,7 @@ public abstract class Opcodes implements RuntimeConstants {
}
LocalInfo li = ca.getLocalInfo(addr, local);
return createNormal
(addr, 3, new IIncOperator
(ca, addr, 3, new IIncOperator
(li, Integer.toString(value),
operation + Operator.OPASSIGN_OP));
}
@ -260,48 +285,46 @@ public abstract class Opcodes implements RuntimeConstants {
if (to >= from)
to++;
return createNormal
(addr, 1, new ConvertOperator(types[0][from],
(ca, addr, 1, new ConvertOperator(types[0][from],
types[0][to]));
}
case opc_i2b: case opc_i2c: case opc_i2s:
return createNormal
(addr, 1, new ConvertOperator
(ca, addr, 1, new ConvertOperator
(ALL_INT_TYPE, types[1][(opcode-opc_i2b)+5]));
case opc_lcmp:
case opc_fcmpl: case opc_fcmpg:
case opc_dcmpl: case opc_dcmpg:
return createNormal
(addr, 1, new CompareToIntOperator
(ca, addr, 1, new CompareToIntOperator
(types[0][(opcode-opc_lcmp+3)/2], (opcode-opc_lcmp+3)%2));
case opc_ifeq: case opc_ifne:
case opc_iflt: case opc_ifge: case opc_ifgt: case opc_ifle:
return createIfGoto
(addr, 3, addr+stream.readShort(),
(ca, addr, 3, addr+stream.readShort(),
new CompareUnaryOperator
(ALL_INT_TYPE, opcode - opc_ifeq+Operator.COMPARE_OP));
case opc_if_icmpeq: case opc_if_icmpne: case opc_if_icmplt:
case opc_if_icmpge: case opc_if_icmpgt: case opc_if_icmple:
return createIfGoto
(addr, 3, addr+stream.readShort(),
(ca, addr, 3, addr+stream.readShort(),
new CompareBinaryOperator
(ALL_INT_TYPE, opcode - opc_if_icmpeq+Operator.COMPARE_OP));
case opc_if_acmpeq: case opc_if_acmpne:
return createIfGoto
(addr, 3, addr+stream.readShort(),
(ca, addr, 3, addr+stream.readShort(),
new CompareBinaryOperator
(OBJECT_TYPE, opcode - opc_if_acmpeq+Operator.COMPARE_OP));
case opc_goto:
return createGoto
(addr, 3, addr+stream.readShort());
// case opc_jsr:
// return createGoto //XXX
// (addr, 3, addr+stream.readShort());
// case opc_ret:
// return createReturn //XXX
// (addr, 2,
// new LocalLoadOperator
// (OBJECT_TYPE,
// ca.getLocalInfo(addr, stream.readUnsignedByte())));
(ca, addr, 3, addr+stream.readShort());
case opc_jsr:
return createJsr
(ca, addr, 3, addr+stream.readShort());
case opc_ret:
return createRet
(ca, addr, 2,
ca.getLocalInfo(addr, stream.readUnsignedByte()));
case opc_tableswitch: {
int length = 3-(addr % 4);
stream.skip(length);
@ -317,7 +340,7 @@ public abstract class Opcodes implements RuntimeConstants {
dests[cases.length] = def;
length += 13 + 4 * cases.length;
return createSwitch
(addr, length, cases, dests);
(ca, addr, length, cases, dests);
}
case opc_lookupswitch: {
int length = 3-(addr % 4);
@ -333,7 +356,7 @@ public abstract class Opcodes implements RuntimeConstants {
dests[npairs] = def;
length += 9 + 8 * npairs;
return createSwitch
(addr, length, cases, dests);
(ca, addr, length, cases, dests);
}
case opc_ireturn: case opc_lreturn:
case opc_freturn: case opc_dreturn: case opc_areturn: {
@ -341,23 +364,23 @@ public abstract class Opcodes implements RuntimeConstants {
(ca.getMethod().mdef.getType().getReturnType(),
types[0][opcode-opc_ireturn]);
return createBlock
(addr, 1, new ReturnBlock(new NopOperator(retType)));
(ca, addr, 1, new ReturnBlock(new NopOperator(retType)));
}
case opc_return:
/* Address -1 is interpreted as end of method */
return createBlock
(addr, 1, new EmptyBlock(new Jump(-1)));
(ca, addr, 1, new EmptyBlock(new Jump(-1)));
case opc_getstatic:
case opc_getfield:
return createNormal
(addr, 3, new GetFieldOperator
(ca, addr, 3, new GetFieldOperator
(ca, opcode == opc_getstatic,
(FieldDefinition)ca.env.getConstant
(stream.readUnsignedShort())));
case opc_putstatic:
case opc_putfield:
return createNormal
(addr, 3, new PutFieldOperator
(ca, addr, 3, new PutFieldOperator
(ca, opcode == opc_putstatic,
(FieldDefinition)ca.env.getConstant
(stream.readUnsignedShort())));
@ -365,14 +388,14 @@ public abstract class Opcodes implements RuntimeConstants {
case opc_invokespecial:
case opc_invokestatic :
return createNormal
(addr, 3, new InvokeOperator
(ca, addr, 3, new InvokeOperator
(ca,
opcode == opc_invokestatic, opcode == opc_invokespecial,
(FieldDefinition)ca.env.getConstant
(stream.readUnsignedShort())));
case opc_invokeinterface: {
FlowBlock fb = createNormal
(addr, 5, new InvokeOperator
(ca, addr, 5, new InvokeOperator
(ca, false, false,
(FieldDefinition)ca.env.getConstant
(stream.readUnsignedShort())));
@ -384,7 +407,7 @@ public abstract class Opcodes implements RuntimeConstants {
ca.env.getConstant(stream.readUnsignedShort());
Type type = MyType.tClassOrArray(cldec.getName());
return createNormal
(addr, 3, new NewOperator(type, ca.env.getTypeString(type)));
(ca, addr, 3, new NewOperator(type, ca.env.getTypeString(type)));
}
case opc_newarray: {
Type type;
@ -401,7 +424,7 @@ public abstract class Opcodes implements RuntimeConstants {
throw new ClassFormatError("Invalid newarray operand");
}
return createNormal
(addr, 2,
(ca, addr, 2,
new NewArrayOperator(MyType.tArray(type),
type.toString(), 1));
}
@ -411,22 +434,22 @@ public abstract class Opcodes implements RuntimeConstants {
Identifier ident = cldec.getName();
Type type = MyType.tClassOrArray(cldec.getName());
return createNormal
(addr, 3, new NewArrayOperator
(ca, addr, 3, new NewArrayOperator
(MyType.tArray(type), ca.env.getTypeString(type),1));
}
case opc_arraylength:
return createNormal
(addr, 1, new ArrayLengthOperator());
(ca, addr, 1, new ArrayLengthOperator());
case opc_athrow:
return createBlock
(addr, 1,
(ca, addr, 1,
new ThrowBlock(new NopOperator(MyType.tUObject)));
case opc_checkcast: {
ClassDeclaration cldec = (ClassDeclaration) ca.env.getConstant
(stream.readUnsignedShort());
Type type = MyType.tClassOrArray(cldec.getName());
return createNormal
(addr, 3, new CheckCastOperator
(ca, addr, 3, new CheckCastOperator
(type, ca.env.getTypeString(type)));
}
case opc_instanceof: {
@ -434,28 +457,28 @@ public abstract class Opcodes implements RuntimeConstants {
(stream.readUnsignedShort());
Type type = MyType.tClassOrArray(cldec.getName());
return createNormal
(addr, 3,
(ca, addr, 3,
new InstanceOfOperator(type, ca.env.getTypeString(type)));
}
case opc_monitorenter:
return createNormal(addr, 1,
return createNormal(ca, addr, 1,
new MonitorEnterOperator());
case opc_monitorexit:
return createNormal(addr, 1,
return createNormal(ca, addr, 1,
new MonitorExitOperator());
case opc_wide: {
switch (opcode=stream.readUnsignedByte()) {
case opc_iload: case opc_lload:
case opc_fload: case opc_dload: case opc_aload:
return createNormal
(addr, 4,
new LocalLoadOperator(types[0][opcode-opc_iload],
new LocalInfo
(stream.readUnsignedShort())));
(ca, addr, 4,
new LocalLoadOperator
(types[0][opcode-opc_iload],
ca.getLocalInfo(addr, stream.readUnsignedShort())));
case opc_istore: case opc_lstore:
case opc_fstore: case opc_dstore: case opc_astore:
return createNormal
(addr, 4,
(ca, addr, 4,
new LocalStoreOperator
(types[0][opcode-opc_istore],
ca.getLocalInfo(addr, stream.readUnsignedShort()),
@ -470,16 +493,14 @@ public abstract class Opcodes implements RuntimeConstants {
}
LocalInfo li = ca.getLocalInfo(addr, local);
return createNormal
(addr, 6, new IIncOperator
(ca, addr, 6, new IIncOperator
(li, Integer.toString(value),
operation + Operator.OPASSIGN_OP));
}
// case opc_ret:
// return new RetInstructionHeader
// (addr, 4,
// new LocalLoadOperator
// (INT_TYPE,
// ca.getLocalInfo(addr, stream.readUnsignedShort())));
case opc_ret:
return createRet
(ca, addr, 4,
ca.getLocalInfo(addr, stream.readUnsignedShort()));
default:
throw new ClassFormatError("Invalid wide opcode "+opcode);
}
@ -493,21 +514,21 @@ public abstract class Opcodes implements RuntimeConstants {
for (int i=0; i<dimension; i++)
baseType = baseType.getElementType();
return createNormal
(addr, 4,
(ca, addr, 4,
new NewArrayOperator
(type, ca.env.getTypeString(baseType), dimension));
}
case opc_ifnull: case opc_ifnonnull:
return createIfGoto
(addr, 3, addr+stream.readShort(),
(ca, addr, 3, addr+stream.readShort(),
new CompareUnaryOperator
(OBJECT_TYPE, opcode - opc_ifnull+Operator.COMPARE_OP));
case opc_goto_w:
return createGoto
(addr, 5, addr + stream.readInt());
// case opc_jsr_w:
// return createGoto
// (addr, 5, addr+stream.readInt()); // XXX
(ca, addr, 5, addr + stream.readInt());
case opc_jsr_w:
return createJsr
(ca, addr, 5, addr+stream.readInt());
default:
throw new ClassFormatError("Invalid opcode "+opcode);
}

@ -139,14 +139,13 @@ public class CodeAnalyzer implements Analyzer, Constants {
static jode.flow.Transformation[] exprTrafos = {
new jode.flow.RemoveEmpty(),
// new CombineCatchLocal(),
new jode.flow.CreateExpression(),
new jode.flow.CreatePostIncExpression(),
new jode.flow.CreateAssignExpression(),
new jode.flow.CreateNewConstructor(),
new jode.flow.CombineIfGotoExpressions(),
new jode.flow.CreateIfThenElseOperator(),
// new CreateConstantArray(),
new jode.flow.CreateConstantArray(),
new jode.flow.SimplifyExpression()
};

@ -58,6 +58,11 @@ public class LocalVariableTable {
env.getConstantPool().
getValue(name_i)),
env.getConstantPool().getType(desc_i));
if (Decompiler.showLVT)
System.err.println(""+env.getConstantPool().getValue(name_i)
+": "+env.getConstantPool().getType(desc_i)
+" range "+start+" - "+(start+length)
+" slot "+slot);
}
readfromclass = true;
}

@ -73,31 +73,26 @@ public class Expression extends Instruction {
public Expression tryToCombine(Expression e) {
if (e.operator instanceof StoreInstruction) {
StoreInstruction store = (StoreInstruction) e.operator;
Expression search = this;
while (true) {
if (store.matches(search.operator)) {
if (store.matches(operator)) {
int i;
for (i=0; i < e.subExpressions.length-1; i++) {
if (!e.subExpressions[i].equals
(search.subExpressions[i]))
(subExpressions[i]))
break;
}
if (i == e.subExpressions.length-1) {
search.operator =
operator =
new AssignOperator(store.getOperator(), store);
search.subExpressions = e.subExpressions;
subExpressions = e.subExpressions;
return this;
}
}
if (search.subExpressions.length == 0)
break;
if (search.getOperator() instanceof AssignOperator)
search = search.subExpressions[subExpressions.length-1];
else if (search.getOperator() instanceof StringAddOperator &&
search.subExpressions[1] == emptyString)
search = search.subExpressions[1];
else
search = search.subExpressions[0];
for (int i=0; i < subExpressions.length; i++) {
Expression combined = subExpressions[i].tryToCombine(e);
if (combined != null) {
subExpressions[i] = combined;
return this;
}
}
}
return null;

@ -26,8 +26,8 @@ public class BreakBlock extends StructuredBlock {
String label;
public BreakBlock(BreakableBlock breaksBlock, boolean needsLabel) {
this.breaksBlock = breaksBlock;
breaksBlock.mayChangeJump = false;
this.breaksBlock = (StructuredBlock) breaksBlock;
breaksBlock.setBreaked();
if (needsLabel)
label = breaksBlock.getLabel();
else

@ -21,54 +21,16 @@ 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;
public interface BreakableBlock {
/**
* 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;
}
public String getLabel();
/**
* 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.
* Is called by BreakBlock, to tell us that this block is breaked.
*/
public boolean jumpMayBeChanged() {
return mayChangeJump;
}
public void setBreaked();
}

@ -21,6 +21,7 @@ package jode.flow;
import java.util.*;
import jode.TabbedPrintWriter;
import jode.Expression;
import jode.CodeAnalyzer;
/**
* A flow block is the structure of which the flow graph consists. A
@ -34,12 +35,18 @@ import jode.Expression;
public class FlowBlock {
static FlowBlock END_OF_METHOD =
new FlowBlock(Integer.MAX_VALUE, 0, new EmptyBlock());
new FlowBlock(null, Integer.MAX_VALUE, 0, new EmptyBlock());
static {
END_OF_METHOD.label = "END_OF_METHOD";
}
/**
* The code analyzer. This is used to pretty printing the
* Types and to get information about all locals in this code.
*/
CodeAnalyzer code;
/**
* The in locals. This are the locals, which are used in this
* flow block and whose values may be the result of a assignment
@ -89,7 +96,9 @@ public class FlowBlock {
* The default constructor. Creates a new flowblock containing
* only the given structured block.
*/
public FlowBlock(int addr, int length, StructuredBlock block) {
public FlowBlock(CodeAnalyzer code, int addr, int length,
StructuredBlock block) {
this.code = code;
this.addr = addr;
this.length = length;
this.block = block;
@ -657,15 +666,32 @@ public class FlowBlock {
*/
StructuredBlock precedingcase = null;
StructuredBlock nextcase = null;
/*XXX*/
if (appendBlock instanceof SwitchBlock) {
nextcase = ((SwitchBlock) appendBlock).findCase(succ);
precedingcase =
((SwitchBlock) appendBlock).prevCase(precedingcase);
enum = successors.elements();
while (nextcase != null && enum.hasMoreElements()) {
Jump jump = (Jump) enum.nextElement();
if (jump == null
|| jump.destination != succ
|| jump.prev == nextcase
|| (precedingcase != null
&& precedingcase.contains(jump.prev)))
continue;
nextcase = null;
}
}
if (succ == END_OF_METHOD) {
} else if (nextcase != null) {
SwitchBlock switchBlock = (SwitchBlock) appendBlock;
/* Now put the succ.block into the next case.
*/
switchBlock.replaceSubBlock(nextcase,succ.block);
succ.block.outer = switchBlock;
nextcase.removeJump();
succ.block.replace(nextcase, succ.block);
/* nextcase is not referenced any more */
/* Do the following modifications on the struct block. */
@ -750,10 +776,16 @@ public class FlowBlock {
}
}
/* Now remove the jump of the appendBlock if it points to successor.
/* appendBlock may be zero, if this is the switchcase with
* precedingcase = null. But in this case, there can't be
* any jumps.
*/
if (appendBlock != null) {
/* Now remove the jump of the appendBlock if it points to
* successor.
*/
if (appendBlock.jump != null &&
appendBlock.jump.destination == succ)
if (appendBlock.jump != null
&& appendBlock.jump.destination == succ)
appendBlock.removeJump();
/* If there are further jumps, put a do/while(0) block around
@ -794,6 +826,7 @@ public class FlowBlock {
doWhileFalse.replace(appendBlock, appendBlock);
doWhileFalse.setBody(appendBlock);
}
}
/* Believe it or not: Now the rule, that the first part of a
* SequentialBlock shouldn't be another SequentialBlock is
@ -868,6 +901,21 @@ public class FlowBlock {
/* Update the in/out-Vectors now */
VariableSet defineHere = updateInOut(this, false);
while (lastModified != block) {
lastModified = lastModified.outer;
if (lastModified instanceof SequentialBlock
&& lastModified.getSubBlocks()[0]
instanceof RawTryCatchBlock) {
/* We leave the catch block of a raw-try-catch-block.
* We shall now create the Catch- resp. FinallyBlock.
*/
lastModified =
createCatchBlock((SequentialBlock)lastModified);
}
}
/* If there is only one jump to the beginning and it is the
* last jump and (there is a do/while(0) block surrounding
* everything but the last instruction, or the last
@ -1000,6 +1048,7 @@ public class FlowBlock {
public void makeDeclaration(VariableSet param) {
in.merge(param);
in.subtract(param);
block.propagateUsage();
block.makeDeclaration(param);
}

@ -23,7 +23,7 @@ import jode.*;
/**
* This is the structured block for an Loop block.
*/
public class LoopBlock extends BreakableBlock {
public class LoopBlock extends StructuredBlock implements BreakableBlock {
public static final int WHILE = 0;
public static final int DOWHILE = 1;
@ -130,6 +130,11 @@ public class LoopBlock extends BreakableBlock {
public void dumpInstruction(TabbedPrintWriter writer)
throws java.io.IOException
{
if (label != null) {
writer.untab();
writer.println(label+":");
writer.tab();
}
boolean needBrace = ! (bodyBlock instanceof InstructionBlock);
switch (type) {
case WHILE:
@ -153,4 +158,43 @@ public class LoopBlock extends BreakableBlock {
else if (needBrace)
writer.println("}");
}
boolean mayChangeJump = true;
/**
* 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 = "while_"+(serialno++)+"_";
return label;
}
/**
* Is called by BreakBlock, to tell us that this block is breaked.
*/
public void setBreaked() {
mayChangeJump = false;
}
/**
* 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;
}
}

@ -63,6 +63,22 @@ public class SequentialBlock extends StructuredBlock {
return getNextFlowBlock();
}
/**
* Make the declarations, i.e. initialize the declare variable
* to correct values. This will declare every variable that
* is marked as used, but not done.
* @param done The set of the already declare variables.
*/
public void makeDeclaration(VariableSet done) {
/* A sequential block is special, since it doesn't declare
* any local Variable, but let the first sub block do this.
*/
declare = new VariableSet();
subBlocks[0].makeDeclaration(done);
done.addExact(used);
subBlocks[1].makeDeclaration(done);
}
public void dumpInstruction(TabbedPrintWriter writer)
throws java.io.IOException
{

@ -70,7 +70,7 @@ public abstract class StructuredBlock {
* The variable set containing all variables we must declare.
* The analyzation is done in makeDeclaration
*/
VariableSet declare = new VariableSet();
VariableSet declare;
/**
* The surrounding structured block. If this is the outermost
@ -285,14 +285,9 @@ public abstract class StructuredBlock {
}
if (subs.length == 2) {
/* All variables used in both sub blocks, are used in
* this block, too. But a sequential block is a notable
* exception, since it is enough if the first sub block
* declares the Variable
* this block, too.
*/
VariableSet newUse = childUse[0].intersectExact(childUse[1]);
if (this instanceof SequentialBlock)
subs[0].used.addExact(newUse);
else
used.addExact(newUse);
}
return allUse;
@ -305,8 +300,13 @@ public abstract class StructuredBlock {
* @param done The set of the already declare variables.
*/
public void makeDeclaration(VariableSet done) {
propagateUsage();
declare.addExact(used);
declare = new VariableSet();
java.util.Enumeration enum = used.elements();
while (enum.hasMoreElements()) {
LocalInfo local = ((LocalInfo) enum.nextElement()).getLocalInfo();
if (!declare.contains(local))
declare.addElement(local);
}
declare.subtractExact(done);
done.addExact(declare);

@ -23,27 +23,82 @@ import jode.TabbedPrintWriter;
/**
* This is the structured block for an empty block.
*/
public class SwitchBlock extends BreakableBlock {
int[] cases;
StructuredBlock[] caseBlocks;
public class SwitchBlock extends InstructionContainer
implements BreakableBlock {
CaseBlock[] 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]));
public SwitchBlock(jode.Instruction instr,
int[] cases, int[] dests) {
super(instr);
this.caseBlocks = new CaseBlock[dests.length];
int lastDest = -1;
boolean lastBlock = true;
for (int i=dests.length-1; i>=0; i--) {
/**
* Sort the destinations by finding the greatest destAddr
*/
int index = 0;
for (int j=1; j<dests.length; j++) {
if (dests[j] >= dests[index])
index = j;
}
int value;
if (index == cases.length)
value = -1;
else
value = cases[index];
if (dests[index] == lastDest)
this.caseBlocks[i] = new CaseBlock(value);
else
this.caseBlocks[i] = new CaseBlock(value,
new Jump(dests[index]));
this.caseBlocks[i].outer = this;
this.caseBlocks[i].isLastBlock = lastBlock;
lastBlock = false;
lastDest = dests[index];
dests[index] = -1;
if (index == cases.length)
this.caseBlocks[i].isDefault = true;
}
this.jump = null;
mayChangeJump = true;
}
public void dumpInstruction(TabbedPrintWriter writer)
throws java.io.IOException
{
writer.println("switch (/* XXX implement */)");
/**
* Find the case that jumps directly to destination.
* @return The sub block of the case block, which jumps to destination.
*/
public StructuredBlock findCase(FlowBlock destination) {
for (int i=0; i < caseBlocks.length; i++) {
if (caseBlocks[i].subBlock != null
&& caseBlocks[i].subBlock instanceof EmptyBlock
&& caseBlocks[i].subBlock.jump != null
&& caseBlocks[i].subBlock.jump.destination == destination)
return caseBlocks[i].subBlock;
}
return null;
}
/**
* Find the case that precedes the given case.
* @param block The sub block of the case, whose predecessor should
* be returned.
* @return The sub block of the case precedes the given case.
*/
public StructuredBlock prevCase(StructuredBlock block) {
for (int i=caseBlocks.length-1; i>=0; i--) {
if (caseBlocks[i].subBlock == block) {
for (i--; i>=0; i--) {
if (caseBlocks[i].subBlock != null)
return caseBlocks[i].subBlock;
}
}
}
return null;
}
/**
* Returns the block where the control will normally flow to, when
@ -53,20 +108,83 @@ public class SwitchBlock extends BreakableBlock {
* the behaviour is undefined, so take care.
* @return null, if the control flows to another FlowBlock. */
public StructuredBlock getNextBlock(StructuredBlock subBlock) {
/*XXX*/
for (int i=0; i< caseBlocks.length-1; i++) {
if (subBlock == caseBlocks[i]) {
return caseBlocks[i+1];
}
}
return getNextBlock();
}
public FlowBlock getNextFlowBlock(StructuredBlock subBlock) {
/*XXX*/
for (int i=0; i< caseBlocks.length-1; i++) {
if (subBlock == caseBlocks[i]) {
return null;
}
}
return getNextFlowBlock();
}
public void dumpInstruction(TabbedPrintWriter writer)
throws java.io.IOException
{
writer.println("switch ("+instr+") {");
for (int i=0; i < caseBlocks.length; i++)
caseBlocks[i].dumpSource(writer);
writer.println("}");
}
public void setInstruction(jode.Instruction instr) {
super.setInstruction(instr);
sun.tools.java.Type type = instr.getType();
if (type != caseBlocks[0].type) {
for (int i=0; i < caseBlocks.length; i++)
caseBlocks[i].type = type;
}
}
/**
* Returns all sub block of this structured block.
*/
public StructuredBlock[] getSubBlocks() {
return caseBlocks;
}
}
boolean mayChangeJump = true;
/**
* 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 = "switch_"+(serialno++)+"_";
return label;
}
/**
* Is called by BreakBlock, to tell us that this block is breaked.
*/
public void setBreaked() {
mayChangeJump = false;
}
/**
* 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;
}
}

@ -238,6 +238,8 @@ public class ClassRangeType extends MyType {
/**
* Returns the generalized type of t1 and t2, e.g
* tObject, tString -> tObject
* object , interface -> object
* since a sub class of object may implement interface
* int , short -> int
* tArray(tObject), tArray(tUnknown) -> tArray(tUnknown)
* tArray(tUnknown), tObject -> tObject
@ -308,14 +310,14 @@ public class ClassRangeType extends MyType {
ClassDeclaration c2 = new ClassDeclaration(t2.getClassName());
try {
/* if one of the two types is an interface which
* is implemented by the other type the interface
* is the result.
/* if one of the two types is an interface, return
* the other type, since at least a subtype of the
* other type may implement the interface.
*/
if (c1.getClassDefinition(env).implementedBy(env, c2))
return t1;
if (c2.getClassDefinition(env).implementedBy(env, c1))
if (c1.getClassDefinition(env).isInterface())
return t2;
if (c2.getClassDefinition(env).isInterface())
return t1;
ClassDefinition c = c1.getClassDefinition(env);
while(c != null && !c.superClassOf(env, c2)) {
@ -339,6 +341,10 @@ public class ClassRangeType extends MyType {
" to <" + bottom + "-" + top +
"> to <error>");
Thread.dumpStack();
} else if (Decompiler.isTypeDebugging) {
System.err.println("intersecting "+ this +" and "+ type +
" to <" + bottom + "-" + top +
"> to " + newType);
}
return newType;
}
@ -350,7 +356,7 @@ public class ClassRangeType extends MyType {
public String typeString(String string, boolean flag1, boolean flag2)
{
if (Decompiler.isDebugging)
if (Decompiler.isTypeDebugging)
return "<"+bottomType+"-"+topType+">" + string;
else if (bottomType != null)
return bottomType.typeString(string, flag1, flag2);

@ -63,7 +63,7 @@ public class MyType extends Type {
return new ClassRangeType(tObject, type);
else if (typeCode == 103)
return (((ClassRangeType)type).topType == null
? tUnknown : new ClassRangeType(tObject, null));
? tUnknown : new ClassRangeType(tObject, type));
else
return type;
}

Loading…
Cancel
Save