From 1995b7a07842e2ab9be3e0ea3da38de7034114ae Mon Sep 17 00:00:00 2001 From: delwi Date: Fri, 7 Aug 1998 20:08:08 +0000 Subject: [PATCH] Typen korrekt? git-svn-id: https://svn.code.sf.net/p/jode/code/trunk@6 379699f6-c40d-0410-875b-85095c16579e --- jode/jode/Decompiler.java | 7 +- jode/jode/bytecode/Opcodes.java | 649 +++++--- jode/jode/decompiler/ClassAnalyzer.java | 4 +- jode/jode/decompiler/CodeAnalyzer.java | 1322 ++++++----------- jode/jode/decompiler/FieldAnalyzer.java | 24 +- jode/jode/decompiler/ImportHandler.java | 17 +- jode/jode/decompiler/LocalInfo.java | 103 +- jode/jode/decompiler/LocalVariable.java | 4 +- .../decompiler/LocalVariableAnalyzer.java | 206 +++ .../decompiler/LocalVariableRangeList.java | 28 +- jode/jode/decompiler/LocalVariableTable.java | 27 +- jode/jode/decompiler/MethodAnalyzer.java | 77 +- jode/jode/decompiler/TabbedPrintWriter.java | 2 +- jode/jode/expr/ArrayLengthOperator.java | 10 +- jode/jode/expr/ArrayLoadOperator.java | 14 +- jode/jode/expr/ArrayStoreOperator.java | 39 +- jode/jode/expr/AssignOperator.java | 15 +- jode/jode/expr/BinaryOperator.java | 19 +- jode/jode/expr/CheckCastOperator.java | 13 +- jode/jode/expr/CompareBinaryOperator.java | 15 +- jode/jode/expr/CompareToIntOperator.java | 39 +- jode/jode/expr/CompareUnaryOperator.java | 23 +- jode/jode/expr/ConstOperator.java | 12 +- jode/jode/expr/ConstantArrayOperator.java | 30 + jode/jode/expr/ConstructorOperator.java | 7 +- jode/jode/expr/ConvertOperator.java | 10 +- jode/jode/expr/DupOperator.java | 10 +- jode/jode/expr/EmptyStringOperator.java | 22 + jode/jode/expr/Expression.java | 178 ++- jode/jode/expr/GetFieldOperator.java | 21 +- jode/jode/expr/IIncOperator.java | 55 + jode/jode/expr/IfThenElseOperator.java | 14 +- jode/jode/expr/InstanceOfOperator.java | 14 +- jode/jode/expr/Instruction.java | 32 +- jode/jode/expr/InstructionHeader.java | 282 ++++ jode/jode/expr/InvokeOperator.java | 31 +- jode/jode/expr/JsrInstructionHeader.java | 55 + jode/jode/expr/JsrOperator.java | 10 +- jode/jode/expr/LocalLoadOperator.java | 54 + jode/jode/expr/LocalPostFixOperator.java | 19 + jode/jode/expr/LocalStoreOperator.java | 75 + jode/jode/expr/LocalVarOperator.java | 11 + jode/jode/expr/MethodInstructionHeader.java | 35 + jode/jode/expr/MonitorEnterOperator.java | 6 +- jode/jode/expr/MonitorExitOperator.java | 8 +- jode/jode/expr/NewArrayOperator.java | 21 +- jode/jode/expr/NewOperator.java | 10 +- jode/jode/expr/NoArgOperator.java | 8 +- jode/jode/expr/NopOperator.java | 18 +- jode/jode/expr/Operator.java | 45 +- jode/jode/expr/PopOperator.java | 8 +- jode/jode/expr/PostFixOperator.java | 35 +- jode/jode/expr/PutFieldOperator.java | 23 +- jode/jode/expr/RetInstructionHeader.java | 45 + jode/jode/expr/RetOperator.java | 13 +- jode/jode/expr/ReturnOperator.java | 10 +- jode/jode/expr/ShiftOperator.java | 10 +- jode/jode/expr/SimpleOperator.java | 8 +- jode/jode/expr/StoreInstruction.java | 34 +- jode/jode/expr/StringAddOperator.java | 27 + jode/jode/expr/SwapOperator.java | 9 +- jode/jode/expr/ThrowOperator.java | 6 +- jode/jode/expr/UnaryOperator.java | 13 +- jode/jode/type/ClassRangeType.java | 319 ++++ jode/jode/type/MyType.java | 199 +++ jode/jode/type/UnknownSuperType.java | 22 + 66 files changed, 3040 insertions(+), 1491 deletions(-) create mode 100644 jode/jode/decompiler/LocalVariableAnalyzer.java create mode 100644 jode/jode/expr/ConstantArrayOperator.java create mode 100644 jode/jode/expr/EmptyStringOperator.java create mode 100644 jode/jode/expr/IIncOperator.java create mode 100644 jode/jode/expr/InstructionHeader.java create mode 100644 jode/jode/expr/JsrInstructionHeader.java create mode 100644 jode/jode/expr/LocalLoadOperator.java create mode 100644 jode/jode/expr/LocalPostFixOperator.java create mode 100644 jode/jode/expr/LocalStoreOperator.java create mode 100644 jode/jode/expr/LocalVarOperator.java create mode 100644 jode/jode/expr/MethodInstructionHeader.java create mode 100644 jode/jode/expr/RetInstructionHeader.java create mode 100644 jode/jode/expr/StringAddOperator.java create mode 100644 jode/jode/type/ClassRangeType.java create mode 100644 jode/jode/type/MyType.java create mode 100644 jode/jode/type/UnknownSuperType.java diff --git a/jode/jode/Decompiler.java b/jode/jode/Decompiler.java index 1facc7e..412d70c 100644 --- a/jode/jode/Decompiler.java +++ b/jode/jode/Decompiler.java @@ -6,7 +6,12 @@ public class Decompiler { public static void main(String[] params) { JodeEnvironment env = new JodeEnvironment(); for (int i=0; i= from) + to++; + return new InstructionHeader + (addr, 1, new ConvertOperator(types[0][from], + types[0][to])); + } + case opc_i2b: case opc_i2c: case opc_i2s: + return new InstructionHeader + (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 new InstructionHeader + (addr, 1, new CompareToIntOperator + (types[0][(opcode-opc_lcmp+3)/2], (opcode-opc_lcmp+3)%2)); + case opc_ifeq: case opc_ifne: + case opc_iflt: case opc_ifge: case opc_ifgt: case opc_ifle: + return InstructionHeader.conditional + (addr, 3, addr+stream.readShort(), + new CompareUnaryOperator + (ALL_INT_TYPE, opcode - opc_ifeq+Operator.COMPARE_OP)); + case opc_if_icmpeq: case opc_if_icmpne: case opc_if_icmplt: + case opc_if_icmpge: case opc_if_icmpgt: case opc_if_icmple: + return InstructionHeader.conditional + (addr, 3, addr+stream.readShort(), + new CompareBinaryOperator + (ALL_INT_TYPE, opcode - opc_if_icmpeq+Operator.COMPARE_OP)); + case opc_if_acmpeq: case opc_if_acmpne: + return InstructionHeader.conditional + (addr, 3, addr+stream.readShort(), + new CompareBinaryOperator + (OBJECT_TYPE, opcode - opc_if_acmpeq+Operator.COMPARE_OP)); + case opc_goto: + return InstructionHeader.jump + (addr, 3, addr+stream.readShort(), new NopOperator()); + case opc_jsr: + return InstructionHeader.jump + (addr, 3, addr+stream.readShort(), + new JsrOperator()); + case opc_ret: + return InstructionHeader.ret + (addr, 2, + new LocalLoadOperator + (INT_TYPE, + stream.readUnsignedByte())); + case opc_tableswitch: { + int length = 3-(addr % 4); + stream.skip(length); + int def = addr + stream.readInt(); + int low = stream.readInt(); + int high = stream.readInt(); + int[] cases = new int[high-low+1]; + int[] dests = new int[high-low+2]; + for (int i=0; i+low <= high; i++) { + cases[i] = i+low; + dests[i] = addr + stream.readInt(); + } + dests[cases.length] = def; + length += 13 + 4 * cases.length; + return new InstructionHeader + (addr, length, new NopOperator(), + ALL_INT_TYPE, cases, dests); + } + case opc_lookupswitch: { + int length = 3-(addr % 4); + stream.skip(length); + int def = addr + stream.readInt(); + int npairs = stream.readInt(); + int[] cases = new int[npairs]; + int[] dests = new int[npairs+1]; + for (int i=0; i < npairs; i++) { + cases[i] = stream.readInt(); + dests[i] = addr + stream.readInt(); + } + dests[npairs] = def; + length += 9 + 8 * npairs; + return new InstructionHeader + (addr, length, new NopOperator(), + ALL_INT_TYPE, cases, dests); + } + case opc_ireturn: case opc_lreturn: + case opc_freturn: case opc_dreturn: case opc_areturn: { + Type retType = MyType.intersection + (ca.getMethod().mdef.getType().getReturnType(), + types[0][opcode-opc_ireturn]); + return InstructionHeader.ret + (addr, 1, new ReturnOperator(retType)); + } + case opc_return: { + Type retType = MyType.intersection + (ca.getMethod().mdef.getType().getReturnType(), + VOID_TYPE); + return InstructionHeader.ret + (addr, 1, new ReturnOperator(retType)); + } + case opc_getstatic: + case opc_getfield: + return new InstructionHeader + (addr, 3, new GetFieldOperator + (ca, opcode == opc_getstatic, + (FieldDefinition)ca.env.getConstant + (stream.readUnsignedShort()))); + case opc_putstatic: + case opc_putfield: + return new InstructionHeader + (addr, 3, new PutFieldOperator + (ca, opcode == opc_putstatic, + (FieldDefinition)ca.env.getConstant + (stream.readUnsignedShort()))); + case opc_invokevirtual: + case opc_invokespecial: + case opc_invokestatic : + return new InstructionHeader + (addr, 3, new InvokeOperator + (ca, + opcode == opc_invokestatic, opcode == opc_invokespecial, + (FieldDefinition)ca.env.getConstant + (stream.readUnsignedShort()))); + case opc_invokeinterface: { + InstructionHeader ih = new InstructionHeader + (addr, 5, new InvokeOperator + (ca, false, false, + (FieldDefinition)ca.env.getConstant + (stream.readUnsignedShort()))); + int reserved = stream.readUnsignedShort(); + return ih; + } + case opc_new: { + ClassDeclaration cldec = (ClassDeclaration) + ca.env.getConstant(stream.readUnsignedShort()); + Type type = MyType.tClassOrArray(cldec.getName()); + return new InstructionHeader + (addr, 3, new NewOperator(type, ca.env.getTypeString(type))); + } + case opc_newarray: { + Type type; + switch (stream.readUnsignedByte()) { + case 4: type = Type.tBoolean; break; + case 5: type = Type.tChar ; break; + case 6: type = Type.tFloat ; break; + case 7: type = Type.tDouble ; break; + case 8: type = Type.tByte ; break; + case 9: type = Type.tShort ; break; + case 10: type = Type.tInt ; break; + case 11: type = Type.tLong ; break; + default: + throw new ClassFormatError("Invalid newarray operand"); + } + return new InstructionHeader + (addr, 2, + new NewArrayOperator(MyType.tArray(type), + type.toString(), 1)); + } + case opc_anewarray: { + ClassDeclaration cldec = (ClassDeclaration) ca.env.getConstant + (stream.readUnsignedShort()); + Identifier ident = cldec.getName(); + Type type = MyType.tClassOrArray(cldec.getName()); + return new InstructionHeader + (addr, 3, new NewArrayOperator + (MyType.tArray(type), ca.env.getTypeString(type),1)); + } + case opc_arraylength: + return new InstructionHeader + (addr, 1, new ArrayLengthOperator()); + case opc_athrow: + return InstructionHeader.ret + (addr, 1, new ThrowOperator()); + case opc_checkcast: { + ClassDeclaration cldec = (ClassDeclaration) ca.env.getConstant + (stream.readUnsignedShort()); + Type type = MyType.tClassOrArray(cldec.getName()); + return new InstructionHeader + (addr, 3, new CheckCastOperator + (type, ca.env.getTypeString(type))); + } + case opc_instanceof: { + ClassDeclaration cldec = (ClassDeclaration) ca.env.getConstant + (stream.readUnsignedShort()); + Type type = MyType.tClassOrArray(cldec.getName()); + return new InstructionHeader + (addr, 3, + new InstanceOfOperator(type, ca.env.getTypeString(type))); + } + case opc_monitorenter: + return new InstructionHeader(addr, 1, + new MonitorEnterOperator()); + case opc_monitorexit: + return new InstructionHeader(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 new InstructionHeader + (addr, 4, + new LocalLoadOperator(types[0][opcode-opc_iload], + stream.readUnsignedShort())); + case opc_istore: case opc_lstore: + case opc_fstore: case opc_dstore: case opc_astore: + return new InstructionHeader + (addr, 4, + new LocalStoreOperator(types[0][opcode-opc_istore], + stream.readUnsignedShort(), + Operator.ASSIGN_OP)); + case opc_iinc: { + int local = stream.readUnsignedShort(); + int value = stream.readShort(); + int operation = Operator.ADD_OP; + if (value < 0) { + value = -value; + operation = Operator.NEG_OP; + } + return new InstructionHeader + (addr, 6, new IIncOperator + (local, Integer.toString(value), + operation + Operator.OPASSIGN_OP)); + } + case opc_ret: + return new RetInstructionHeader + (addr, 4, + new LocalLoadOperator + (INT_TYPE, stream.readUnsignedShort())); + default: + throw new ClassFormatError("Invalid wide opcode "+opcode); + } + } + case opc_multianewarray: { + ClassDeclaration cldec = (ClassDeclaration) ca.env.getConstant + (stream.readUnsignedShort()); + Type type = MyType.tClassOrArray(cldec.getName()); + int dimension = stream.readUnsignedByte(); + Type baseType = type; + for (int i=0; i 0) writer.print(modif + " "); writer.print((cdef.isInterface())?"interface ":"class "); - writer.println(env.getNickName(cdef.getName().toString())); + writer.println(cdef.getName().getName().toString()); writer.tab(); if (cdef.getSuperClass() != null) writer.println("extends "+cdef.getSuperClass().getName().toString()); diff --git a/jode/jode/decompiler/CodeAnalyzer.java b/jode/jode/decompiler/CodeAnalyzer.java index 6fc495b..8a73a64 100644 --- a/jode/jode/decompiler/CodeAnalyzer.java +++ b/jode/jode/decompiler/CodeAnalyzer.java @@ -4,508 +4,52 @@ import java.lang.reflect.Modifier; import java.util.*; import java.io.*; -public class CodeAnalyzer implements Analyzer, Constants, Opcodes { +public class CodeAnalyzer implements Analyzer, Constants { - MethodAnalyzer method; - JodeEnvironment env; BinaryCode bincode; - Instruction[] instr; + MethodInstructionHeader methodHeader; int[] references; Hashtable tryAddrs = new Hashtable(); Hashtable catchAddrs = new Hashtable(); Hashtable labels = new Hashtable(); - - public void readOpcodes(DataInputStream stream) - throws IOException, ClassFormatError - { - int addr = 0; - try { - while (true) { - int opcode; - try { - opcode = stream.readUnsignedByte(); - } catch (EOFException eof) { - break; - } - switch (opcode) { - case NOP_OP: - instr[addr] = new NopOperator(addr, 1); - break; - case ACONST_NULL_OP: - instr[addr] = new ConstOperator(addr, 1, OBJECT_TYPE, "null"); - break; - case ICONST_M1_OP: - case ICONST_0_OP: case ICONST_1_OP: case ICONST_2_OP: - case ICONST_3_OP: case ICONST_4_OP: case ICONST_5_OP: - instr[addr] = - new ConstOperator(addr, 1, ALL_INT_TYPE, - Integer.toString(opcode - ICONST_0_OP)); - break; - case LCONST_0_OP: case LCONST_1_OP: - instr[addr] = - new ConstOperator(addr, 1, LONG_TYPE, - Integer.toString(opcode - LCONST_0_OP)+ - "L"); - break; - case FCONST_0_OP: case FCONST_1_OP: case FCONST_2_OP: - instr[addr] = - new ConstOperator(addr, 1, FLOAT_TYPE, - Integer.toString(opcode - FCONST_0_OP)+ - ".0F"); - break; - case DCONST_0_OP: case DCONST_1_OP: - instr[addr] = - new ConstOperator(addr, 1, DOUBLE_TYPE, - Integer.toString(opcode - DCONST_0_OP)+ - ".0"); - break; - case BIPUSH_OP: - instr[addr] = - new ConstOperator(addr, 2, ALL_INT_TYPE, - Integer.toString(stream.readByte())); - break; - case SIPUSH_OP: - instr[addr] = - new ConstOperator(addr, 3, ALL_INT_TYPE, - Integer.toString(stream.readShort())); - break; - case LDC_OP: { - int index = stream.readUnsignedByte(); - instr[addr] = - new ConstOperator(addr, 2, env.getConstantType(index), - env.getConstant(index).toString()); - break; - } - case LDC_W_OP: - case LDC2_W_OP: { - int index = stream.readUnsignedShort(); - instr[addr] = - new ConstOperator(addr, 3, env.getConstantType(index), - env.getConstant(index).toString()); - break; - } - case ILOAD_OP: case LLOAD_OP: - case FLOAD_OP: case DLOAD_OP: case ALOAD_OP: - instr[addr] = - new LoadOperator(addr, 2, types[0][opcode-ILOAD_OP], - method.getLocal(stream.readUnsignedByte())); - break; - case ILOAD_0_OP: case ILOAD_1_OP: case ILOAD_2_OP: case ILOAD_3_OP: - case LLOAD_0_OP: case LLOAD_1_OP: case LLOAD_2_OP: case LLOAD_3_OP: - case FLOAD_0_OP: case FLOAD_1_OP: case FLOAD_2_OP: case FLOAD_3_OP: - case DLOAD_0_OP: case DLOAD_1_OP: case DLOAD_2_OP: case DLOAD_3_OP: - case ALOAD_0_OP: case ALOAD_1_OP: case ALOAD_2_OP: case ALOAD_3_OP: - instr[addr] = - new LoadOperator(addr, 1, types[0][(opcode-ILOAD_0_OP)/4], - method.getLocal((opcode-ILOAD_0_OP) & 3)); - break; - case IALOAD_OP: case LALOAD_OP: - case FALOAD_OP: case DALOAD_OP: case AALOAD_OP: - case BALOAD_OP: case CALOAD_OP: case SALOAD_OP: - instr[addr] = - new ArrayLoadOperator(addr, 1, types[1][opcode - IALOAD_OP]); - break; - case ISTORE_OP: case LSTORE_OP: - case FSTORE_OP: case DSTORE_OP: case ASTORE_OP: - instr[addr] = - new StoreOperator(addr, 2, types[0][opcode-ISTORE_OP], - method.getLocal(stream.readUnsignedByte()), - Operator.ASSIGN_OP); - break; - case ISTORE_0_OP: case ISTORE_1_OP: - case ISTORE_2_OP: case ISTORE_3_OP: - case LSTORE_0_OP: case LSTORE_1_OP: - case LSTORE_2_OP: case LSTORE_3_OP: - case FSTORE_0_OP: case FSTORE_1_OP: - case FSTORE_2_OP: case FSTORE_3_OP: - case DSTORE_0_OP: case DSTORE_1_OP: - case DSTORE_2_OP: case DSTORE_3_OP: - case ASTORE_0_OP: case ASTORE_1_OP: - case ASTORE_2_OP: case ASTORE_3_OP: - instr[addr] = - new StoreOperator(addr, 1, types[0][(opcode-ISTORE_0_OP)/4], - method.getLocal((opcode-ISTORE_0_OP) & 3), - Operator.ASSIGN_OP); - break; - case IASTORE_OP: case LASTORE_OP: - case FASTORE_OP: case DASTORE_OP: case AASTORE_OP: - case BASTORE_OP: case CASTORE_OP: case SASTORE_OP: - instr[addr] = - new ArrayStoreOperator(addr, 1, - types[1][opcode - IASTORE_OP]); - break; - case POP_OP: case POP2_OP: - instr[addr] = - new PopOperator(addr, 1, opcode - POP_OP + 1); - break; - case DUP_OP: case DUP_X1_OP: case DUP_X2_OP: - case DUP2_OP: case DUP2_X1_OP: case DUP2_X2_OP: - instr[addr] = - new DupOperator(addr, 1, - (opcode - DUP_OP)%3, - (opcode - DUP_OP)/3+1); - break; - case SWAP_OP: - instr[addr] = new SwapOperator(addr, 1); - break; - case IADD_OP: case LADD_OP: case FADD_OP: case DADD_OP: - case ISUB_OP: case LSUB_OP: case FSUB_OP: case DSUB_OP: - case IMUL_OP: case LMUL_OP: case FMUL_OP: case DMUL_OP: - case IDIV_OP: case LDIV_OP: case FDIV_OP: case DDIV_OP: - case IREM_OP: case LREM_OP: case FREM_OP: case DREM_OP: - instr[addr] = - new BinaryOperator(addr, 1, types[0][(opcode - IADD_OP)%4], - (opcode - IADD_OP)/4+Operator.ADD_OP); - break; - case INEG_OP: case LNEG_OP: case FNEG_OP: case DNEG_OP: - instr[addr] = - new UnaryOperator(addr, 1, types[0][opcode - INEG_OP], - Operator.NEG_OP); - break; - case ISHL_OP: case LSHL_OP: - case ISHR_OP: case LSHR_OP: - case IUSHR_OP: case LUSHR_OP: - instr[addr] = new ShiftOperator(addr, 1, - types[0][(opcode - ISHL_OP)%2], - (opcode - ISHL_OP)/2 + - Operator.SHIFT_OP); - break; - case IAND_OP: case LAND_OP: - case IOR_OP : case LOR_OP : - case IXOR_OP: case LXOR_OP: - instr[addr] = new BinaryOperator(addr, 1, - types[0][(opcode - ISHL_OP)%2], - (opcode - ISHL_OP)/2 + - Operator.SHIFT_OP); - break; - case IINC_OP: { - int local = stream.readUnsignedByte(); - int value = stream.readUnsignedByte(); - int operation = Operator.ADD_OP; - if (value < 0) { - value = -value; - operation = Operator.NEG_OP; - } - instr[addr] = new ConstOperator(addr, 1, ALL_INT_TYPE, - Integer.toString(value)); - instr[addr+1] = - new StoreOperator(addr+1, 2, ALL_INT_TYPE, - method.getLocal(local), - operation + Operator.OPASSIGN_OP); - addr++; - } - - break; - case I2L_OP: case I2F_OP: case I2D_OP: - case L2I_OP: case L2F_OP: case L2D_OP: - case F2I_OP: case F2L_OP: case F2D_OP: - case D2I_OP: case D2L_OP: case D2F_OP: { - int from = (opcode-I2L_OP)/3; - int to = (opcode-I2L_OP)%3; - if (to >= from) - to++; - instr[addr] = new ConvertOperator(addr, 1, types[0][from], - types[1][to]); - break; - } - case I2B_OP: case I2C_OP: case I2S_OP: - instr[addr] = new ConvertOperator(addr, 1, ALL_INT_TYPE, - types[1][(opcode-I2B_OP)+5]); - break; - case LCMP_OP: - case FCMPL_OP: case FCMPG_OP: - case DCMPL_OP: case DCMPG_OP: - instr[addr] = new CompareToIntOperator - (addr, 1, types[0][(opcode-LCMP_OP+3)/2], - (opcode-LCMP_OP+3)%2); - break; - case IFEQ_OP: case IFNE_OP: - case IFLT_OP: case IFGE_OP: case IFGT_OP: case IFLE_OP: { - instr[addr] = new CompareUnaryOperator - (addr, 1, ALL_INT_TYPE, - opcode - IFEQ_OP+Operator.COMPARE_OP); - instr[addr+1] = new IfGotoOperator(addr+1, 2, - addr+stream.readShort()); - addr++; - break; - } - case IF_ICMPEQ_OP: case IF_ICMPNE_OP: case IF_ICMPLT_OP: - case IF_ICMPGE_OP: case IF_ICMPGT_OP: case IF_ICMPLE_OP: - instr[addr] = new CompareBinaryOperator - (addr, 1, ALL_INT_TYPE, - opcode - IF_ICMPEQ_OP+Operator.COMPARE_OP); - instr[addr+1] = new IfGotoOperator(addr+1, 2, - addr+stream.readShort()); - addr++; - break; - case IF_ACMPEQ_OP: case IF_ACMPNE_OP: - instr[addr] = new CompareBinaryOperator - (addr, 1, OBJECT_TYPE, - opcode - IF_ACMPEQ_OP+Operator.COMPARE_OP); - instr[addr+1] = new IfGotoOperator(addr+1, 2, - addr+stream.readShort()); - addr++; - break; - case GOTO_OP: - instr[addr] = new GotoOperator(addr, 3, addr+stream.readShort()); - break; - case JSR_OP: - instr[addr] = new JsrOperator(addr, 3, addr+stream.readShort()); - break; - case RET_OP: - instr[addr] = new RetOperator(addr, 3, stream.readUnsignedByte()); - break; - case TABLESWITCH_OP: { - int length = 3-(addr % 4); - stream.skip(length); - int def = addr + stream.readInt(); - int low = stream.readInt(); - int high = stream.readInt(); - int[] cases = new int[high-low+1]; - int[] dests = new int[high-low+2]; - for (int i=0; i+low <= high; i++) { - cases[i] = i+low; - dests[i] = addr + stream.readInt(); - } - dests[cases.length] = def; - length += 13 + 4 * cases.length; - instr[addr] = new SwitchOperator(addr, length, cases, dests); - break; - } - case LOOKUPSWITCH_OP: { - int length = 3-(addr % 4); - stream.skip(length); - int def = addr + stream.readInt(); - int npairs = stream.readInt(); - int[] cases = new int[npairs]; - int[] dests = new int[npairs+1]; - for (int i=0; i < npairs; i++) { - cases[i] = stream.readInt(); - dests[i] = addr + stream.readInt(); - } - dests[npairs] = def; - length += 9 + 8 * npairs; - instr[addr] = new SwitchOperator(addr, length, cases, dests); - break; - } - case IRETURN_OP: case LRETURN_OP: - case FRETURN_OP: case DRETURN_OP: case ARETURN_OP: { - Type retType = UnknownType.commonType - (method.mdef.getType().getReturnType(), - types[0][opcode-IRETURN_OP]); - instr[addr] = - new ReturnOperator(addr, 1, retType); - break; - } - case RETURN_OP: - instr[addr] = new ReturnOperator(addr, 1, Type.tVoid); - break; - case GETSTATIC_OP: - instr[addr] = - new GetFieldOperator(addr, 3, true, - (FieldDefinition)env.getConstant - (stream.readUnsignedShort())); - break; - case PUTSTATIC_OP: - instr[addr] = - new PutFieldOperator(addr, 3, true, - (FieldDefinition)env.getConstant - (stream.readUnsignedShort())); - break; - case GETFIELD_OP: - instr[addr] = new GetFieldOperator(addr, 3, false, - (FieldDefinition)env.getConstant - (stream.readUnsignedShort())); - break; - case PUTFIELD_OP: - instr[addr] = - new PutFieldOperator(addr, 3, false, - (FieldDefinition)env.getConstant - (stream.readUnsignedShort())); - break; - case INVOKEVIRTUAL_OP: - case INVOKESPECIAL_OP: - case INVOKESTATIC_OP : - instr[addr] = new InvokeOperator(addr, 3, - opcode == INVOKESTATIC_OP, - opcode == INVOKESPECIAL_OP, - (FieldDefinition)env.getConstant - (stream.readUnsignedShort())); - break; - case INVOKEINTERFACE_OP: { - instr[addr] = new InvokeOperator(addr, 5, - false, false, - (FieldDefinition)env.getConstant - (stream.readUnsignedShort())); - int reserved = stream.readUnsignedShort(); - break; - } - case NEW_OP: { - ClassDeclaration cldec = (ClassDeclaration) - env.getConstant(stream.readUnsignedShort()); - instr[addr] = new NewOperator(addr, 3, - Type.tClass(cldec.getName())); - break; - } - case NEWARRAY_OP: { - Type type; - switch (stream.readUnsignedByte()) { - case 4: type = Type.tBoolean; break; - case 5: type = Type.tChar ; break; - case 6: type = Type.tFloat ; break; - case 7: type = Type.tDouble ; break; - case 8: type = Type.tByte ; break; - case 9: type = Type.tShort ; break; - case 10: type = Type.tInt ; break; - case 11: type = Type.tLong ; break; - default: - throw new ClassFormatError("Invalid newarray operand"); - } - instr[addr] = new NewArrayOperator(addr, 2, type); - break; - } - case ANEWARRAY_OP: { - ClassDeclaration cldec = (ClassDeclaration) env.getConstant - (stream.readUnsignedShort()); - instr[addr] = new NewArrayOperator - (addr, 3, Type.tClass(cldec.getName())); - break; - } - case ARRAYLENGTH_OP: - instr[addr] = new ArrayLengthOperator(addr, 1); - break; - case ATHROW_OP: - instr[addr] = new ThrowOperator(addr, 1); - break; - case CHECKCAST_OP: { - ClassDeclaration cldec = (ClassDeclaration) env.getConstant - (stream.readUnsignedShort()); - instr[addr] = new CheckCastOperator - (addr, 3, Type.tClass(cldec.getName())); - break; - } - case INSTANCEOF_OP: { - ClassDeclaration cldec = (ClassDeclaration) env.getConstant - (stream.readUnsignedShort()); - instr[addr] = new InstanceOfOperator - (addr, 3, Type.tClass(cldec.getName())); - break; - } - case MONITORENTER_OP: - instr[addr] = new MonitorEnterOperator(addr, 1); - break; - case MONITOREXIT_OP: - instr[addr] = new MonitorExitOperator(addr, 1); - break; - case WIDE_OP: { - switch (opcode=stream.readUnsignedByte()) { - case ILOAD_OP: case LLOAD_OP: - case FLOAD_OP: case DLOAD_OP: case ALOAD_OP: - instr[addr] = new LoadOperator(addr, 3, - types[0][opcode-ILOAD_OP], - method.getLocal - (stream.readUnsignedShort())); - break; - case ISTORE_OP: case LSTORE_OP: - case FSTORE_OP: case DSTORE_OP: case ASTORE_OP: - instr[addr] = new StoreOperator(addr, 3, - types[0][opcode-ISTORE_OP], - method.getLocal - (stream.readUnsignedShort()), - Operator.ASSIGN_OP); - break; - case IINC_OP: { - int local = stream.readUnsignedShort(); - int value = stream.readUnsignedShort(); - int operation = Operator.ADD_OP; - if (value < 0) { - value = -value; - operation = Operator.NEG_OP; - } - instr[addr] = new ConstOperator(addr, 1, ALL_INT_TYPE, - Integer.toString(value)); - instr[addr+1] = - new StoreOperator(addr+1, 4, ALL_INT_TYPE, - method.getLocal(local), - operation + Operator.OPASSIGN_OP); - addr++; - break; - } - case RET_OP: - instr[addr] = - new RetOperator(addr, 3, stream.readUnsignedShort()); - break; - default: - throw new ClassFormatError("Invalid wide opcode "+opcode); - } - break; - } - case MULTIANEWARRAY_OP: { - ClassDeclaration cldec = (ClassDeclaration) env.getConstant - (stream.readUnsignedShort()); - int dimension = stream.readUnsignedByte(); - instr[addr] = new NewArrayOperator - (addr, 3, Type.tClass(cldec.getName()), dimension); - break; - } - case IFNULL_OP: case IFNONNULL_OP: - instr[addr] = new CompareUnaryOperator - (addr, 1, OBJECT_TYPE, - opcode - IFNULL_OP + Operator.COMPARE_OP); - instr[addr+1] = new IfGotoOperator(addr+1, 2, - addr+stream.readShort()); - addr++; - break; - case GOTO_W_OP: - instr[addr] = new GotoOperator(addr, 5, addr + stream.readInt()); - break; - case JSR_W_OP: - instr[addr] = new JsrOperator(addr, 5, addr + stream.readInt()); - break; - default: - throw new ClassFormatError("Invalid opcode "+opcode); - } - addr += instr[addr].getLength(); - if (stream.available() != instr.length-addr) { - throw new RuntimeException("invalid op size: "+opcode); - } - } - } catch (ClassCastException ex) { - ex.printStackTrace(); - throw new ClassFormatError("Constant has wrong type"); - } - } - + MethodAnalyzer method; + public JodeEnvironment env; + + /** + * Get the method. + * @return The method to which this code belongs. + */ + public MethodAnalyzer getMethod() {return method;} + void readCode(byte[] code) throws ClassFormatError { - instr = new Instruction[code.length]; - references = new int[code.length]; + InstructionHeader[] instr = new InstructionHeader[code.length]; + int returnCount; try { DataInputStream stream = new DataInputStream(new ByteArrayInputStream(code)); - readOpcodes(stream); + for (int addr = 0; addr < code.length; ) { + instr[addr] = Opcodes.readOpcode(addr, stream, this); + addr = instr[addr].getNextAddr(); + } } catch (IOException ex) { throw new ClassFormatError(ex.toString()); } - references[0]++; - for (int addr = 0; addr < code.length; - addr += instr[addr].getLength()) { - int[] successors = instr[addr].getSuccessors(); - for (int i=0; i < successors.length; i++) { - references[successors[i]]++; - } - } + methodHeader = new MethodInstructionHeader(instr); } void setExceptionHandler(BinaryExceptionHandler handler) { + /* tryAddrs.put(new Integer(handler.startPC), handler); references[handler.startPC]++; catchAddrs.put(new Integer(handler.handlerPC), handler); references[handler.handlerPC]++; + */ } + /* Instruction getInstruction(int addr) { return instr[addr]; } @@ -517,22 +61,30 @@ public class CodeAnalyzer implements Analyzer, Constants, Opcodes { void removeInstruction(int addr) { instr[addr] = null; } + */ static int WRONG = -3; static int SPECIAL = -2; static int FIRST = -1; int getPreviousAddr(int addr) { + /* int i; for (i = addr-1; i >= 0 && instr[i] == null; i--) {} return i; + */ + return addr; } int getNextAddr(int addr) { + /* return addr + instr[addr].getLength(); + */ + return addr; } int getPredecessor(int addr) { + /* if (references[addr] != 1) return WRONG; if (addr == 0) @@ -548,36 +100,19 @@ public class CodeAnalyzer implements Analyzer, Constants, Opcodes { if (successors[j] == addr) return i; } + */ return WRONG; } public void dumpSource(TabbedPrintWriter writer) throws java.io.IOException { - int[] successors = { 0}; - for (int addr = 0; addr < instr.length;) { - if (writer.verbosity > 5) { - writer.println("<"+addr + " - "+ - (addr+instr[addr].getLength()-1)+ - "> ["+references[addr]+"] : "+ - instr[addr].getClass().getName()); - writer.tab(); - } - int i; - for (i=0; i< successors.length && successors[i] != addr; i++) - {} - if (references[addr] != 1 || i == successors.length) - writer.print("addr_"+addr+": "); - instr[addr].dumpSource(writer, this); - - if (writer.verbosity > 5) - writer.untab(); - successors = instr[addr].getSuccessors(); - - for (i = instr[addr++].getLength()-1; i>0; i--) - if (instr[addr++] != null) - throw new AssertError ("dubious instr at addr "+addr); - } + InstructionHeader ih; + for (ih = methodHeader.getNextInstruction(); ih != null; + ih = ih.getNextInstruction()) { + + ih.dumpSource(writer); + } } public CodeAnalyzer(MethodAnalyzer ma, BinaryCode bc, JodeEnvironment e) @@ -585,6 +120,7 @@ public class CodeAnalyzer implements Analyzer, Constants, Opcodes { { method = ma; env = e; + bincode = bc; readCode(bincode.getCode()); BinaryExceptionHandler[] handlers = bincode.getExceptionHandlers(); for (int i=0; i 0) { + ih = ih.getUniquePredecessor(); + ArrayStoreOperator store2 = + (ArrayStoreOperator) ih.getInstruction(); + ih = ih.getUniquePredecessor(); + lastconst = (Expression) ih.getInstruction(); + ih = ih.getUniquePredecessor(); + Expression indexexpr = (Expression) ih.getInstruction(); + ConstOperator indexop = + (ConstOperator) indexexpr.getOperator(); + if (!MyType.isOfType(indexop.getType(), MyType.tUInt)) + return null; + int index = Integer.parseInt(indexop.getValue()); + if (index > lastindex) + return null; + while (index < lastindex) { + consts[lastindex] = new Expression + (new ConstOperator(MyType.tUnknown, ""), + new Expression[0]); + lastindex--; + } + consts[lastindex] = lastconst; + ih = ih.getUniquePredecessor(); + dup = (DupOperator) ih.getInstruction(); + if (dup.getDepth() != 0 || + dup.getCount() != store.getLValueType().stackSize()) + return null; + count++; + } + ih = ih.getUniquePredecessor(); + Expression newArrayExpr = (Expression) ih.getInstruction(); + NewArrayOperator newArrayOp = + (NewArrayOperator) newArrayExpr.getOperator(); + type = newArrayOp.getType(); + if (newArrayOp.getOperandCount() != 1) + return null; + Expression countexpr = + (Expression) newArrayExpr.getSubExpressions()[0]; + ConstOperator countop = + (ConstOperator) countexpr.getOperator(); + if (!MyType.isOfType(countop.getType(), MyType.tUInt)) + return null; + if (Integer.parseInt(countop.getValue()) != consts.length) + return null; + } catch (NullPointerException ex) { + return null; + } catch (ClassCastException ex) { + return null; + } + Operator op = new ConstantArrayOperator(type, consts.length); + ih.combine(4*count+1, new Expression(op, consts)); + return ih; + } + + public InstructionHeader createExpression(InstructionHeader ih) { + Operator op; + Expression exprs[]; + int count; + try { + op = (Operator) ih.getInstruction(); int params = op.getOperandCount(); - Expression exprs[] = new Expression[params]; - int addrs[] = new int[params+1]; - - addrs[params] = addr; + exprs = new Expression[params]; + count = 1; for (int i = params-1; i>=0; i--) { - addrs[i] = getPredecessor(addrs[i+1]); - if (addrs[i] < 0) - return -1; - exprs[i] = (Expression) instr[addrs[i]]; - if (exprs[i].isVoid()) - return -1; - } - length += addrs[params]-addrs[0]; - for (int i = 1; i <= params; i++) { - instr[addrs[i]] = null; - } - addr = addrs[0]; - instr[addr] = new Expression(addr, length, op, exprs); - return addr; + count++; + ih = ih.getUniquePredecessor(); + exprs[i] = (Expression) ih.getInstruction(); + if (exprs[i].isVoid()) { + if (i == params-1) + return null; + Expression e = exprs[i+1].tryToCombine(exprs[i]); + if (e == null) + return null; + i++; + exprs[i] = e; + } + } + } catch (NullPointerException ex) { + return null; } catch (ClassCastException ex) { - return -1; + return null; } + ih.combine(count, new Expression(op, exprs)); + return ih; } - public int combineExpressions(int addr) { - int count = 0; - int start = addr; - if (!(instr[addr] instanceof Expression) || - !((Expression)instr[addr]).isVoid()) - return -1; - do { - addr = getNextAddr(addr); - count++; - } while (addr < instr.length && - references[addr] == 1 && - instr[addr] instanceof Expression && - ((Expression)instr[addr]).isVoid()); - Expression[] expr = new Expression[count]; - addr = start; - for (int i=0; i < count; i++) { - expr[i] = (Expression)instr[addr]; - int next = getNextAddr(addr); - instr[addr] = null; - addr = next; +// public int combineExpressions(int addr) { +// int count = 0; +// int start = addr; +// if (!(instr[addr] instanceof Expression) || +// !((Expression)instr[addr]).isVoid()) +// return -1; +// do { +// addr = getNextAddr(addr); +// count++; +// } while (addr < instr.length && +// references[addr] == 1 && +// instr[addr] instanceof Expression && +// ((Expression)instr[addr]).isVoid()); +// Expression[] expr = new Expression[count]; +// addr = start; +// for (int i=0; i < count; i++) { +// expr[i] = (Expression)instr[addr]; +// int next = getNextAddr(addr); +// instr[addr] = null; +// addr = next; +// } +// instr[start] = new Block(start, addr-start, expr); +// return start; +// } + + public InstructionHeader createAssignExpression(InstructionHeader ih) { + StoreInstruction store; + try { + store = (StoreInstruction) ih.getInstruction(); + ih = ih.getUniquePredecessor(); + + DupOperator dup = (DupOperator) ih.getInstruction(); + if (dup.getDepth() != store.getLValueOperandCount() && + dup.getCount() != store.getLValueType().stackSize()) + return null; + } catch (NullPointerException ex) { + return null; + } catch (ClassCastException ex) { + return null; } - instr[start] = new Block(start, addr-start, expr); - return start; + ih.combine(2, new AssignOperator(Operator.ASSIGN_OP, store)); + return ih; } - public int createAssignExpression(int addr) { + public InstructionHeader createLocalPostIncExpression(InstructionHeader ih) + { + IIncOperator iinc; + int op; + Type type; try { - StoreInstruction store = (StoreInstruction) instr[addr]; - int dupAddr = getPreviousAddr(addr); - if (dupAddr < 0 || references[dupAddr] != 1) - return -1; - DupOperator dup = (DupOperator) instr[dupAddr]; - if (dup.getDepth() != store.getLValueOperandCount() && - dup.getLength() != store.getLValueType().stackSize()) - return -1; - int end = getNextAddr(addr); - instr[dupAddr] = new AssignOperator(dupAddr, end-dupAddr, - Operator.ASSIGN_OP, store); - instr[addr] = null; - return dupAddr; + Expression iincExpr = (Expression) ih.getInstruction(); + iinc = (IIncOperator) iincExpr.getOperator(); + if (iinc.getOperator() == iinc.ADD_OP + iinc.OPASSIGN_OP) + op = Operator.INC_OP; + else if (iinc.getOperator() == iinc.NEG_OP + iinc.OPASSIGN_OP) + op = Operator.DEC_OP; + else + return null; + if (!iinc.getValue().equals("1") && + !iinc.getValue().equals("-1")) + return null; + if (iinc.getValue().equals("-1")) + op ^= 1; + ih = ih.getUniquePredecessor(); + Expression loadExpr = (Expression) ih.getInstruction(); + LocalLoadOperator load = + (LocalLoadOperator)loadExpr.getOperator(); + if (!iinc.matches(load)) + return null; + + type = MyType.intersection(load.getType(), MyType.tUInt); + } catch (NullPointerException ex) { + return null; } catch (ClassCastException ex) { - return -1; + return null; } + Operator postop = new LocalPostFixOperator(type, op, iinc); + ih.combine(2, postop); + return ih; } - public int createPostIncExpression(int addr) { + public InstructionHeader createPostIncExpression(InstructionHeader ih) { + StoreInstruction store; + int op; + Type type; try { - int op; - Expression storeExpr = (Expression) instr[addr]; - StoreOperator store = (StoreOperator) storeExpr.getOperator(); - if (store.getOperator() == store.ADD_OP+store.OPASSIGN_OP) + store = (StoreInstruction) ih.getInstruction(); + if (store.getLValueOperandCount() == 0) + return null; + ih = ih.getUniquePredecessor(); + BinaryOperator binOp = (BinaryOperator) ih.getInstruction(); + if (binOp.getOperator() == store.ADD_OP) op = Operator.INC_OP; - else if (store.getOperator() == store.NEG_OP+store.OPASSIGN_OP) - op = Operator.INC_OP+1; + else if (store.getOperator() == store.NEG_OP) + op = Operator.DEC_OP; else - return -1; - Expression expr = storeExpr.getSubExpressions()[0]; + return null; + ih = ih.getUniquePredecessor(); + Expression expr = (Expression) ih.getInstruction(); ConstOperator constOp = (ConstOperator) expr.getOperator(); - if (!constOp.getValue().equals("1")) - return -1; - int loadAddr = getPreviousAddr(addr); - if (loadAddr < 0 || references[loadAddr] != 1) - return -1; - Expression loadExpr = (Expression) instr[loadAddr]; - LoadOperator load = (LoadOperator) loadExpr.getOperator(); - if (load.getSlot() != store.getSlot()) - return -1; - int end = getNextAddr(addr); - Operator postop = - new PostFixOperator(loadAddr, end-loadAddr, - loadExpr.getType(), op); - Expression [] exprs = { loadExpr }; - instr[loadAddr] = new Expression - (loadAddr, end-loadAddr, postop, exprs); - instr[addr] = null; - return loadAddr; + if (!constOp.getValue().equals("1") && + !constOp.getValue().equals("-1")) + return null; + if (constOp.getValue().equals("-1")) + op ^= 1; + ih = ih.getUniquePredecessor(); + DupOperator dup = (DupOperator) ih.getInstruction(); + if (dup.getCount() != store.getLValueType().stackSize() || + dup.getDepth() != store.getLValueOperandCount()) + return null; + ih = ih.getUniquePredecessor(); + Operator load = (Operator) ih.getInstruction(); + + if (!store.matches(load)) + return null; + + ih = ih.getUniquePredecessor(); + DupOperator dup2 = (DupOperator) ih.getInstruction(); + if (dup2.getCount() != store.getLValueOperandCount() || + dup2.getDepth() != 0) + return null; + + type = MyType.intersection(load.getType(), store.getLValueType()); + } catch (NullPointerException ex) { + return null; } catch (ClassCastException ex) { - return -1; + return null; } + Operator postop = new PostFixOperator(type, op, store); + ih.combine(6, postop); + return ih; } - public int createArrayOpAssign(int addr) { + public InstructionHeader createAssignOp(InstructionHeader ih) { + Expression rightHandSide; + StoreInstruction store; + BinaryOperator binop; try { - StoreInstruction store = (StoreInstruction) instr[addr]; - int binOpAddr = getPreviousAddr(addr); - if (binOpAddr < 0 || references[binOpAddr] != 1) - return -1; - BinaryOperator binop = (BinaryOperator) instr[binOpAddr]; + store = (StoreInstruction) ih.getInstruction(); + ih = ih.getUniquePredecessor(); + binop = (BinaryOperator) ih.getInstruction(); if (binop.getOperator() < binop.ADD_OP || binop.getOperator() >= binop.ASSIGN_OP) - return -1; - int exprAddr = getPreviousAddr(binOpAddr); - if (exprAddr < 0 || references[exprAddr] != 1) - return -1; - Expression expr = (Expression) instr[exprAddr]; - int loadAddr = getPreviousAddr(exprAddr); - if (loadAddr < 0 || references[loadAddr] != 1) - return -1; - Operator load = - (Operator) instr[loadAddr]; - if (load.getType() != store.getLValueType()) - return -1; + return null; + ih = ih.getUniquePredecessor(); + rightHandSide = (Expression) ih.getInstruction(); + if (rightHandSide.isVoid()) + return null; /* XXX */ + ih = ih.getUniquePredecessor(); + Operator load = (Operator) ih.getInstruction(); if (!store.matches(load)) - return -1; - int dupAddr = getPreviousAddr(loadAddr); - if (dupAddr < 0) - return -1; - DupOperator dup = (DupOperator) instr[dupAddr]; + return null; + ih = ih.getUniquePredecessor(); + DupOperator dup = (DupOperator) ih.getInstruction(); if (dup.getDepth() != 0 && - dup.getLength() != store.getLValueOperandCount()) - return -1; - int end = getNextAddr(addr); - instr[dupAddr] = new Expression - (dupAddr, binOpAddr-dupAddr, - expr.getOperator(), expr.getSubExpressions()); - instr[binOpAddr] = store; - store.setAddr(binOpAddr); - store.setLength(end-binOpAddr); - store.setOperator(store.OPASSIGN_OP+binop.getOperator()); - store.setLValueType - (UnknownType.commonType(binop.getType(), - store.getLValueType())); - instr[loadAddr] = instr[exprAddr] = - instr[addr] = null; - return dupAddr; + dup.getCount() != store.getLValueOperandCount()) + return null; } catch (ClassCastException ex) { - return -1; + return null; + } catch (NullPointerException ex) { + return null; } + ih.combine(3, rightHandSide); + InstructionHeader storeIH = ih.getNextInstruction(); + store.setOperator(store.OPASSIGN_OP+binop.getOperator()); + store.setLValueType(MyType.intersection(binop.getType(), + store.getLValueType())); + storeIH.combine(2, store); + return ih; } - public int combineNewConstructor(int addr) { + public InstructionHeader combineNewConstructor(InstructionHeader ih) { + InvokeOperator constrCall; + Expression exprs[]; try { - InvokeOperator constrCall = (InvokeOperator) instr[addr]; + constrCall = (InvokeOperator) ih.getInstruction(); if (!constrCall.isConstructor()) - return -1; - int length = instr[addr].getLength(); + return null; int params = constrCall.getOperandCount(); - Expression exprs[] = new Expression[params]; - int addrs[] = new int[params+1]; - addrs[params] = addr; + exprs = new Expression[params]; for (int i = params-1; i>0; i--) { - addrs[i] = getPredecessor(addrs[i+1]); - if (addrs[i] < 0) - return -1; - exprs[i] = (Expression) instr[addrs[i]]; + ih = ih.getUniquePredecessor(); + exprs[i] = (Expression) ih.getInstruction(); if (exprs[i].isVoid()) - return -1; + return null; /* XXX */ } - addrs[0] = getPredecessor(addrs[1]); - DupOperator dup = (DupOperator) instr[addrs[0]]; + ih = ih.getUniquePredecessor(); + DupOperator dup = (DupOperator) ih.getInstruction(); if (dup.getCount() != 1 && dup.getDepth() != 0) - return -1; - addr = getPredecessor(addrs[0]); - exprs[0] = (Expression) instr[addr]; + return null; + ih = ih.getUniquePredecessor(); + exprs[0] = (Expression) ih.getInstruction(); if (exprs[0].isVoid()) - return -1; + return null; NewOperator op = (NewOperator) exprs[0].getOperator(); if (constrCall.getClassType() != op.getType()) - return -1; - length += addrs[params]-addr; - for (int i = 0; i <= params; i++) { - instr[addrs[i]] = null; - } - ConstructorOperator conOp = - new ConstructorOperator(addr, length, - constrCall.getClassType(), - constrCall.getField()); - instr[addr] = new Expression(addr, length, conOp, exprs); - return addr; + return null; } catch (ClassCastException ex) { - return -1; + return null; + } catch (NullPointerException ex) { + return null; } - } + ConstructorOperator conOp = + new ConstructorOperator(constrCall.getClassType(), + constrCall.getField()); -// public int createIfGotoStatement(int addr) { -// if (references[addr] != 1) -// return -1; -// Expression e; -// int condAddr, dest; -// try { -// IfGotoOperator igo = (IfGotoOperator) instr[addr]; -// condAddr = getPreviousAddr(addr); -// if (condAddr < 0) -// return -1; -// e = (Expression) instr[condAddr]; -// if (e.isVoid()) -// return -1; -// dest = igo.getDestination(); -// } catch (ClassCastException ex) { -// return -1; -// } -// int end = getNextAddr(addr); -// instr[condAddr] = new IfGotoStatement(condAddr, end-condAddr, dest, e); -// instr[addr] = null; -// return condAddr; -// } + ih.combine(exprs.length+2, new Expression(conOp, exprs)); + return ih; + } - public int combineIfGotoExpressions(int addr) { - Expression e[]; - int if1Addr; - int end = getNextAddr(addr); + public InstructionHeader combineIfGotoExpressions(InstructionHeader ih2) { + InstructionHeader ih1; + Expression[] e; int operator; - IfGotoOperator igo2; try { - igo2 = (IfGotoOperator) - ((Expression)instr[addr]).getOperator(); - int dest = igo2.getDestination(); - if1Addr = getPreviousAddr(addr); - if (if1Addr < 0 || references[if1Addr] != 1) - return -1; - IfGotoOperator igo1 = (IfGotoOperator) - ((Expression)instr[if1Addr]).getOperator(); - if (igo1.getDestination() == end) { + if (ih2.switchType != MyType.tBoolean) + return null; + InstructionHeader[] dests2 = ih2.getSuccessors(); + + /* if ih2.getUniquePredecessor.getOperator().isVoid() XXX */ + + Vector predec = ih2.getPredecessors(); + if (predec.size() != 1) + return null; + + ih1 = (InstructionHeader) predec.elementAt(0); + if (ih1.switchType != MyType.tBoolean) + return null; + InstructionHeader[] dests1 = ih1.getSuccessors(); + if (dests1[0] != ih2) + return null; + + if (dests1[1] == dests2[0]) { e = new Expression[2]; operator = Operator.LOG_AND_OP; - e[1] = ((Expression)instr[addr]).getSubExpressions()[0]; - e[0] = ((Expression)instr[if1Addr]). - getSubExpressions()[0].negate(); - references[end]--; - } else if (igo1.getDestination() == dest) { + e[1] = (Expression)ih2.getInstruction(); + e[0] = ((Expression)ih2.getInstruction()).negate(); + } else if (dests1[1] == dests2[1]) { e = new Expression[2]; operator = Operator.LOG_OR_OP; - e[1] = ((Expression)instr[addr]).getSubExpressions()[0]; - e[0] = ((Expression)instr[if1Addr]).getSubExpressions()[0]; - references[dest]--; + e[1] = (Expression)ih2.getInstruction(); + e[0] = (Expression)ih2.getInstruction(); } else - return -1; + return null; } catch (ClassCastException ex) { - return -1; + return null; + } catch (NullPointerException ex) { + return null; } - Expression[] cond = - { new Expression(if1Addr, end-if1Addr, - new BinaryOperator(if1Addr, end-if1Addr, - Type.tBoolean, operator), e) }; - instr[if1Addr] = new Expression(if1Addr, end-if1Addr, igo2, cond); - instr[addr] = null; - return if1Addr; + + Expression cond = + new Expression(new BinaryOperator(Type.tBoolean, operator), e); + + ih1.combineConditional(cond); + return ih1; } - public int combineConditionalExpr(int addr) { - if (references[addr] != 1) - return -1; + public InstructionHeader createIfThenElseOperator(InstructionHeader ih) { + InstructionHeader ifHeader; Expression e[] = new Expression[3]; - int ifAddr, gotoAddr, e1Addr; - int end = getNextAddr(addr); + InstructionHeader[] succs; try { - e[2] = (Expression) instr[addr]; - if (e[2].isVoid()) - return -1; - gotoAddr = getPreviousAddr(addr); - if (gotoAddr < 0 || references[gotoAddr] != 1) - return -1; - if (((GotoOperator) - ((Expression)instr[gotoAddr]).getOperator()) - .getDestination() != end) - return -1; - e1Addr = getPreviousAddr(gotoAddr); - if (e1Addr <0 || references[e1Addr] != 1) - return -1; - e[1] = (Expression) instr[e1Addr]; - if (e[1].isVoid()) - return -1; - ifAddr = getPreviousAddr(e1Addr); - if (ifAddr < 0) - return -1; - e[0] = (Expression)instr[ifAddr]; - IfGotoOperator igo = (IfGotoOperator) e[0].getOperator(); - if (igo.getDestination() != addr) - return -1; - e[0] = e[0].getSubExpressions()[0].negate(); + Vector predec = ih.getPredecessors(); + + if (predec.size() != 1) + return null; + ifHeader = (InstructionHeader) predec.elementAt(0); + if (ifHeader.switchType != Type.tBoolean) + return null; + succs = ifHeader.getSuccessors(); + if (succs[1] != ih || + succs[0].getNextInstruction() != succs[1] || + succs[0].getSuccessors().length != 1 || + succs[1].getSuccessors().length != 1 || + succs[0].getSuccessors()[0] != succs[1].getSuccessors()[0]) + return null; + + e[0] = (Expression) ifHeader.getInstruction(); + e[1] = (Expression) succs[0].getInstruction(); + e[2] = (Expression) succs[1].getInstruction(); } catch (ClassCastException ex) { - return -1; + return null; + } catch (NullPointerException ex) { + return null; } IfThenElseOperator iteo = new IfThenElseOperator - (ifAddr, end-ifAddr, - UnknownType.commonType(e[1].getType(),e[2].getType())); - instr[ifAddr] = new Expression(ifAddr, end-ifAddr, iteo, e); - instr[e1Addr] = instr[gotoAddr] = instr[addr] = null; - references[end]--; - return ifAddr; + (MyType.intersection(e[1].getType(),e[2].getType())); + ifHeader.instr = new Expression(iteo, e); + ifHeader.nextInstruction = ih.nextInstruction; + ifHeader.successors = ih.successors; + ifHeader.switchType = Type.tVoid; + ifHeader.nextInstruction.predecessors.removeElement(succs[0]); + ifHeader.nextInstruction.predecessors.removeElement(succs[1]); + ifHeader.nextInstruction.predecessors.addElement(ifHeader); + return ifHeader; } - public void analyzeLocals() + public void analyze() { - for (int slot=0; slot< bincode.maxLocals(); slot++) { - LocalVariable localVar = method.getLocal(slot); - int storeAddr[] = new int[instr.size]; - for (int i=0; i< instr.size; i++) { - storeAddr[i] = -1; - - Stack addrStack = new Stack(); - addrStack.push(new Integer(0)); - storeAddr[0] = 0; - - while (!addrStack.isEmpty()) { - int[] successors; - int addr = ((Integer)addrStack.pop()).intValue(); - - int store = infos[addr]; - if (instr[addr] instanceof StoreOperator) { - store = addr; - } else if (instr[addr] instanceof LoadOperator) { - localVar.combine(store, addr); - } - successors = instr[addr].getSuccessors(); - addr = (successors.length==1)?successor[0]; - - /* XXX try - catch blocks */ - - LocalInfo nextInfo = localVar.getInfo(store); - for (int i=0; i< successors.length; i++) { - if (info[successors[i]] != -1) { - if (nextInfo == localVar.getInfo(info[successors[i]])) - continue; - localVar.combine(info[successors[i]], store); - } else - info[successors[i]] = store; - addrStack.push(successors[i]); - } - } + InstructionHeader ih, next; + for (ih = methodHeader.getNextInstruction(); ih != null; + ih = next) { + if (env.isVerbose) + System.err.print("."); + if ((next = removeNop(ih)) != null) continue; + if ((next = createExpression(ih)) != null) continue; + if ((next = createPostIncExpression(ih)) != null) continue; + if ((next = createLocalPostIncExpression(ih)) != null) continue; + if ((next = createAssignOp(ih)) != null) continue; + if ((next = combineNewConstructor(ih)) != null) continue; + if ((next = combineIfGotoExpressions(ih)) != null) continue; + if ((next = createIfThenElseOperator(ih)) != null) continue; + if ((next = createAssignExpression(ih)) != null) continue; + if ((next = createConstantArray(ih)) != null) continue; + next = ih.getNextInstruction(); } - } - public void analyze() - { - for (int addr = 0; addr < instr.length; ) { - int nextAddr; - nextAddr = createExpression(addr); - if (nextAddr >= 0) { - addr = nextAddr; - continue; - } - nextAddr = createAssignExpression(addr); - if (nextAddr >= 0) { - addr = nextAddr; - continue; - } - nextAddr = createArrayOpAssign(addr); - if (nextAddr >= 0) { - addr = nextAddr; - continue; - } - nextAddr = createPostIncExpression(addr); - if (nextAddr >= 0) { - addr = nextAddr; - continue; - } - nextAddr = combineNewConstructor(addr); - if (nextAddr >= 0) { - addr = nextAddr; - continue; - } -// nextAddr = createIfGotoStatement(addr); + for (ih = methodHeader.getNextInstruction(); ih != null; + ih = ih.getNextInstruction()) { + ih.instr = ih.getInstruction().simplify(); + } +// for (int addr = 0; addr < instr.length; ) { +// int nextAddr; +// nextAddr = createExpression(addr); // if (nextAddr >= 0) { // addr = nextAddr; // continue; // } - nextAddr = combineIfGotoExpressions(addr); - if (nextAddr >= 0) { - addr = nextAddr; - continue; - } - nextAddr = combineConditionalExpr(addr); - if (nextAddr >= 0) { - addr = nextAddr; - continue; - } - addr += instr[addr].getLength(); - } - for (int addr = 0; addr < instr.length; ) { - int nextAddr; - nextAddr = combineExpressions(addr); - if (nextAddr >= 0) { - addr = nextAddr; - continue; - } - addr += instr[addr].getLength(); - } - } - - public String getLocalName(int i, int addr) { - return method.getLocalName(i, addr).toString(); +// nextAddr = createAssignExpression(addr); +// if (nextAddr >= 0) { +// addr = nextAddr; +// continue; +// } +// nextAddr = createArrayOpAssign(addr); +// if (nextAddr >= 0) { +// addr = nextAddr; +// continue; +// } +// nextAddr = createPostIncExpression(addr); +// if (nextAddr >= 0) { +// addr = nextAddr; +// continue; +// } +// // nextAddr = createIfGotoStatement(addr); +// // if (nextAddr >= 0) { +// // addr = nextAddr; +// // continue; +// // } +// nextAddr = combineIfGotoExpressions(addr); +// if (nextAddr >= 0) { +// addr = nextAddr; +// continue; +// } +// nextAddr = combineConditionalExpr(addr); +// if (nextAddr >= 0) { +// addr = nextAddr; +// continue; +// } +// addr += instr[addr].getLength(); +// } +// for (int addr = 0; addr < instr.length; ) { +// int nextAddr; +// nextAddr = combineExpressions(addr); +// if (nextAddr >= 0) { +// addr = nextAddr; +// continue; +// } +// addr += instr[addr].getLength(); +// } } public String getTypeString(Type type) { diff --git a/jode/jode/decompiler/FieldAnalyzer.java b/jode/jode/decompiler/FieldAnalyzer.java index 1ec371c..6f74450 100644 --- a/jode/jode/decompiler/FieldAnalyzer.java +++ b/jode/jode/decompiler/FieldAnalyzer.java @@ -15,6 +15,13 @@ public class FieldAnalyzer implements Analyzer { public void analyze() { } + public int unsigned(byte value) { + if (value < 0) + return value + 256; + else + return value; + } + public void dumpSource(TabbedPrintWriter writer) throws java.io.IOException { @@ -22,15 +29,14 @@ public class FieldAnalyzer implements Analyzer { if (modif.length() > 0) writer.print(modif+" "); - writer.println(fdef.getType(). - typeString(fdef.getName().toString(), false, false)+";"); -// writer.tab(); -// if (attributes.length > 0) { -// writer.println("/* Attributes: "+attributes.length+" */"); -// for (int i=0; i < attributes.length; i++) -// attributes[i].dumpSource(writer); -// } -// writer.untab(); + writer.print(env.getTypeString(fdef.getType(), fdef.getName())); + byte[] attrib = + ((BinaryField) fdef).getAttribute(Constants.idConstantValue); + if (attrib != null) { + int index = (unsigned(attrib[0]) << 8) | unsigned(attrib[1]); + writer.print(" = "+env.getConstant(index).toString()); + } + writer.println(";"); } } diff --git a/jode/jode/decompiler/ImportHandler.java b/jode/jode/decompiler/ImportHandler.java index ab8a70b..d071092 100644 --- a/jode/jode/decompiler/ImportHandler.java +++ b/jode/jode/decompiler/ImportHandler.java @@ -8,10 +8,12 @@ public class JodeEnvironment extends LoadEnvironment { BinaryClass main; Identifier pkg; - boolean isVerbose = true; + public boolean isVerbose = false; + public boolean isDebugging = false; JodeEnvironment() { super(null); + MyType.setEnvironment(this); path = new ClassPath(System.getProperty("java.class.path")); } @@ -38,8 +40,16 @@ public class JodeEnvironment extends LoadEnvironment { } } - public String getNickName(String string) { - return string; + public String getTypeString(Type type) { + return type.toString(); + } + + public String getTypeString(Identifier clazz) { + return clazz.toString(); + } + + public String getTypeString(Type type, Identifier name) { + return type.typeString(name.toString(), false, false); } public ClassDefinition getClassDefinition() { @@ -81,6 +91,7 @@ public class JodeEnvironment extends LoadEnvironment { a.analyze(); TabbedPrintWriter writer = new TabbedPrintWriter(System.out, " "); + writer.verbosity = isDebugging?10:0; a.dumpSource(writer); } catch (ClassNotFound e) { error(e.toString()); diff --git a/jode/jode/decompiler/LocalInfo.java b/jode/jode/decompiler/LocalInfo.java index 04ef789..96199d8 100644 --- a/jode/jode/decompiler/LocalInfo.java +++ b/jode/jode/decompiler/LocalInfo.java @@ -1,15 +1,106 @@ package jode; import sun.tools.java.*; +/** + * The LocalInfo represents a local variable of a method. + * The problem is that two different local variables may use the same + * slot. The current strategie is to make the range of a local variable + * as small as possible. + * + * There may be more than one LocalInfo for a single local variable, + * because the algorithm begins with totally disjunct variables and + * then unifies locals. One of the local is then a shadow object which + * calls the member functions of the other local. + */ public class LocalInfo { - static int serialnr = 0; - Identifier name; - Type type; + private static int serialnr = 0; + private Identifier name; + private Type type; + private LocalInfo shadow; - public LocalInfo() { - name = Identifier.lookup("__"+serialnr); - type = Type.tUnknown; + /** + * Create a new local info. The name will be an identifier + * of the form local_x__yyy, where x is the slot number and + * yyy a unique number. + * @param slot The slot of this variable. + */ + public LocalInfo(int slot) { + name = Identifier.lookup("local_"+slot+"__"+serialnr); + type = MyType.tUnknown; serialnr++; } + + /** + * Combines the LocalInfo with another. This will make this + * a shadow object to the other local info. That is all member + * functions will use the new local info instead of data in this + * object.

+ * If this is called with ourself nothing will happen. + * @param li the local info that we want to shadow. + */ + public void combineWith(LocalInfo li) { + if (this == li) + return; + if (shadow != null) + shadow.combineWith(li); + shadow = li; + } + + /** + * Get the real LocalInfo. This may be different from the + * current object if this is a shadow local info. + */ + public LocalInfo getLocalInfo() { + if (shadow != null) + return shadow.getLocalInfo(); + return this; + } + + /** + * Get the name of this local. + */ + public Identifier getName() { + if (shadow != null) + return shadow.getName(); + return name; + } + + /** + * Set the name of this local. + */ + public void setName(Identifier name) { + if (shadow != null) + shadow.setName(name); + else + this.name = name; + } + + /** + * Get the type of this local. + */ + public Type getType() { + if (shadow != null) + return shadow.getType(); + return type; + } + + /** + * Sets a new information about the type of this local. + * The type of the local is may be made more specific by this call. + * @param The new type information to be set. + * @return The new type of the local. + */ + public Type setType(Type newType) { + if (shadow != null) + return shadow.setType(type); + this.type = MyType.intersection(this.type, newType); + if (this.type == MyType.tError) + System.err.println("Type error in "+name.toString()); + return this.type; + } + + public boolean isShadow() { + return (shadow != null); + } } diff --git a/jode/jode/decompiler/LocalVariable.java b/jode/jode/decompiler/LocalVariable.java index 404e186..a1057f5 100644 --- a/jode/jode/decompiler/LocalVariable.java +++ b/jode/jode/decompiler/LocalVariable.java @@ -3,8 +3,6 @@ import sun.tools.java.Type; import sun.tools.java.Identifier; public interface LocalVariable { - public Identifier getName(int addr); - public Type getType(int addr); - public Type setType(int addr, Type type); + public LocalInfo getInfo(int addr); public void combine(int addr1, int addr2); } diff --git a/jode/jode/decompiler/LocalVariableAnalyzer.java b/jode/jode/decompiler/LocalVariableAnalyzer.java new file mode 100644 index 0000000..7034165 --- /dev/null +++ b/jode/jode/decompiler/LocalVariableAnalyzer.java @@ -0,0 +1,206 @@ +package jode; +import sun.tools.java.*; +import java.io.*; +import java.util.*; + +public class LocalVariableAnalyzer { + + Vector locals; + + LocalInfo[] argLocals; + LocalVariableTable lvt; + JodeEnvironment env; + FieldDefinition mdef; + int maxlocals; + + LocalVariableAnalyzer(JodeEnvironment env, FieldDefinition mdef, + int maxlocals) { + this.env = env; + this.mdef = mdef; + this.maxlocals = maxlocals; + locals = new Vector(); + } + + /** + * Reads the local variable table from the class file + * if it exists. + */ + public void read(BinaryCode bc) { + BinaryAttribute attr = bc.getAttributes(); + while (attr != null) { + if (attr.getName() == Constants.idLocalVariableTable) { + DataInputStream stream = + new DataInputStream + (new ByteArrayInputStream(attr.getData())); + try { + lvt = new LocalVariableTable(maxlocals); + lvt.read(env, stream); + } catch (IOException ex) { + throw new ClassFormatError(ex.toString()); + } + } + attr = attr.getNextAttribute(); + } + } + + /** + * This method combines to LocalInfos to a single one. + * It also handles the special cases where one or both LocalInfo + * are null. + */ + private LocalInfo combine(int slot, LocalInfo li1, LocalInfo li2) { + if (li1 == null && li2 == null) { + li2 = new LocalInfo(slot); + locals.addElement(li2); + } else if (li1 != null && li2 != null) + li1.combineWith(li2.getLocalInfo()); + else if (li2 == null) + li2 = li1; + + return li2.getLocalInfo(); + } + + public void analyze(MethodInstructionHeader mih) { + + Hashtable done = new Hashtable(); + Stack instrStack = new Stack(); + Stack readsStack = new Stack(); + + LocalInfo[] reads = new LocalInfo[maxlocals]; + + Enumeration predec = mih.getPredecessors().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(); + + if (env.isVerbose) + System.err.print("."); +// 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 li.start+li.length) li = li.next; if (li == null || li.start > addr) { - LocalInfo temp =new LocalInfo(); + LocalInfo temp = new LocalInfo(slot); return temp; } return li; @@ -53,30 +54,15 @@ public class LocalVariableRangeList implements LocalVariable { public void addLocal(int start, int length, Identifier name, Type type) { - MyLocalInfo li = new MyLocalInfo(start,length,name,type); + MyLocalInfo li = new MyLocalInfo(slot,start,length,name,type); add (li); } - public Identifier getName(int addr) { - LocalInfo li = find(addr); - return li.name; - } - - public Type getType(int addr) { - LocalInfo li = find(addr); - return li.type; - } - public LocalInfo getInfo(int addr) { return find(addr); } - public Type setType(int addr, Type newType) { - LocalInfo li = find(addr); - return commonType(newType, li.type); - } - public void combine(int addr1, int addr2) { - throw AssertError("combine called on RangeList"); + throw new AssertError("combine called on RangeList"); } } diff --git a/jode/jode/decompiler/LocalVariableTable.java b/jode/jode/decompiler/LocalVariableTable.java index ca811e8..c4fed19 100644 --- a/jode/jode/decompiler/LocalVariableTable.java +++ b/jode/jode/decompiler/LocalVariableTable.java @@ -1,18 +1,20 @@ package jode; import sun.tools.java.*; import java.io.*; -import java.util.Vector; public class LocalVariableTable { - Vector locals; + LocalVariableRangeList[] locals; boolean readfromclass; public LocalVariableTable(int size) { - locals = new Vector(); - locals.setSize(size); + locals = new LocalVariableRangeList[size]; readfromclass = false; } + public int getSize() { + return locals.length; + } + public boolean isReadFromClass() { return readfromclass; } @@ -22,16 +24,15 @@ public class LocalVariableTable { { int count = stream.readUnsignedShort(); for (int i=0; i0) writer.print(", "); - writer.print(paramTypes[i]. - typeString(getLocalName(i+offset, 0).toString(), - false, false)); + writer.print + ((code == null)? + env.getTypeString(paramTypes[i]): + env.getTypeString + (paramTypes[i], lva.getLocal(i+offset).getName())); } writer.print(")"); } @@ -110,13 +84,14 @@ public class MethodAnalyzer implements Analyzer, Constants { if (exceptions[i] != null) { if (i > 0) writer.print(", "); - writer.print(exceptions[i].getName().toString()); + writer.print(env.getTypeString(exceptions[i].getName())); } } } if (code != null) { writer.println(" {"); writer.tab(); + lva.dumpSource(writer); code.dumpSource(writer); writer.untab(); writer.println("}"); diff --git a/jode/jode/decompiler/TabbedPrintWriter.java b/jode/jode/decompiler/TabbedPrintWriter.java index 765c5e7..afa6ff2 100644 --- a/jode/jode/decompiler/TabbedPrintWriter.java +++ b/jode/jode/decompiler/TabbedPrintWriter.java @@ -6,7 +6,7 @@ public class TabbedPrintWriter { String tabstr; StringBuffer indent; PrintWriter pw; - int verbosity=100; + int verbosity=0; public TabbedPrintWriter (OutputStream os, String tabstr) { pw = new PrintWriter(os); diff --git a/jode/jode/expr/ArrayLengthOperator.java b/jode/jode/expr/ArrayLengthOperator.java index a2adbc7..6c594dc 100644 --- a/jode/jode/expr/ArrayLengthOperator.java +++ b/jode/jode/expr/ArrayLengthOperator.java @@ -5,9 +5,9 @@ public class ArrayLengthOperator extends Operator { Type arrayType; - public ArrayLengthOperator(int addr, int length) { - super(addr,length, Type.tInt, 0); - arrayType = Type.tArray(UnknownType.tUnknown); + public ArrayLengthOperator() { + super(Type.tInt, 0); + arrayType = Type.tArray(MyType.tUnknown); } public int getPriority() { @@ -27,10 +27,10 @@ public class ArrayLengthOperator extends Operator { } public void setOperandType(Type[] types) { - arrayType = UnknownType.commonType(arrayType,types[0]); + arrayType = MyType.intersection(arrayType,types[0]); } - public String toString(CodeAnalyzer ca, String[] operands) { + public String toString(String[] operands) { return operands[0] + ".length"; } } diff --git a/jode/jode/expr/ArrayLoadOperator.java b/jode/jode/expr/ArrayLoadOperator.java index ca1b9d0..8a4d433 100644 --- a/jode/jode/expr/ArrayLoadOperator.java +++ b/jode/jode/expr/ArrayLoadOperator.java @@ -5,10 +5,10 @@ import sun.tools.java.ArrayType; public class ArrayLoadOperator extends SimpleOperator { String value; - public ArrayLoadOperator(int addr, int length, Type type) { - super(addr,length, type, 0, 2); + public ArrayLoadOperator(Type type) { + super(type, 0, 2); operandTypes[0] = Type.tArray(type); - operandTypes[1] = UnknownType.tUIndex; + operandTypes[1] = MyType.tUIndex; } public int getPriority() { @@ -34,13 +34,13 @@ public class ArrayLoadOperator extends SimpleOperator { public void setOperandType(Type[] t) { super.setOperandType(t); - if (operandTypes[0] instanceof ArrayType) +// if (operandTypes[0] instanceof ArrayType) type = operandTypes[0].getElementType(); - else - type = Type.tError; +// else +// type = Type.tError; } - public String toString(CodeAnalyzer ca, String[] operands) { + public String toString(String[] operands) { return operands[0]+"["+operands[1]+"]"; } } diff --git a/jode/jode/expr/ArrayStoreOperator.java b/jode/jode/expr/ArrayStoreOperator.java index 6bf029e..ab6b4c2 100644 --- a/jode/jode/expr/ArrayStoreOperator.java +++ b/jode/jode/expr/ArrayStoreOperator.java @@ -5,16 +5,16 @@ import sun.tools.java.ArrayType; public class ArrayStoreOperator extends StoreInstruction { Type indexType; - public ArrayStoreOperator(int addr, int length, Type type) { - super(addr,length, type); - indexType = UnknownType.tUIndex; + public ArrayStoreOperator(Type type, int operator) { + super(type, operator); + indexType = MyType.tUIndex; } - public ArrayStoreOperator(int addr, int length, Type type, int operator) { - super(addr,length, type, operator); - indexType = UnknownType.tUIndex; + public ArrayStoreOperator(Type type) { + this(type, ASSIGN_OP); } + public boolean matches(Operator loadop) { return loadop instanceof ArrayLoadOperator; } @@ -30,6 +30,16 @@ public class ArrayStoreOperator extends StoreInstruction { return 0; } + /** + * Sets the type of the lvalue (and rvalue). + * @return true since the operand types changed + */ + public boolean setLValueType(Type type) { + this.lvalueType = type; + System.err.println("Setting Lvalue type to "+lvalueType); + return true; + } + public Type getLValueOperandType(int i) { if (i == 0) return Type.tArray(lvalueType); @@ -38,20 +48,17 @@ public class ArrayStoreOperator extends StoreInstruction { } public void setLValueOperandType(Type[] t) { - indexType = UnknownType.commonType(indexType, t[1]); - Type arraytype = - UnknownType.commonType(t[0], Type.tArray(lvalueType)); - System.err.println("lvot: "+t[0]+","+Type.tArray(lvalueType)+ - " -> "+arraytype); - if (arraytype instanceof ArrayType) - lvalueType = arraytype.getElementType(); - else { - System.err.println("no array: "+arraytype); + indexType = MyType.intersection(indexType, t[1]); + Type arrayType = + MyType.intersection(t[0], Type.tArray(lvalueType)); + try { + lvalueType = arrayType.getElementType(); + } catch (sun.tools.java.CompilerError err) { lvalueType = Type.tError; } } - public String getLValueString(CodeAnalyzer ca, String[] operands) { + public String getLValueString(String[] operands) { return operands[0]+"["+operands[1]+"]"; } } diff --git a/jode/jode/expr/AssignOperator.java b/jode/jode/expr/AssignOperator.java index da98438..a0d1ebc 100644 --- a/jode/jode/expr/AssignOperator.java +++ b/jode/jode/expr/AssignOperator.java @@ -1,14 +1,17 @@ package jode; import sun.tools.java.Type; -public class AssignOperator extends BinaryOperator { +public class AssignOperator extends Operator { StoreInstruction store; - public AssignOperator(int addr, int length, int op, - StoreInstruction store) { - super(addr,length, store.getLValueType(), op); + public AssignOperator(int op, StoreInstruction store) { + super(store.getLValueType(), op); this.store = store; } + + public int getPriority() { + return store.getPriority(); + } public int getOperandCount() { return store.getOperandCount(); @@ -40,7 +43,7 @@ public class AssignOperator extends BinaryOperator { this.type = store.getLValueType(); } - public String toString(CodeAnalyzer ca, String[] operands) { - return store.toString(ca, operands); + public String toString(String[] operands) { + return store.toString(operands); } } diff --git a/jode/jode/expr/BinaryOperator.java b/jode/jode/expr/BinaryOperator.java index ec11347..4036ef1 100644 --- a/jode/jode/expr/BinaryOperator.java +++ b/jode/jode/expr/BinaryOperator.java @@ -4,8 +4,8 @@ import sun.tools.java.Type; public class BinaryOperator extends Operator { protected Type operandType; - public BinaryOperator(int addr, int length, Type type, int op) { - super(addr,length, type, op); + public BinaryOperator(Type type, int op) { + super(type, op); operandType = type; } @@ -47,8 +47,8 @@ public class BinaryOperator extends Operator { } public void setOperandType(Type[] inputTypes) { - operandType = UnknownType.commonType - (operandType, UnknownType.commonType(inputTypes[0], + operandType = MyType.intersection + (operandType, MyType.intersection(inputTypes[0], inputTypes[1])); type = operandType; } @@ -58,7 +58,7 @@ public class BinaryOperator extends Operator { * @return true if the operand types changed */ public boolean setType(Type newType) { - operandType = UnknownType.commonType(operandType, newType); + operandType = MyType.intersection(operandType, newType); if (type != operandType) { type = operandType; return true; @@ -66,7 +66,12 @@ public class BinaryOperator extends Operator { return false; } - public String toString(CodeAnalyzer ca, String[] operands) { - return operands[0] + " "+getOperatorString()+" "+ operands[1]; + public boolean equals(Object o) { + return (o instanceof BinaryOperator) && + ((BinaryOperator)o).operator == operator; + } + + public String toString(String[] operands) { + return operands[0] + getOperatorString() + operands[1]; } } diff --git a/jode/jode/expr/CheckCastOperator.java b/jode/jode/expr/CheckCastOperator.java index 2e0e40c..c2b1304 100644 --- a/jode/jode/expr/CheckCastOperator.java +++ b/jode/jode/expr/CheckCastOperator.java @@ -2,9 +2,12 @@ package jode; import sun.tools.java.Type; public class CheckCastOperator extends SimpleOperator { - public CheckCastOperator(int addr, int length, Type type) { - super(addr,length, type, 0, 1); - operandTypes[0] = UnknownType.tSubClass(type); + String typeString; + + public CheckCastOperator(Type type, String typeString) { + super(type, 0, 1); + this.typeString = typeString; + operandTypes[0] = MyType.tSuperType(type); } public int getPriority() { @@ -15,7 +18,7 @@ public class CheckCastOperator extends SimpleOperator { return getPriority(); } - public String toString(CodeAnalyzer ca, String[] operands) { - return "("+ca.getTypeString(type) + ")" + operands[0]; + public String toString(String[] operands) { + return "(" + typeString + ")" + operands[0]; } } diff --git a/jode/jode/expr/CompareBinaryOperator.java b/jode/jode/expr/CompareBinaryOperator.java index 891a403..3631697 100644 --- a/jode/jode/expr/CompareBinaryOperator.java +++ b/jode/jode/expr/CompareBinaryOperator.java @@ -2,8 +2,8 @@ package jode; import sun.tools.java.Type; public class CompareBinaryOperator extends SimpleOperator { - public CompareBinaryOperator(int addr, int length, Type type, int op) { - super(addr,length, Type.tBoolean, op, 2); + public CompareBinaryOperator(Type type, int op) { + super(Type.tBoolean, op, 2); operandTypes[0] = operandTypes[1] = type; } @@ -28,11 +28,16 @@ public class CompareBinaryOperator extends SimpleOperator { public void setOperandType(Type[] inputTypes) { super.setOperandType(inputTypes); Type operandType = - UnknownType.commonType(operandTypes[0],operandTypes[1]); + MyType.intersection(operandTypes[0],operandTypes[1]); operandTypes[0] = operandTypes[1] = operandType; } - public String toString(CodeAnalyzer ca, String[] operands) { - return operands[0] + " "+opString[operator]+" "+operands[1]; + public boolean equals(Object o) { + return (o instanceof CompareBinaryOperator) && + ((CompareBinaryOperator)o).operator == operator; + } + + public String toString(String[] operands) { + return operands[0] + getOperatorString() + operands[1]; } } diff --git a/jode/jode/expr/CompareToIntOperator.java b/jode/jode/expr/CompareToIntOperator.java index e927008..bcad98c 100644 --- a/jode/jode/expr/CompareToIntOperator.java +++ b/jode/jode/expr/CompareToIntOperator.java @@ -1,27 +1,32 @@ package jode; import sun.tools.java.Type; -public class CompareToIntOperator extends BinaryOperator { - public CompareToIntOperator(int addr, int length, Type type, int op) { - super(addr,length, Type.tInt, op); - operandType = type; +public class CompareToIntOperator extends SimpleOperator { + public CompareToIntOperator(Type type, int lessGreater) { + super(Type.tInt, 0, 2); + operandTypes[0] = operandTypes[1] = type; } public int getPriority() { - switch (getOperator()) { - case 25: - case 26: - return 500; - case 27: - case 28: - case 29: - case 30: - return 550; - } - throw new RuntimeException("Illegal operator"); + return 499; } - public String toString(CodeAnalyzer ca, String[] operands) { - return operands[0] + " "+opString[operator]+" "+operands[1]; + public int getOperandPriority(int i) { + return 550; + } + + public void setOperandType(Type[] inputTypes) { + super.setOperandType(inputTypes); + Type operandType = + MyType.intersection(operandTypes[0],operandTypes[1]); + operandTypes[0] = operandTypes[1] = operandType; + } + + public boolean equals(Object o) { + return (o instanceof CompareToIntOperator); + } + + public String toString(String[] operands) { + return operands[0] + " <=> " + operands[1]; } } diff --git a/jode/jode/expr/CompareUnaryOperator.java b/jode/jode/expr/CompareUnaryOperator.java index 881be5d..b865234 100644 --- a/jode/jode/expr/CompareUnaryOperator.java +++ b/jode/jode/expr/CompareUnaryOperator.java @@ -2,8 +2,8 @@ package jode; import sun.tools.java.Type; public class CompareUnaryOperator extends SimpleOperator { - public CompareUnaryOperator(int addr, int length, Type type, int op) { - super(addr,length, Type.tBoolean, op, 1); + public CompareUnaryOperator(Type type, int op) { + super(Type.tBoolean, op, 1); operandTypes[0] = type; } @@ -25,15 +25,14 @@ public class CompareUnaryOperator extends SimpleOperator { return getPriority(); } - public String toString(CodeAnalyzer ca, String[] operands) { - if (operandTypes[0] == Type.tBoolean) { - if (operator == 26) /* xx == false */ - return "! ("+operands[0]+")"; /*XXX Make operators */ - else if (operator == 27) /* xx != false */ - return operands[0]; - } - return operands[0] + " "+opString[operator]+" "+ - (UnknownType.isOfType(operandTypes[0], - UnknownType.tObject)?"null":"0"); + public boolean equals(Object o) { + return (o instanceof CompareUnaryOperator) && + ((CompareUnaryOperator)o).operator == operator; + } + + public String toString(String[] operands) { + return operands[0] + getOperatorString() + + (MyType.isOfType(operandTypes[0], + MyType.tObject)?"null":"0"); } } diff --git a/jode/jode/expr/ConstOperator.java b/jode/jode/expr/ConstOperator.java index aaf639d..d6a7eb8 100644 --- a/jode/jode/expr/ConstOperator.java +++ b/jode/jode/expr/ConstOperator.java @@ -4,8 +4,8 @@ import sun.tools.java.Type; public class ConstOperator extends NoArgOperator { String value; - public ConstOperator(int addr, int length, Type type, String value) { - super(addr, length, type); + public ConstOperator(Type type, String value) { + super(type); this.value = value; } @@ -40,7 +40,12 @@ public class ConstOperator extends NoArgOperator { return result.append("\"").toString(); } - public String toString(CodeAnalyzer ca, String[] operands) { + public boolean equals(Object o) { + return (o instanceof ConstOperator) && + ((ConstOperator)o).value.equals(value); + } + + public String toString(String[] operands) { if (type == Type.tString) return quoted(value); if (type == Type.tBoolean) { @@ -52,4 +57,3 @@ public class ConstOperator extends NoArgOperator { return value; } } - diff --git a/jode/jode/expr/ConstantArrayOperator.java b/jode/jode/expr/ConstantArrayOperator.java new file mode 100644 index 0000000..c5acf42 --- /dev/null +++ b/jode/jode/expr/ConstantArrayOperator.java @@ -0,0 +1,30 @@ +package jode; +import sun.tools.java.Type; + +public class ConstantArrayOperator extends SimpleOperator { + + public ConstantArrayOperator(Type type, int size) { + super(type, 0, size); + for (int i=0; i< size; i++) + operandTypes[i] = type.getElementType(); + } + + public int getPriority() { + return 200; + } + + public int getOperandPriority(int i) { + return 0; + } + + public String toString(String[] operands) { + StringBuffer result + = new StringBuffer("{"); + for (int i=0; i< getOperandCount(); i++) { + if (i>0) + result.append(", "); + result.append(operands[i]); + } + return result.append("}").toString(); + } +} diff --git a/jode/jode/expr/ConstructorOperator.java b/jode/jode/expr/ConstructorOperator.java index c6a8ad1..2584adc 100644 --- a/jode/jode/expr/ConstructorOperator.java +++ b/jode/jode/expr/ConstructorOperator.java @@ -4,9 +4,8 @@ import sun.tools.java.*; public class ConstructorOperator extends Operator { FieldDefinition field; - public ConstructorOperator(int addr, int length, Type type, - FieldDefinition field) { - super(addr,length, type, 0); + public ConstructorOperator(Type type, FieldDefinition field) { + super(type, 0); this.field = field; } @@ -33,7 +32,7 @@ public class ConstructorOperator extends Operator { public void setOperandType(Type types[]) { } - public String toString(CodeAnalyzer ca, String[] operands) { + public String toString(String[] operands) { StringBuffer result = new StringBuffer(operands[0]).append("("); for (int i=0; i < field.getType().getArgumentTypes().length; i++) { if (i>0) diff --git a/jode/jode/expr/ConvertOperator.java b/jode/jode/expr/ConvertOperator.java index 4873d56..e4d9346 100644 --- a/jode/jode/expr/ConvertOperator.java +++ b/jode/jode/expr/ConvertOperator.java @@ -4,8 +4,8 @@ import sun.tools.java.Type; public class ConvertOperator extends Operator { Type from; - public ConvertOperator(int addr, int length, Type from, Type to) { - super(addr,length, to, 0); + public ConvertOperator(Type from, Type to) { + super(to, 0); this.from = from; } @@ -26,11 +26,11 @@ public class ConvertOperator extends Operator { } public void setOperandType(Type[] inputTypes) { - from = UnknownType.commonType(from, inputTypes[0]); + from = MyType.intersection(from, inputTypes[0]); } - public String toString(CodeAnalyzer ca, String[] operands) + public String toString(String[] operands) { - return "("+ca.getTypeString(type)+") "+operands[0]; + return "("+type.toString()+") "+operands[0]; } } diff --git a/jode/jode/expr/DupOperator.java b/jode/jode/expr/DupOperator.java index f9e5db0..1b61134 100644 --- a/jode/jode/expr/DupOperator.java +++ b/jode/jode/expr/DupOperator.java @@ -1,10 +1,11 @@ package jode; +import sun.tools.java.Type; public class DupOperator extends Instruction { int count, depth; - public DupOperator(int a, int l, int depth, int count) { - super(a,l); + public DupOperator(int depth, int count) { + super(MyType.tUnknown); this.count = count; this.depth = depth; } @@ -17,9 +18,8 @@ public class DupOperator extends Instruction { return depth; } - public void dumpSource(TabbedPrintWriter tpw, CodeAnalyzer ca) - throws java.io.IOException + public String toString() { - tpw.println("dup"+count+"_x"+depth+";"); + return "dup"+count+"_x"+depth; } } diff --git a/jode/jode/expr/EmptyStringOperator.java b/jode/jode/expr/EmptyStringOperator.java new file mode 100644 index 0000000..e5a875e --- /dev/null +++ b/jode/jode/expr/EmptyStringOperator.java @@ -0,0 +1,22 @@ +package jode; +import sun.tools.java.Type; + +public class EmptyStringOperator extends NoArgOperator { + + public EmptyStringOperator() { + super(Type.tString, 0); + } + + public int getPriority() { + return 1000; + } + + public boolean equals(Object o) { + return (o instanceof EmptyStringOperator); + } + + public String toString(String[] operands) { + return "\"\""; + } +} + diff --git a/jode/jode/expr/Expression.java b/jode/jode/expr/Expression.java index a12d6f2..5e69dc9 100644 --- a/jode/jode/expr/Expression.java +++ b/jode/jode/expr/Expression.java @@ -1,19 +1,21 @@ package jode; import sun.tools.java.Type; +import sun.tools.java.Constants; +import sun.tools.java.FieldDefinition; public class Expression extends Instruction { Operator operator; Expression[] subExpressions; - protected Expression(int addr, int length) { - super(addr, length); - } - - public Expression(int addr, int length, Operator op, Expression[] sub) { - super(addr, length); + public Expression(Operator op, Expression[] sub) { + super(MyType.tUnknown); operator = op; subExpressions = sub; - if (op.getOperandCount() > 0) { + if (subExpressions.length != op.getOperandCount()) + throw new AssertError ("Operand count mismatch: "+ + subExpressions.length + " != " + + op.getOperandCount()); + if (subExpressions.length > 0) { Type types[] = new Type[subExpressions.length]; for (int i=0; i < types.length; i++) { types[i] = subExpressions[i].getType(); @@ -21,6 +23,7 @@ public class Expression extends Instruction { operator.setOperandType(types); updateSubTypes(); } + this.type = operator.getType(); } public Expression negate() { @@ -40,10 +43,34 @@ public class Expression extends Instruction { } Operator negop = - new UnaryOperator(getAddr(), getLength(), - Type.tBoolean, Operator.LOG_NOT_OP); + new UnaryOperator(Type.tBoolean, Operator.LOG_NOT_OP); Expression[] e = { this }; - return new Expression(getAddr(), getLength(), negop, e); + return new Expression(negop, e); + } + + public Expression tryToCombine(Expression e) { + if (e.operator instanceof StoreInstruction) { + StoreInstruction store = (StoreInstruction) e.operator; + Expression search = this; + while (search.subExpressions.length > 0) { + if (store.matches(search.operator)) { + int i; + for (i=0; i < e.subExpressions.length-1; i++) { + if (!e.subExpressions[i].equals + (search.subExpressions[i])) + break; + } + if (i == e.subExpressions.length-1) { + search.operator = + new AssignOperator(store.getOperator(), store); + search.subExpressions = e.subExpressions; + return this; + } + } + search = search.subExpressions[0]; + } + } + return null; } public Operator getOperator() { @@ -54,10 +81,6 @@ public class Expression extends Instruction { return subExpressions; } - public Type getType() { - return operator.getType(); - } - public void updateSubTypes() { for (int i=0; i < subExpressions.length; i++) { subExpressions[i].setType(operator.getOperandType(i)); @@ -67,23 +90,20 @@ public class Expression extends Instruction { public void setType(Type type) { if (operator.setType(type)) updateSubTypes(); - } - - public int[] getSuccessors() { - return operator.getSuccessors(); + this.type = operator.getType(); } public boolean isVoid() { return operator.getType() == Type.tVoid; } - String toString(CodeAnalyzer ca, int minPriority) { + String toString(int minPriority) { String[] expr = new String[subExpressions.length]; for (int i=0; i 6) { - writer.print("< "+ - ca.getTypeString(operator.getType())+" "+ - operator.getClass().getName()+"("); - for (int i=0; i< subExpressions.length; i++) { - if (i>0) - writer.print(", "); - writer.print("("+ca.getTypeString(operator.getOperandType(i))+ - ") "+ca.getTypeString(subExpressions[i].getType())); + public String toString() { + return toString(0); + } + + Expression simplifyStringBuffer() { + FieldDefinition field; + if (operator instanceof InvokeOperator && + (field = ((InvokeOperator)operator).getField()) + .getClassDefinition().getName() == + Constants.idJavaLangStringBuffer && + field.getName() == Constants.idAppend && + field.getType().getArgumentTypes().length == 1) { + + Expression e = subExpressions[0].simplifyStringBuffer(); + if (e == null) + return null; + + if (e.operator instanceof EmptyStringOperator && + subExpressions[1].getType() == Type.tString) + return subExpressions[1]; + + Expression[] exprs = { e, subExpressions[1] }; + return new Expression(new StringAddOperator(), exprs); + } + if (operator instanceof ConstructorOperator && + operator.getType() == MyType.tStringBuffer) { + if (operator.getOperandCount() == 1) + return new Expression(new EmptyStringOperator(), + new Expression[0]); + else if (operator.getOperandCount() == 2 && + subExpressions[1].getType() == MyType.tString) + return subExpressions[1]; + } + return null; + } + + public Instruction simplify() { + if (operator instanceof IfThenElseOperator && + operator.getType() == Type.tBoolean) { + if (subExpressions[1].operator instanceof ConstOperator && + subExpressions[2].operator instanceof ConstOperator) { + ConstOperator c1 = (ConstOperator) subExpressions[1].operator; + ConstOperator c2 = (ConstOperator) subExpressions[2].operator; + if (c1.getValue().equals("true") && + c2.getValue().equals("false")) + return subExpressions[0].simplify(); + if (c2.getValue().equals("true") && + c1.getValue().equals("false")) + return subExpressions[0].negate().simplify(); } - writer.println(") >"); } - if (!isVoid()) - writer.print("push "); - writer.println(toString(ca, 0)+";"); + if (operator instanceof CompareUnaryOperator && + subExpressions[0].operator instanceof CompareToIntOperator) { + CompareBinaryOperator newOp = new CompareBinaryOperator + (subExpressions[0].operator.getOperandType(0), + operator.getOperator()); + return new Expression(newOp, subExpressions[0].subExpressions). + simplify(); + } + if (operator instanceof CompareUnaryOperator && + operator.getOperandType(0) != Type.tBoolean) { + if (subExpressions[0].operator instanceof ConstOperator) { + ConstOperator c = (ConstOperator) subExpressions[0].operator; + if (c.getValue().equals("0") || c.getValue().equals("1")) { + Type[] newType = {Type.tBoolean}; + operator.setOperandType(newType); + } + } + } + if (operator instanceof CompareUnaryOperator && + operator.getOperandType(0) == Type.tBoolean) { + if (operator.getOperator() == 26) /* xx == false */ + return subExpressions[0].negate().simplify(); + if (operator.getOperator() == 27) /* xx != false */ + return subExpressions[0].simplify(); + } + + if (operator instanceof InvokeOperator && + ((InvokeOperator)operator).getField(). + getName() == Constants.idToString && + ((InvokeOperator)operator).getField(). + getClassDefinition().getType() == MyType.tStringBuffer && + operator.getOperandCount() == 1) { + Expression e = subExpressions[0].simplifyStringBuffer(); + if (e != null) + return e.simplify(); + } + + for (int i=0; i< subExpressions.length; i++) + subExpressions[i] = (Expression) subExpressions[i].simplify(); + + return this; } } diff --git a/jode/jode/expr/GetFieldOperator.java b/jode/jode/expr/GetFieldOperator.java index 22521fb..f157257 100644 --- a/jode/jode/expr/GetFieldOperator.java +++ b/jode/jode/expr/GetFieldOperator.java @@ -4,10 +4,12 @@ import sun.tools.java.*; public class GetFieldOperator extends Operator { boolean staticFlag; FieldDefinition field; + CodeAnalyzer codeAnalyzer; - public GetFieldOperator(int addr, int length, boolean staticFlag, - FieldDefinition field) { - super(addr, length, field.getType(), 0); + public GetFieldOperator(CodeAnalyzer codeAnalyzer, boolean staticFlag, + FieldDefinition field) { + super(field.getType(), 0); + this.codeAnalyzer = codeAnalyzer; this.staticFlag = staticFlag; this.field = field; } @@ -33,19 +35,19 @@ public class GetFieldOperator extends Operator { /* shouldn't be called */ throw new RuntimeException("Field is static"); } - return field.getClassDeclaration().getType(); + return MyType.tSubType(field.getClassDeclaration().getType()); } public void setOperandType(Type types[]) { } - public String toString(CodeAnalyzer ca, String[] operands) { + public String toString(String[] operands) { String object; if (staticFlag) { - if (field.getClassDefinition() == ca.getClassDefinition()) + if (field.getClassDefinition() == codeAnalyzer.getClassDefinition()) return field.getName().toString(); object = - ca.getTypeString(field.getClassDeclaration().getType()); + codeAnalyzer.getTypeString(field.getClassDeclaration().getType()); } else { if (operands[0].equals("this")) return field.getName().toString(); @@ -53,4 +55,9 @@ public class GetFieldOperator extends Operator { } return object + "." + field.getName(); } + + public boolean equals(Object o) { + return (o instanceof GetFieldOperator) && + ((GetFieldOperator)o).field == field; + } } diff --git a/jode/jode/expr/IIncOperator.java b/jode/jode/expr/IIncOperator.java new file mode 100644 index 0000000..dc8e567 --- /dev/null +++ b/jode/jode/expr/IIncOperator.java @@ -0,0 +1,55 @@ +package jode; +import sun.tools.java.Type; + +public class IIncOperator extends NoArgOperator +implements LocalVarOperator { + int slot; + String value; + LocalInfo local; + + public IIncOperator(int slot, String value, int operator) { + super(MyType.tVoid, operator); + this.slot = slot; + this.value = value; + } + + public String getValue() { + return value; + } + + public boolean isRead() { + return true; + } + + public boolean isWrite() { + return true; + } + + public void setLocalInfo(LocalInfo local) { + local.setType(MyType.tUIndex); + this.local = local; + } + + public LocalInfo getLocalInfo() { + return local; + } + + public int getSlot() { + return slot; + } + + public int getPriority() { + return 100; + } + + public boolean matches(Operator loadop) { + return loadop instanceof LocalLoadOperator && + ((LocalLoadOperator)loadop).getLocalInfo().getLocalInfo() + == local.getLocalInfo(); + } + + public String toString(String[] operands) { + return local.getName().toString() + + getOperatorString() + value; + } +} diff --git a/jode/jode/expr/IfThenElseOperator.java b/jode/jode/expr/IfThenElseOperator.java index 145a2d0..40b2184 100644 --- a/jode/jode/expr/IfThenElseOperator.java +++ b/jode/jode/expr/IfThenElseOperator.java @@ -2,8 +2,8 @@ package jode; import sun.tools.java.Type; public class IfThenElseOperator extends SimpleOperator { - public IfThenElseOperator(int addr, int length, Type type) { - super(addr,length, type, 0, 3); + public IfThenElseOperator(Type type) { + super(type, 0, 3); operandTypes[0] = Type.tBoolean; } @@ -31,7 +31,7 @@ public class IfThenElseOperator extends SimpleOperator { public void setOperandType(Type[] inputTypes) { super.setOperandType(inputTypes); Type operandType = - UnknownType.commonType(operandTypes[1],operandTypes[2]); + MyType.intersection(operandTypes[1],operandTypes[2]); type = operandTypes[1] = operandTypes[2] = operandType; } @@ -41,7 +41,7 @@ public class IfThenElseOperator extends SimpleOperator { */ public boolean setType(Type newType) { Type operandType = - UnknownType.commonType(operandTypes[1], newType); + MyType.intersection(operandTypes[1], newType); if (type != operandType) { type = operandTypes[1] = operandTypes[2] = operandType; return true; @@ -49,7 +49,11 @@ public class IfThenElseOperator extends SimpleOperator { return false; } - public String toString(CodeAnalyzer ca, String[] operands) { + public boolean equals(Object o) { + return (o instanceof IfThenElseOperator); + } + + public String toString(String[] operands) { return operands[0] + " ? "+operands[1]+" : "+ operands[2]; } } diff --git a/jode/jode/expr/InstanceOfOperator.java b/jode/jode/expr/InstanceOfOperator.java index 4de74fc..c4fc988 100644 --- a/jode/jode/expr/InstanceOfOperator.java +++ b/jode/jode/expr/InstanceOfOperator.java @@ -2,12 +2,12 @@ package jode; import sun.tools.java.Type; public class InstanceOfOperator extends SimpleOperator { - Type classType; + String typeString; - public InstanceOfOperator(int addr, int length, Type type) { - super(addr, length, Type.tBoolean, 0, 1); - this.operandTypes[0] = UnknownType.tSubClass(type); - this.classType = type; + public InstanceOfOperator(Type type, String typeString) { + super(Type.tBoolean, 0, 1); + this.operandTypes[0] = MyType.tSuperType(type); + this.typeString = typeString; } public int getOperandCount() { return 1; @@ -21,7 +21,7 @@ public class InstanceOfOperator extends SimpleOperator { return getPriority(); } - public String toString(CodeAnalyzer ca, String[] operands) { - return operands[0] + " instanceof "+ca.getTypeString(classType); + public String toString(String[] operands) { + return operands[0] + " instanceof "+typeString; } } diff --git a/jode/jode/expr/Instruction.java b/jode/jode/expr/Instruction.java index 4a34a7a..ee9afe5 100644 --- a/jode/jode/expr/Instruction.java +++ b/jode/jode/expr/Instruction.java @@ -1,34 +1,20 @@ package jode; +import sun.tools.java.Type; public abstract class Instruction { - int addr,length; + protected Type type; - Instruction(int a, int l) { - addr = a; - length = l; + Instruction(Type type) { + this.type = type; } - public int getAddr() { - return addr; + public Type getType() { + return type; } - public void setAddr(int addr) { - this.addr = addr; + public Instruction simplify() { + return this; } - public int getLength() { - return length; - } - - public void setLength(int length) { - this.length = length; - } - - public int[] getSuccessors() { - int[] result = { addr + length }; - return result; - } - - public abstract void dumpSource(TabbedPrintWriter tpw, CodeAnalyzer ca) - throws java.io.IOException; + public abstract String toString(); } diff --git a/jode/jode/expr/InstructionHeader.java b/jode/jode/expr/InstructionHeader.java new file mode 100644 index 0000000..076cab3 --- /dev/null +++ b/jode/jode/expr/InstructionHeader.java @@ -0,0 +1,282 @@ +package jode; +import java.util.Vector; +import sun.tools.java.Type; + +/** + * This class maintains the connections between the + * InstructionHeaders. They are connected in a doubly linked list + * (but a instruction may have multiple successors and predecessors). + * @see JumpInstructionHeader + * @see SwitchInstructionHeader + * @author Jochen Hoenicke + */ +public class InstructionHeader { + int addr, length; + Instruction instr; + InstructionHeader nextInstruction; + + Type switchType; + int[] cases; + int[] succs; + InstructionHeader[] successors; + + Vector predecessors = new Vector(); + + /** + * Create a new InstructionHeader. + * @param addr The address of this Instruction. + * @param length The length of this Instruction. + * @param instr The underlying Instruction. + */ + public InstructionHeader(int addr, int length, Instruction instr) { + int[] succs = { addr + length }; + this.addr = addr; + this.length = length; + this.instr = instr; + switchType = MyType.tVoid; + this.cases = new int[0]; + this.succs = succs; + } + + /** + * Create a new InstructionHeader. + * @param addr The address of this Instruction. + * @param length The length of this Instruction. + * @param instr The underlying Instruction. + * @param type The type of the switch + * @param cases The possible cases + * @param succs The destinations (one longer for default) + */ + public InstructionHeader(int addr, int length, Instruction instr, + Type type, int[] cases, int[] succs) { + this.addr = addr; + this.length = length; + this.instr = instr; + switchType = type; + this.cases = cases; + this.succs = succs; + } + + /** + * Create an InstructionHeader for a return + * @param addr The address of this instruction. + * @param length The length of this instruction. + * @param instr The underlying Instruction. + */ + public static InstructionHeader ret(int addr, int length, + Instruction instr) { + return new InstructionHeader (addr, length, instr, + MyType.tVoid, new int[0], new int[0]); + } + + /** + * Create an InstructionHeader for an unconditional jump. + * @param addr The address of this instruction. + * @param length The length of this instruction. + * @param instr The underlying Instruction. + * @param dest The destination address of the jump. + */ + public static InstructionHeader jump(int addr, int length, int dest, + Instruction instr) { + int [] succs = { dest }; + return new InstructionHeader (addr, length, instr, + MyType.tVoid, new int[0], succs); + } + + /** + * Create an InstructionHeader for a conditional jump. + * @param addr The address of this instruction. + * @param length The length of this instruction. + * @param instr The underlying Instruction. + * @param dest The destination address of the jump. + */ + public static InstructionHeader conditional(int addr, int length, int dest, + Instruction instr) { + int[] cases = { 0 }; + int[] succs = { addr+length , dest }; + return new InstructionHeader (addr, length, instr, + MyType.tBoolean, cases, succs); + } + + public String toString() { + return instr.toString(); + } + + /** + * Get the address of this instruction. + * @return The address. + */ + public int getAddress() { + return addr; + } + + /** + * Get the next address in code order. + * @return The next instruction + */ + public int getNextAddr() { + return addr+length; + } + + /** + * Get the underlying instruction. + * @return The underlying instruction. + */ + public Instruction getInstruction() { + return instr; + } + + /** + * Get the next instruction in code order. This function mustn't + * be called before resolveSuccessors is executed for this + * InstructionHeaders. + * @return The next instruction + */ + public InstructionHeader getNextInstruction() { + return nextInstruction; + } + + /** + * Get the successors of this instructions. This function mustn't + * be called before resolveSuccessors is executed for this + * InstructionHeaders. + * @return Array of successors. + */ + public InstructionHeader[] getSuccessors() { + return successors; + } + + public boolean hasDirectPredecessor() { + return predecessors.size() == 1 && + ((InstructionHeader)predecessors.elementAt(0)). + getNextInstruction() == this; + } + + /** + * Get the unique predecessor or null if there isn't a + * unique predecessor. + */ + public InstructionHeader getUniquePredecessor() { + if (predecessors.size() != 1) + return null; + InstructionHeader pre = (InstructionHeader)predecessors.elementAt(0); + return (pre.getNextInstruction() == this && + pre.getSuccessors().length != 1) ? null : pre; + } + + /** + * Get the predecessors of this instruction. This function mustn't + * be called before resolveSuccessors is executed for all + * InstructionHeaders. + * @return Vector of predecessors. + */ + public Vector getPredecessors() { + return predecessors; + } + + /** + * Resolve the successors and predecessors and build a doubly + * linked list. + * @param instHeaders an array of the InstructionHeaders, indexed + * by addresses. + */ + public void resolveSuccessors(InstructionHeader[] instHeaders) { + if (addr+length < instHeaders.length) + nextInstruction = instHeaders[addr+length]; + else + nextInstruction = null; + successors = new InstructionHeader[succs.length]; + for (int i=0; i< succs.length; i++) { + successors[i] = instHeaders[succs[i]]; + successors[i].predecessors.addElement(this); + } + } + + public void dumpSource(TabbedPrintWriter writer) + throws java.io.IOException + { + if (writer.verbosity > 5) { + writer.println("<"+addr + " - "+(addr+length-1)+">"); + writer.tab(); + } + if (!hasDirectPredecessor() && addr != 0) + writer.print("addr_"+addr+": "); + + if (switchType == MyType.tBoolean) { + + writer.println("if ("+instr.toString()+") goto addr_"+succs[1]); + if (succs[0] != addr + length) + writer.println("goto addr_"+succs[0]); + + } else if (switchType == MyType.tVoid) { + + if (instr.getType() != MyType.tVoid) + writer.print("push "); + writer.println(instr.toString()+";"); + if (succs.length > 0 && succs[0] != addr + length) + writer.println("goto addr_"+succs[0]); + + } else { + writer.println("switch ("+instr.toString()+") {"); + writer.tab(); + writer.untab(); + } + if (writer.verbosity > 5) + writer.untab(); + } + + /** + * This method replaces multiple InstructionHeaders by a single one. + * The next count Instructions must be unique. + * @param count the number of InstructionHeaders that should be replaced. + * @param instr the new instruction; this should be equivalent to the + * old count

  • boolean for a conditional Jsr.
  • + *
  • void for an unconditional Jsr.
  • + */ + public JsrInstructionHeader(int addr, int length, int dest, + Instruction instr) { + super(addr,length, instr); + this.dest = dest; + } + + /** + * Get the successors of this instructions. This function mustn't + * be called before resolveSuccessors is executed for this + * InstructionHeaders. + * @return Array of successors. + */ + public InstructionHeader[] getSuccessors() { + InstructionHeader[] result = { destination }; + return result; + } + + /** + * Resolve the successors and predecessors and build a doubly + * linked list. + * @param instHeaders an array of the InstructionHeaders, indexed + * by addresses. + */ + public void resolveSuccessors(InstructionHeader[] instHeaders) { + nextInstruction = instHeaders[addr+length]; + destination = instHeaders[dest]; + destination.predecessors.addElement(this); + /* Ret.successors.addElement(nextInstruction); XXX */ + } + + public String toString() { + return "Jsr " + dest; + } +} diff --git a/jode/jode/expr/JsrOperator.java b/jode/jode/expr/JsrOperator.java index 3d2a103..af8a776 100644 --- a/jode/jode/expr/JsrOperator.java +++ b/jode/jode/expr/JsrOperator.java @@ -3,14 +3,12 @@ package jode; public class JsrOperator extends Instruction { int destination; - public JsrOperator(int addr, int length, int dest) { - super(addr,length); - this.destination = dest; + public JsrOperator() { + super(MyType.tVoid); } - public void dumpSource(TabbedPrintWriter writer, CodeAnalyzer ca) - throws java.io.IOException + public String toString() { - writer.println("jsr addr_"+destination+";"); + return "JSR"; } } diff --git a/jode/jode/expr/LocalLoadOperator.java b/jode/jode/expr/LocalLoadOperator.java new file mode 100644 index 0000000..505417e --- /dev/null +++ b/jode/jode/expr/LocalLoadOperator.java @@ -0,0 +1,54 @@ +package jode; +import sun.tools.java.Type; + +public class LocalLoadOperator extends ConstOperator +implements LocalVarOperator { + int slot; + LocalInfo local; + + public LocalLoadOperator(Type type, int slot) { + super(type, ""); + this.slot = slot; + } + + public boolean isRead() { + return true; + } + + public boolean isWrite() { + return false; + } + + public void setLocalInfo(LocalInfo local) { + local.setType(type); + this.local = local; + } + + public LocalInfo getLocalInfo() { + return local; + } + + public Type getType() { + System.err.println("LocalLoad.getType of "+local.getName()+": "+local.getType()); + return local.getType(); + } + + public boolean setType(Type type) { + System.err.println("LocalLoad.setType of "+local.getName()+": "+local.getType()); + return super.setType(local.setType(type)); + } + + public int getSlot() { + return slot; + } + + public String toString(String[] operands) { + return local.getName().toString(); + } + + public boolean equals(Object o) { + return (o instanceof LocalLoadOperator && + ((LocalLoadOperator) o).slot == slot); + } +} + diff --git a/jode/jode/expr/LocalPostFixOperator.java b/jode/jode/expr/LocalPostFixOperator.java new file mode 100644 index 0000000..aa936fa --- /dev/null +++ b/jode/jode/expr/LocalPostFixOperator.java @@ -0,0 +1,19 @@ +package jode; +import sun.tools.java.Type; + +public class LocalPostFixOperator extends NoArgOperator { + IIncOperator iinc; + + public LocalPostFixOperator(Type type, int op, IIncOperator iinc) { + super(type, op); + this.iinc = iinc; + } + + public int getPriority() { + return 800; + } + + public String toString(String[] operands) { + return iinc.getLocalInfo().getName() + getOperatorString(); + } +} diff --git a/jode/jode/expr/LocalStoreOperator.java b/jode/jode/expr/LocalStoreOperator.java new file mode 100644 index 0000000..1677ff9 --- /dev/null +++ b/jode/jode/expr/LocalStoreOperator.java @@ -0,0 +1,75 @@ +package jode; +import sun.tools.java.Type; + +public class LocalStoreOperator extends StoreInstruction +implements LocalVarOperator { + int slot; + LocalInfo local; + + public LocalStoreOperator(Type lvalueType, int slot, int operator) { + super(lvalueType, operator); + this.slot = slot; + } + + public boolean isRead() { + return operator != ASSIGN_OP; + } + + public boolean isWrite() { + return true; + } + + public void setLocalInfo(LocalInfo local) { + local.setType(lvalueType); + this.local = local; + } + + public LocalInfo getLocalInfo() { + return local; + } + + public Type getLValueType() { + System.err.println("LocalStore.getType of "+local.getName()+": "+local.getType()); + return local.getType(); + } + + public boolean setLValueType(Type type) { + System.err.println("LocalStore.setType of "+local.getName()+": "+local.getType()); + return super.setLValueType + (local.setType(MyType.tSuperType(type))); + } + + public int getSlot() { + return slot; + } + + public boolean matches(Operator loadop) { + return loadop instanceof LocalLoadOperator && + ((LocalLoadOperator)loadop).getLocalInfo().getLocalInfo() + == local.getLocalInfo(); + } + + public int getLValueOperandCount() { + return 0; + } + + public int getLValueOperandPriority(int i) { + /* shouldn't be called */ + throw new RuntimeException("LocalStoreOperator has no operands"); + } + + public Type getLValueOperandType(int i) { + /* shouldn't be called */ + throw new RuntimeException("LocalStoreOperator has no operands"); + } + + public void setLValueOperandType(Type []t) { + /* shouldn't be called */ + throw new RuntimeException("LocalStoreOperator has no operands"); + } + + public String getLValueString(String[] operands) { + return local.getName().toString(); + } +} + diff --git a/jode/jode/expr/LocalVarOperator.java b/jode/jode/expr/LocalVarOperator.java new file mode 100644 index 0000000..ccbe0e7 --- /dev/null +++ b/jode/jode/expr/LocalVarOperator.java @@ -0,0 +1,11 @@ +package jode; + +public interface LocalVarOperator { + public boolean isRead(); + public boolean isWrite(); + public int getSlot(); + public LocalInfo getLocalInfo(); + public void setLocalInfo(LocalInfo li); +} + + diff --git a/jode/jode/expr/MethodInstructionHeader.java b/jode/jode/expr/MethodInstructionHeader.java new file mode 100644 index 0000000..bf6634d --- /dev/null +++ b/jode/jode/expr/MethodInstructionHeader.java @@ -0,0 +1,35 @@ +package jode; +import java.util.Vector; + +/** + * This class is the end point of the InstructionHeader list. + * @author Jochen Hoenicke + */ +public class MethodInstructionHeader extends InstructionHeader { + /** + * Create a new InstructionHeader. + * @param addr The address of this Instruction. + * @param length The length of this Instruction. + * @param instr The underlying Instruction. + */ + public MethodInstructionHeader(InstructionHeader[] instr) { + super(-1,1,null); + nextInstruction = instr[0]; + nextInstruction.predecessors.addElement(this); + for (int addr = 0; addr < instr.length; ) { + instr[addr].resolveSuccessors(instr); + if (instr[addr].succs.length == 0) + predecessors.addElement(instr[addr]); + addr = instr[addr].getNextAddr(); + } + } + + /** + * Resolve the successors and predecessors and build a doubly + * linked list. + * @param instHeaders an array of the InstructionHeaders, indexed + * by addresses. + */ + public void resolveSuccessors(InstructionHeader[] instHeaders) { + } +} diff --git a/jode/jode/expr/MonitorEnterOperator.java b/jode/jode/expr/MonitorEnterOperator.java index 74d1d91..1141876 100644 --- a/jode/jode/expr/MonitorEnterOperator.java +++ b/jode/jode/expr/MonitorEnterOperator.java @@ -2,8 +2,8 @@ package jode; import sun.tools.java.Type; public class MonitorEnterOperator extends SimpleOperator { - public MonitorEnterOperator(int a, int l) { - super(a,l, Type.tVoid, 0, 1); + public MonitorEnterOperator() { + super(Type.tVoid, 0, 1); operandTypes[0] = Type.tObject; } @@ -15,7 +15,7 @@ public class MonitorEnterOperator extends SimpleOperator { return 0; } - public String toString(CodeAnalyzer ca, String[] operands) { + public String toString(String[] operands) { return "monitorenter "+operands[0]; } } diff --git a/jode/jode/expr/MonitorExitOperator.java b/jode/jode/expr/MonitorExitOperator.java index 42c6cc2..05b3ff8 100644 --- a/jode/jode/expr/MonitorExitOperator.java +++ b/jode/jode/expr/MonitorExitOperator.java @@ -2,8 +2,8 @@ package jode; import sun.tools.java.Type; public class MonitorExitOperator extends SimpleOperator { - public MonitorExitOperator(int a, int l) { - super(a,l,Type.tVoid, 0, 1); + public MonitorExitOperator() { + super(Type.tVoid, 0, 1); operandTypes[0] = Type.tObject; } @@ -16,10 +16,10 @@ public class MonitorExitOperator extends SimpleOperator { } public Type getOperandType(int i) { - return UnknownType.tObject; + return MyType.tObject; } - public String toString(CodeAnalyzer ca, String[] operands) { + public String toString(String[] operands) { return "monitorexit "+operands[0]; } } diff --git a/jode/jode/expr/NewArrayOperator.java b/jode/jode/expr/NewArrayOperator.java index 29644c7..cb3bc61 100644 --- a/jode/jode/expr/NewArrayOperator.java +++ b/jode/jode/expr/NewArrayOperator.java @@ -2,20 +2,15 @@ package jode; import sun.tools.java.Type; public class NewArrayOperator extends SimpleOperator { - Type baseType; + String baseTypeString; - public NewArrayOperator(int addr, int length, - Type baseType, int dimensions) { - super(addr, length, baseType, 0, dimensions); - this.baseType = baseType; + public NewArrayOperator(Type arrayType, String baseTypeString, + int dimensions) { + super(arrayType, 0, dimensions); for (int i=0; i< dimensions; i++) { - this.type = Type.tArray(this.type); - operandTypes[i] = UnknownType.tUIndex; + operandTypes[i] = MyType.tUIndex; } - } - - public NewArrayOperator(int addr, int length, Type baseType) { - this(addr, length, baseType, 1); + this.baseTypeString = baseTypeString; } public int getPriority() { @@ -26,9 +21,9 @@ public class NewArrayOperator extends SimpleOperator { return 0; } - public String toString(CodeAnalyzer ca, String[] operands) { + public String toString(String[] operands) { StringBuffer result - = new StringBuffer("new ").append(ca.getTypeString(baseType)); + = new StringBuffer("new ").append(baseTypeString); for (int i=0; i< getOperandCount(); i++) { result.append("[").append(operands[i]).append("]"); } diff --git a/jode/jode/expr/NewOperator.java b/jode/jode/expr/NewOperator.java index ef15ff2..b12e271 100644 --- a/jode/jode/expr/NewOperator.java +++ b/jode/jode/expr/NewOperator.java @@ -2,16 +2,18 @@ package jode; import sun.tools.java.Type; public class NewOperator extends NoArgOperator { + String typeString; - public NewOperator(int addr, int length, Type type) { - super(addr,length, type); + public NewOperator(Type type, String typeString) { + super(type); + this.typeString = typeString; } public int getPriority() { return 950; } - public String toString(CodeAnalyzer ca, String[] operands) { - return "new "+getType().toString(); + public String toString(String[] operands) { + return "new "+typeString; } } diff --git a/jode/jode/expr/NoArgOperator.java b/jode/jode/expr/NoArgOperator.java index 0cc9981..f0512c3 100644 --- a/jode/jode/expr/NoArgOperator.java +++ b/jode/jode/expr/NoArgOperator.java @@ -3,8 +3,12 @@ import sun.tools.java.Type; public abstract class NoArgOperator extends Operator { - public NoArgOperator(int addr, int length, Type type) { - super(addr, length, type, 0); + public NoArgOperator(Type type, int operator) { + super(type, operator); + } + + public NoArgOperator(Type type) { + this(type, 0); } public int getOperandCount() { diff --git a/jode/jode/expr/NopOperator.java b/jode/jode/expr/NopOperator.java index a2f1aa7..0492c35 100644 --- a/jode/jode/expr/NopOperator.java +++ b/jode/jode/expr/NopOperator.java @@ -1,13 +1,21 @@ package jode; +import sun.tools.java.Type; public class NopOperator extends Instruction { - public NopOperator(int a, int l) { - super(a,l); + public NopOperator(Type type) { + super(type); } - public void dumpSource(TabbedPrintWriter tpw, CodeAnalyzer ca) - throws java.io.IOException + public NopOperator() { + this(MyType.tVoid); + } + + public boolean equals(Object o) { + return (o instanceof NopOperator); + } + + public String toString() { - tpw.println("nop;"); + return "nop"; } } diff --git a/jode/jode/expr/Operator.java b/jode/jode/expr/Operator.java index 4797c30..9aa46fe 100644 --- a/jode/jode/expr/Operator.java +++ b/jode/jode/expr/Operator.java @@ -5,29 +5,31 @@ public abstract class Operator extends Instruction { public final static int ADD_OP = 1; public final static int NEG_OP = 2; public final static int SHIFT_OP = 6; + public final static int AND_OP = 9; public final static int ASSIGN_OP = 12; public final static int OPASSIGN_OP= 12; - public final static int INC_OP = 24; + public final static int INC_OP = 24; /* must be even! */ + public final static int DEC_OP = 25; public final static int COMPARE_OP = 26; /* must be even! */ public final static int LOG_AND_OP = 32; /* must be even! */ public final static int LOG_OR_OP = 33; public final static int LOG_NOT_OP = 34; static String opString[] = { - "", "+","-","*","/","%", "<<", ">>", ">>>", "&", "|", "^", - "=","+=","-=","*=","/=","%=", "<<=", ">>=", ">>>=", "&=", "|=", "^=", + "", " + ", " - ", " * ", " / ", " % ", + " << ", " >> ", " >>> ", " & ", " | ", " ^ ", + " = ", " += ", " -= ", " *= ", " /= ", " %= ", + " <<= ", " >>= ", " >>>= ", " &= ", " |= ", " ^= ", "++", "--", - "==","!=","<",">=",">", "<=", "&&", "||", - "~", "!" + " == "," != "," < "," >= "," > ", " <= ", " && ", " || ", + "!", "~" }; - protected Type type; protected int operator; String casts; - Operator (int addr, int length, Type type, int op) { - super(addr,length); - this.type = type; + Operator (Type type, int op) { + super(type); this.operator = op; if (type == null) throw new AssertError("type == null"); @@ -46,19 +48,15 @@ public abstract class Operator extends Instruction { * @return true if the operand types changed */ public boolean setType(Type type) { - if (!UnknownType.isOfType(type, this.type)) { - casts = type.toString()+"/*invalid*/ <- " + casts; - } else if (type != this.type) { - casts = type.toString()+" <- " + casts; - } - this.type = type; +// if (!MyType.isOfType(type, this.type)) { +// casts = type.toString()+"/*invalid*/ <- " + casts; +// } else if (type != this.type) { +// casts = type.toString()+" <- " + casts; +// } +// this.type = type; return false; } - public final Type getType() { - return type; - } - public String getOperatorString() { return opString[operator]; } @@ -95,17 +93,14 @@ public abstract class Operator extends Instruction { public abstract Type getOperandType(int i); public abstract int getOperandCount(); public abstract void setOperandType(Type[] inputTypes); - public abstract String toString(CodeAnalyzer ca, String[] operands); + public abstract String toString(String[] operands); - public void dumpSource(TabbedPrintWriter writer, CodeAnalyzer ca) - throws java.io.IOException + public String toString() { - if (type == null) - throw new AssertError("type == null"); String[] operands = new String[getOperandCount()]; for (int i=0; i< operands.length; i++) { operands[i] = "stack_"+(operands.length-i-1); } - writer.println(toString(ca, operands)); + return toString(operands); } } diff --git a/jode/jode/expr/PopOperator.java b/jode/jode/expr/PopOperator.java index 5fad913..d540763 100644 --- a/jode/jode/expr/PopOperator.java +++ b/jode/jode/expr/PopOperator.java @@ -4,9 +4,9 @@ import sun.tools.java.Type; public class PopOperator extends SimpleOperator { int count; - public PopOperator(int a, int l, int count) { - super(a,l, Type.tVoid, 0, 1); - operandTypes[0] = UnknownType.tUnknown; + public PopOperator(int count) { + super(Type.tVoid, 0, 1); + operandTypes[0] = MyType.tUnknown; this.count = count; } @@ -18,7 +18,7 @@ public class PopOperator extends SimpleOperator { return 0; } - public String toString(CodeAnalyzer ca, String[] operands) { + public String toString(String[] operands) { return operands[0]; } } diff --git a/jode/jode/expr/PostFixOperator.java b/jode/jode/expr/PostFixOperator.java index f4b2635..3beca0d 100644 --- a/jode/jode/expr/PostFixOperator.java +++ b/jode/jode/expr/PostFixOperator.java @@ -1,9 +1,12 @@ package jode; import sun.tools.java.Type; -public class PostFixOperator extends SimpleOperator { - public PostFixOperator(int addr, int length, Type type, int op) { - super(addr,length, type, op, 1); +public class PostFixOperator extends Operator { + StoreInstruction store; + + public PostFixOperator(Type type, int op, StoreInstruction store) { + super(type, op); + this.store = store; } public int getPriority() { @@ -14,21 +17,29 @@ public class PostFixOperator extends SimpleOperator { return getPriority(); } + public Type getOperandType(int i) { + return store.getLValueOperandType(i); + } + + public int getOperandCount() { + return store.getLValueOperandCount(); + } + /** * Sets the return type of this operator. * @return true if the operand types changed */ public boolean setType(Type type) { - super.setType(type); - Type newOpType = UnknownType.commonType(type, operandTypes[0]); - if (newOpType != operandTypes[0]) { - operandTypes[0] = newOpType; - return true; - } - return false; + boolean result = store.setLValueType(type); + super.setType(store.getLValueType()); + return result; + } + + public void setOperandType(Type[] inputTypes) { + store.setLValueOperandType(inputTypes); } - public String toString(CodeAnalyzer ca, String[] operands) { - return operands[0] + getOperatorString(); + public String toString(String[] operands) { + return store.getLValueString(operands) + getOperatorString(); } } diff --git a/jode/jode/expr/PutFieldOperator.java b/jode/jode/expr/PutFieldOperator.java index 222d3db..fc20caf 100644 --- a/jode/jode/expr/PutFieldOperator.java +++ b/jode/jode/expr/PutFieldOperator.java @@ -2,12 +2,14 @@ package jode; import sun.tools.java.*; public class PutFieldOperator extends StoreInstruction { + CodeAnalyzer codeAnalyzer; boolean staticFlag; FieldDefinition field; - public PutFieldOperator(int addr, int length, boolean staticFlag, - FieldDefinition field) { - super(addr, length, field.getType()); + public PutFieldOperator(CodeAnalyzer codeAnalyzer, boolean staticFlag, + FieldDefinition field) { + super(field.getType(), ASSIGN_OP); + this.codeAnalyzer = codeAnalyzer; this.staticFlag = staticFlag; this.field = field; } @@ -34,7 +36,7 @@ public class PutFieldOperator extends StoreInstruction { /* shouldn't be called */ throw new AssertError("Field is static"); } - return field.getClassDefinition().getType(); + return MyType.tSubType(field.getClassDefinition().getType()); } public void setLValueOperandType(Type[] t) { @@ -45,13 +47,15 @@ public class PutFieldOperator extends StoreInstruction { return; } - public String getLValueString(CodeAnalyzer ca, String[] operands) { + public String getLValueString(String[] operands) { String object; if (staticFlag) { - if (field.getClassDefinition() == ca.getClassDefinition()) + if (field.getClassDefinition() + == codeAnalyzer.getClassDefinition()) return field.getName().toString(); object = - ca.getTypeString(field.getClassDeclaration().getType())+"."; + codeAnalyzer.getTypeString + (field.getClassDeclaration().getType())+"."; } else { if (operands[0].equals("this")) return field.getName().toString(); @@ -59,4 +63,9 @@ public class PutFieldOperator extends StoreInstruction { } return object + "." + field.getName(); } + + public boolean equals(Object o) { + return (o instanceof PutFieldOperator) && + ((PutFieldOperator)o).field == field; + } } diff --git a/jode/jode/expr/RetInstructionHeader.java b/jode/jode/expr/RetInstructionHeader.java new file mode 100644 index 0000000..5199d75 --- /dev/null +++ b/jode/jode/expr/RetInstructionHeader.java @@ -0,0 +1,45 @@ +package jode; + +/** + * This is an InstructionHeader for an RET (return from JSR) opcode. + * @author Jochen Hoenicke + */ +public class RetInstructionHeader extends InstructionHeader { + int dest; + boolean conditional; + + InstructionHeader destination; + InstructionHeader[] successors;/*XXX*/ + + /** + * Create an InstructionHeader for a conditional or unconditional + * Ret. + * @param addr The address of this instruction. + * @param length The length of this instruction. + * @param instr The underlying Instruction of int type (ret addr). + */ + public RetInstructionHeader(int addr, int length, Instruction instr) { + super(addr, length, instr); + } + + /** + * Get the successors of this instructions. This function mustn't + * be called before resolveSuccessors is executed for this + * InstructionHeaders. + * @return Array of successors. + */ + public InstructionHeader[] getSuccessors() { + /* XXX */ + return successors; + } + + /** + * Resolve the successors and predecessors and build a doubly + * linked list. + * @param instHeaders an array of the InstructionHeaders, indexed + * by addresses. + */ + public void resolveSuccessors(InstructionHeader[] instHeaders) { + nextInstruction = instHeaders[addr+length]; + } +} diff --git a/jode/jode/expr/RetOperator.java b/jode/jode/expr/RetOperator.java index 27e1ddb..a843007 100644 --- a/jode/jode/expr/RetOperator.java +++ b/jode/jode/expr/RetOperator.java @@ -3,18 +3,13 @@ package jode; public class RetOperator extends Instruction { int slot; - public RetOperator(int addr, int length, int slot) { - super(addr,length); + public RetOperator(int slot) { + super(MyType.tVoid); this.slot = slot; } - public int[] getSuccessors() { - return new int[0]; - } - - public void dumpSource(TabbedPrintWriter writer, CodeAnalyzer ca) - throws java.io.IOException + public String toString() { - writer.println("ret;"); + return "ret"; } } diff --git a/jode/jode/expr/ReturnOperator.java b/jode/jode/expr/ReturnOperator.java index b71f2f7..cea0b47 100644 --- a/jode/jode/expr/ReturnOperator.java +++ b/jode/jode/expr/ReturnOperator.java @@ -2,16 +2,12 @@ package jode; import sun.tools.java.Type; public class ReturnOperator extends SimpleOperator { - public ReturnOperator(int addr, int length, Type type) { - super(addr,length, Type.tVoid, 0, (type == Type.tVoid)?0:1); + public ReturnOperator(Type type) { + super(Type.tVoid, 0, (type == Type.tVoid)?0:1); if (type != Type.tVoid) operandTypes[0] = type; } - public int[] getSuccessors() { - return new int[0]; - } - public int getPriority() { return 0; } @@ -20,7 +16,7 @@ public class ReturnOperator extends SimpleOperator { return 0; } - public String toString(CodeAnalyzer ca, String[] operands) { + public String toString(String[] operands) { StringBuffer result = new StringBuffer("return"); if (getOperandCount() != 0) result.append(" ").append(operands[0]); diff --git a/jode/jode/expr/ShiftOperator.java b/jode/jode/expr/ShiftOperator.java index 2dc6005..89de051 100644 --- a/jode/jode/expr/ShiftOperator.java +++ b/jode/jode/expr/ShiftOperator.java @@ -7,9 +7,9 @@ import sun.tools.java.Type; public class ShiftOperator extends BinaryOperator { protected Type shiftType; - public ShiftOperator(int addr, int length, Type type, int op) { - super(addr,length, type, op); - shiftType = UnknownType.tUIndex; + public ShiftOperator(Type type, int op) { + super(type, op); + shiftType = MyType.tUIndex; } public Type getOperandType(int i) { @@ -17,7 +17,7 @@ public class ShiftOperator extends BinaryOperator { } public void setOperandType(Type[] inputTypes) { - operandType = UnknownType.commonType(operandType, inputTypes[0]); - shiftType = UnknownType.commonType(shiftType, inputTypes[1]); + operandType = MyType.intersection(operandType, inputTypes[0]); + shiftType = MyType.intersection(shiftType, inputTypes[1]); } } diff --git a/jode/jode/expr/SimpleOperator.java b/jode/jode/expr/SimpleOperator.java index a3b4817..c71b800 100644 --- a/jode/jode/expr/SimpleOperator.java +++ b/jode/jode/expr/SimpleOperator.java @@ -4,9 +4,9 @@ import sun.tools.java.Type; public abstract class SimpleOperator extends Operator { protected Type[] operandTypes; - public SimpleOperator(int addr, int length, Type type, int operator, + public SimpleOperator(Type type, int operator, int operandCount) { - super(addr, length, type, operator); + super(type, operator); operandTypes = new Type[operandCount]; for (int i=0; i< operandCount; i++) { operandTypes[i] = type; @@ -23,9 +23,9 @@ public abstract class SimpleOperator extends Operator { public void setOperandType(Type[] t) { for (int i=0; i< operandTypes.length; i++) { - if (UnknownType.commonType(operandTypes[i], t[i]) == Type.tError) + if (MyType.intersection(operandTypes[i], t[i]) == Type.tError) System.err.println("Error: "+operandTypes[i]+","+t[i]); - operandTypes[i] = UnknownType.commonType(operandTypes[i], t[i]); + operandTypes[i] = MyType.intersection(operandTypes[i], t[i]); } } } diff --git a/jode/jode/expr/StoreInstruction.java b/jode/jode/expr/StoreInstruction.java index 8af333c..b570ce9 100644 --- a/jode/jode/expr/StoreInstruction.java +++ b/jode/jode/expr/StoreInstruction.java @@ -6,13 +6,9 @@ public abstract class StoreInstruction extends Operator { public String lvCasts; Type lvalueType; - public StoreInstruction(int addr, int length, Type type) { - this (addr,length, type, ASSIGN_OP); - } - - public StoreInstruction(int addr, int length, Type type, int operator) { - super(addr,length, Type.tVoid, operator); - lvalueType = type; + public StoreInstruction(Type type, int operator) { + super(Type.tVoid, operator); + lvalueType = MyType.tSubType(type); lvCasts = lvalueType.toString(); } @@ -31,16 +27,16 @@ public abstract class StoreInstruction extends Operator { * @return true if the operand types changed */ public boolean setLValueType(Type type) { - if (!UnknownType.isOfType(type, this.lvalueType)) { - lvCasts = type.toString()+"/*invalid*/ <- " + lvCasts; - } else if (type != this.lvalueType) { - lvCasts = type.toString()+" <- " + lvCasts; - } +// if (!MyType.isOfType(type, this.lvalueType)) { +// lvCasts = type.toString()+"/*invalid*/ <- " + lvCasts; +// } else if (type != this.lvalueType) { +// lvCasts = type.toString()+" <- " + lvCasts; +// } this.lvalueType = type; return false; } - public abstract String getLValueString(CodeAnalyzer ca, String[] operands); + public abstract String getLValueString(String[] operands); public int getPriority() { return 100; @@ -55,7 +51,7 @@ public abstract class StoreInstruction extends Operator { public Type getOperandType(int i) { if (i == getLValueOperandCount()) - return getLValueType(); + return MyType.tSubType(getLValueType()); else return getLValueOperandType(i); } @@ -63,18 +59,18 @@ public abstract class StoreInstruction extends Operator { public void setOperandType(Type[] t) { if (getLValueOperandCount() > 0) setLValueOperandType(t); - setLValueType - (UnknownType.commonType(lvalueType, t[getLValueOperandCount()])); + setLValueType(MyType.intersection + (lvalueType, + MyType.tSuperType(t[getLValueOperandCount()]))); } public int getOperandCount() { return 1 + getLValueOperandCount(); } - public String toString(CodeAnalyzer ca, String[] operands) + public String toString(String[] operands) { - return "{"+lvCasts+" "+getLValueString(ca, operands) + "} "+ - getOperatorString() +" "+ + return getLValueString(operands) + getOperatorString() + operands[getLValueOperandCount()]; } } diff --git a/jode/jode/expr/StringAddOperator.java b/jode/jode/expr/StringAddOperator.java new file mode 100644 index 0000000..ba20186 --- /dev/null +++ b/jode/jode/expr/StringAddOperator.java @@ -0,0 +1,27 @@ +package jode; +import sun.tools.java.Type; + +public class StringAddOperator extends SimpleOperator { + protected Type operandType; + + public StringAddOperator() { + super(MyType.tString, ADD_OP, 2); + operandTypes[1] = MyType.tUnknown; + } + + public int getPriority() { + return 610; + } + + public int getOperandPriority(int i) { + return 610 + i; + } + + public boolean equals(Object o) { + return (o instanceof StringAddOperator); + } + + public String toString(String[] operands) { + return operands[0] + getOperatorString() + operands[1]; + } +} diff --git a/jode/jode/expr/SwapOperator.java b/jode/jode/expr/SwapOperator.java index df67646..de95061 100644 --- a/jode/jode/expr/SwapOperator.java +++ b/jode/jode/expr/SwapOperator.java @@ -1,13 +1,12 @@ package jode; public class SwapOperator extends Instruction { - public SwapOperator(int a, int l) { - super(a,l); + public SwapOperator() { + super(MyType.tError); } - public void dumpSource(TabbedPrintWriter writer, CodeAnalyzer ca) - throws java.io.IOException + public String toString() { - writer.println("swap;"); + return "swap"; } } diff --git a/jode/jode/expr/ThrowOperator.java b/jode/jode/expr/ThrowOperator.java index 3995219..b7cec55 100644 --- a/jode/jode/expr/ThrowOperator.java +++ b/jode/jode/expr/ThrowOperator.java @@ -3,11 +3,11 @@ import sun.tools.java.Type; public class ThrowOperator extends ReturnOperator { - public ThrowOperator(int addr, int length) { - super(addr,length, UnknownType.tUObject); + public ThrowOperator() { + super(MyType.tUObject); } - public String toString(CodeAnalyzer ca, String[] operands) { + public String toString(String[] operands) { return "throw " + operands[0]; } } diff --git a/jode/jode/expr/UnaryOperator.java b/jode/jode/expr/UnaryOperator.java index e25627e..1d0f744 100644 --- a/jode/jode/expr/UnaryOperator.java +++ b/jode/jode/expr/UnaryOperator.java @@ -2,8 +2,8 @@ package jode; import sun.tools.java.Type; public class UnaryOperator extends SimpleOperator { - public UnaryOperator(int addr, int length, Type type, int op) { - super(addr,length, type, op, 1); + public UnaryOperator(Type type, int op) { + super(type, op, 1); } public int getPriority() { @@ -20,7 +20,7 @@ public class UnaryOperator extends SimpleOperator { */ public boolean setType(Type type) { super.setType(type); - Type newOpType = UnknownType.commonType(type, operandTypes[0]); + Type newOpType = MyType.intersection(type, operandTypes[0]); if (newOpType != operandTypes[0]) { operandTypes[0] = newOpType; return true; @@ -28,7 +28,12 @@ public class UnaryOperator extends SimpleOperator { return false; } - public String toString(CodeAnalyzer ca, String[] operands) { + public boolean equals(Object o) { + return (o instanceof UnaryOperator) && + ((UnaryOperator)o).operator == operator; + } + + public String toString(String[] operands) { return getOperatorString() + operands[0]; } } diff --git a/jode/jode/type/ClassRangeType.java b/jode/jode/type/ClassRangeType.java new file mode 100644 index 0000000..050c985 --- /dev/null +++ b/jode/jode/type/ClassRangeType.java @@ -0,0 +1,319 @@ +package jode; +import sun.tools.java.*; + +/** + * This class represents an object type which isn't fully known. + * The real object type lies in a range of types between topType + * and bottomType.

    + * + * For a totally unknown type topType is tObject and bottomType is + * null. It is always garanteed that topType is an Array or an Object + * and that bottomType is null or an Array or an Object.

    + * + * @author Jochen Hoenicke + * @date 98/08/06 + */ +public class ClassRangeType extends MyType { + final Type bottomType; + final Type topType; + + public ClassRangeType(Type bottomType, Type topType) { + super(103, "-"); + if (bottomType != null && bottomType.getTypeCode() == 103) + bottomType = ((ClassRangeType)bottomType).bottomType; + if (topType != null && topType.getTypeCode() == 103) + topType = ((ClassRangeType)topType).topType; + this.bottomType = bottomType; + this.topType = topType; + } + + public static Type createRangeType(Type bottom, Type top) { + // TODO: XXX calculate < top, ...> \cap <..., bottom> + // e.g. top , bottom result + // x , null + // tUnknown, object + // Fahrrad , Fahrzeug error + // Fahrzeug, Fahrrad + // int , Fahrrad error + + /* First the trivial cases + */ + if (top == tError || bottom == tError) + return tError; + + /* This is always okay (right open interval, maybe left open) + */ + if (top == null) + return new ClassRangeType(bottom,top); + + /* -> + * if bottom is tObject, its okay. + */ + if (bottom == null || bottom == tObject) + return new ClassRangeType(tObject, top); + + /* now bottom != null and top != null */ + if (bottom.getTypeCode() == 9 && top.getTypeCode() == 9) + return tArray(createRangeType(bottom.getElementType(), + top.getElementType())); + + if (bottom.getTypeCode() != 10 || top.getTypeCode() != 10) + return tError; + + if (bottom == top) + return bottom; + + ClassDeclaration c1 = new ClassDeclaration(bottom.getClassName()); + ClassDeclaration c2 = new ClassDeclaration(top.getClassName()); + + try { + if (c1.getClassDefinition(env).superClassOf(env, c2) || + c1.getClassDefinition(env).implementedBy(env, c2)) + return new ClassRangeType(bottom, top); + } catch (ClassNotFound ex) { + } + return tError; + } + + public Type getElementType() { + Type bottom = bottomType != null ? bottomType.getElementType() : null; + Type top = topType != null ? topType.getElementType() : null; + return new ClassRangeType(bottom, top); + } + + /** + * Returns the specialized type of t1 and t2, e.g + * null , xx -> xx + * tObject, object -> object + * int , short -> short + * tArray(tObject), tArray(tUnknown) -> tArray(tObject) + * tArray(tUnknown), tObject -> tArray(tUnknown) + */ + public static Type getSpecializedType(Type t1, Type t2) { + if (t1 == null || t2 == tError) + return t2; + if (t2 == null || t1 == tError) + return t1; + + if (t1.getTypeCode() == 103) { + t1 = ((ClassRangeType)t1).bottomType; + if (t1 == null) + return t2; + } + if (t2.getTypeCode() == 103) { + t2 = ((ClassRangeType)t2).bottomType; + if (t2 == null) + return t1; + } + + if (t1 == t2) + return t1; + + if (t1.getTypeCode() <= 4 && t2.getTypeCode() <= 4) { + if (t1.getTypeCode() < t2.getTypeCode()) + return t1; + else + return t2; + } + + if ((t1.getTypeCode() != 9 && t1.getTypeCode() != 10) || + (t2.getTypeCode() != 9 && t2.getTypeCode() != 10)) + return tError; + + if (t1 == MyType.tObject) + return t2; + if (t2 == MyType.tObject) + return t1; + + if (t1.getTypeCode() == 9 && t2.getTypeCode() == 9) + return tArray(getSpecializedType(t1.getElementType(), + t2.getElementType())); + + if (t1.getTypeCode() != 10 && t2.getTypeCode() != 10) + return tError; + + /* Now we have two classes or interfaces. The result should + * be the object that is the the child of both objects resp + * implements both interfaces. + * + * I currently only handle the simple case where one of the + * two objects implements the other or is a child of it. + * + * Forget the following setences, java tells us if the local + * is an interface or an object. + * + * There are really complicated cases that are currently + * ignored: imaging, c1 and c2 are both disjunct interfaces + * and there are some object which implements them both. + * There is no way for us to guess which. + * + * What can we do about this? We probably need something more + * powerful than a simple class range. + * But maybe this isn't needed at all. How should someone + * use an object which implements two interfaces in a local + * variable without casting? The information which object + * to use must be somewhere in the method. + * + * But think of this code fragment: + * + * class Foo implements i1, i2 { ... } + * + * class Bar { + * Foo getFoo() { ... } + * void someFunction() { + * while ((Foo foo = getFoo()) != null) { + * foo.interface1Method(); + * foo.interface2Method(); + * } + * } + * } + * + * Since the while condition is moved to the bottom of + * the loop, the type information of foo is only available + * after the two interface methods are called. + * The current code would produce tError. */ + + + ClassDeclaration c1 = new ClassDeclaration(t1.getClassName()); + ClassDeclaration c2 = new ClassDeclaration(t2.getClassName()); + + try { + if (c1.getClassDefinition(env).superClassOf(env, c2)) + return t2; + if (c2.getClassDefinition(env).superClassOf(env, c1)) + return t1; +// if (c1.getClassDefinition(env).implementedBy(env, c2)) +// return t2; +// if (c2.getClassDefinition(env).implementedBy(env, c1)) +// return t1; + } catch (ClassNotFound ex) { + } + return tError; + } + + /** + * Returns the generalized type of t1 and t2, e.g + * tObject, tString -> tObject + * int , short -> int + * tArray(tObject), tArray(tUnknown) -> tArray(tUnknown) + * tArray(tUnknown), tObject -> tObject + * tUnknown, tString -> tString !! + * null , tString -> tString !! + */ + public static Type getGeneralizedType(Type t1, Type t2) { + if (t1 != null && t1.getTypeCode() == 103) + t1 = ((ClassRangeType)t1).topType; + if (t2 != null && t2.getTypeCode() == 103) + t2 = ((ClassRangeType)t2).topType; + + if (t1 == t2 || + t1 == tError || t2 == null) + return t1; + if (t2 == tError || t1 == null) + return t2; + + if (t1.getTypeCode() <= 4 && t2.getTypeCode() <= 4) { + if (t1.getTypeCode() < t2.getTypeCode()) + return t2; + else + return t1; + } + if ((t1.getTypeCode() != 9 && t1.getTypeCode() != 10) || + (t1.getTypeCode() != 9 && t1.getTypeCode() != 10)) + return tError; + + if (t1 == MyType.tObject) + return t1; + if (t2 == MyType.tObject) + return t2; + + if (t1.getTypeCode() == 9 && t2.getTypeCode() == 9) + return tArray(getGeneralizedType(t1.getElementType(), + t2.getElementType())); + + if (t1.getTypeCode() != 10 && t2.getTypeCode() != 10) + return tError; + + /* This code is not always correct: + * We don't want a real super type in all cases, but maybe only + * an interface which both objects implement. Think of this: + * + * interface I; + * class C1 implements I; + * class C2 implements I; + * + * { + * I var; + * if (cond) + * var = getC1(); + * else + * var = getC2(); + * return var.interfaceMethod(); + * } + * + * The current code would first assign the type object to + * var and then produce a type error when interfaceMethod + * is called. + * + * Now we have proved that we need some better concept for + * types. (Maybe a set of types for the upper and lower + * bound) + */ + + ClassDeclaration c1 = new ClassDeclaration(t1.getClassName()); + 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 (c1.getClassDefinition(env).implementedBy(env, c2)) +// return t1; +// if (c2.getClassDefinition(env).implementedBy(env, c1)) +// return t2; + + ClassDefinition c = c1.getClassDefinition(env); + while(c != null && !c.superClassOf(env, c2)) { + c = c.getSuperClass(env).getClassDefinition(env); + } + if (c != null) + return tClass(c.getName()); + } catch (ClassNotFound ex) { + } + return tObject; + } + + public Type getIntersection(ClassRangeType type) + { + Type bottom = getSpecializedType(bottomType, type.bottomType); + Type top = getGeneralizedType(topType, type.topType); + + System.err.println("intersecting "+ this +" and "+ type + + " to <" + bottom + "-" + top + ">"); + try { + throw new AssertError("in:"); + } catch(AssertError error) { + error.printStackTrace(); + } + return createRangeType(bottom,top); + } + + public boolean intersects(ClassRangeType type) + { + return getIntersection(type) != tError; + } + + public String typeString(String string, boolean flag1, boolean flag2) + { +// if (verbose??) + return "<"+bottomType+"-"+topType+">" + string; +// else +// return bottomType.typeString(string, flag1, flag2); + } + +// public String toString() +// { +// return "<"+bottomType+"-"+topType+">"; +// } +} diff --git a/jode/jode/type/MyType.java b/jode/jode/type/MyType.java new file mode 100644 index 0000000..df9fe3d --- /dev/null +++ b/jode/jode/type/MyType.java @@ -0,0 +1,199 @@ +package jode; +import sun.tools.java.Constants; +import sun.tools.java.Type; +import sun.tools.java.Identifier; +import java.util.Hashtable; + +/** + * This is my own type class. It differs from sun.tools.java.Type, in + * that it maintains a type range. This type range may be implicit or + * explicit.

    + * + * The type tInt (which is the same as Type.tInt) is a good example + * for the implicit range <tInt -- tBoolean>. Most other + * standard types stand for the range consisting only of themselve. + * The explicit form is the class range type

    + * + * The main operation on a type range is the intersection. To do this + * on class ranges we need two more operations: specialization and + * generalization.

    + * + * specialization chooses the startpoint of two intervals which + * lies in the open range <sp -- null>, where sp is the startpoint + * of the other interval, or returns tError on failure.

    + * + * generalization chooses the endpoint of two intervals which lies in + * the open range <null -- ep>, where ep is the endpoint of + * the other interval, or returns tError on failure.

    + */ +public class MyType extends Type { + static Hashtable superclasses = new Hashtable(); + + protected static JodeEnvironment env; + + public static final Type tStringBuffer = + Type.tClass(idJavaLangStringBuffer); + public static final Type tUnknown = new ClassRangeType(null, null); + public static final Type tUInt = tInt; + public static final Type tUIndex = tInt; + public static final Type tUObject = new ClassRangeType(tObject, null); + + public static Type tSuperType(Type type) { + int typeCode = type.getTypeCode(); + if (typeCode == 9 || typeCode == 10 || typeCode == 103) + return new ClassRangeType(tObject, type); + else + return type; + } + + public static Type tSubType(Type type) { + int typeCode = type.getTypeCode(); + if (typeCode == 9 || typeCode == 10 || typeCode == 103) + return new ClassRangeType(type, null); + else + return type; + } + + public static Type tClassOrArray(Identifier ident) { + if (ident.toString().charAt(0) == '[') + return MyType.tType(ident.toString()); + else + return MyType.tClass(ident); + } + + public static void setEnvironment(JodeEnvironment e) { + env = e; + } + + protected MyType(int i, String str) { + super (i, str); + } + + public int stackSize() + { + return 1; + } + + public String typeString(String var, boolean flag1, boolean flag2) + { + String typeStr; + switch (typeCode) { + case 100: typeStr="unknown"; break; + default: + throw new RuntimeException("Wrong typeCode "+typeCode); + } + if (var.length() > 0) + return typeStr+" "+var; + return typeStr; + } + + /** + * Find the intersection of two types + * @param t1 the first type. + * @param t2 the second type. + * @return the intersection, or tError, if a type conflict happens. + */ + public static Type intersection(Type t1, Type t2) { + System.err.println("intersecting "+ t1 +" and "+ t2); + /* Trivial cases first. + */ + if (t1 == t2 || t2 == tUnknown) + return t1; + if (t1 == tUnknown) + return t2; + + /* This is the integer case + * tBoolean = 0 ,..., tInt = 4 + * return the smaller type code. + */ + if (t1.getTypeCode() <= 4 && t2.getTypeCode() <= 4) { + if (t1.getTypeCode() < t2.getTypeCode()) + return t1; + else + return t2; + } + + /* If this is an array or a class convert to class range. + */ + if (t1.getTypeCode() == 9 || t1.getTypeCode() == 10) + t1 = new ClassRangeType(t1,t1); + + if (t2.getTypeCode() == 9 || t2.getTypeCode() == 10) + t2 = new ClassRangeType(t2,t2); + + /* Now it must be a class range type, or we have lost! + */ + if (t1.getTypeCode() != 103 || t2.getTypeCode() != 103) + throw new AssertError("Types incompatible: "+ + t1.toString()+","+ t2.toString()); +// return tError; + + return ((ClassRangeType)t1).getIntersection((ClassRangeType)t2); + } + + + /** + * @deprecated renamed to intersection. + */ + public static Type commonType(Type t1, Type t2) { + return intersection(t1, t2); + } + + /** + * Check if t1 is in <unknown -- t2&rt;. + * @return true if t1 is a more specific type than t2, e.g. + * if t2 is a superclass of t1 + * @deprecated think about it, you don't need it! (I think) + * this code is probably broken so don't use it! + */ + public static boolean isOfType(Type t1, Type t2) { + if ((t1 == t2 || t2 == tUnknown) && t1 != tError) + return true; + + switch (t1.getTypeCode()) { + case 0: /* boolean*/ + case 1: /* byte */ + case 2: /* char */ + case 3: /* short */ + case 4: /* int */ + + /* JavaC thinks, that this is okay. */ + if (t2.getTypeCode() >= 0 && t2.getTypeCode() <=4) + return true; + +// /* fallthrough */ +// case 104: /* unknown index */ +// if (t2 == tUInt) +// return true; + break; + + case 5: /* long */ + case 6: /* float */ + case 7: /* double */ + case 8: /* null? */ + case 11: /* void */ + case 12: /* method */ + case 13: /* error */ +// case 101: /* unknown int */ + /* This are only to themself compatible */ + break; + + case 9: /* array */ + case 10: /* class */ + t1 = new ClassRangeType(t1, null); + /* fall through */ + case 103: /* class range type */ + if (t2.getTypeCode() == 103) + return ((ClassRangeType)t1).intersects((ClassRangeType)t2); + + if (t2.getTypeCode() == 9 || t2.getTypeCode() == 10) + return ((ClassRangeType)t1). + intersects(new ClassRangeType(t2, null)); + break; + + default: + throw new AssertError("Wrong typeCode "+t1.getTypeCode()); + } + return false; + } +} diff --git a/jode/jode/type/UnknownSuperType.java b/jode/jode/type/UnknownSuperType.java new file mode 100644 index 0000000..c6c5d08 --- /dev/null +++ b/jode/jode/type/UnknownSuperType.java @@ -0,0 +1,22 @@ +package jode; +import sun.tools.java.Type; + +public class UnknownSuperType extends MyType { + Type elemType; + + public UnknownSuperType(Type type) { + super(103, "<"); + elemType = type; + } + + public Type getElementType() + { + return elemType; + } + + public String typeString(String string, boolean flag1, boolean flag2) + { + return ""; + } +}