Typen korrekt?

git-svn-id: https://svn.code.sf.net/p/jode/code/trunk@6 379699f6-c40d-0410-875b-85095c16579e
stable
delwi 27 years ago
parent fbd4236fed
commit 1995b7a078
  1. 7
      jode/jode/Decompiler.java
  2. 649
      jode/jode/bytecode/Opcodes.java
  3. 4
      jode/jode/decompiler/ClassAnalyzer.java
  4. 1318
      jode/jode/decompiler/CodeAnalyzer.java
  5. 24
      jode/jode/decompiler/FieldAnalyzer.java
  6. 17
      jode/jode/decompiler/ImportHandler.java
  7. 103
      jode/jode/decompiler/LocalInfo.java
  8. 4
      jode/jode/decompiler/LocalVariable.java
  9. 206
      jode/jode/decompiler/LocalVariableAnalyzer.java
  10. 28
      jode/jode/decompiler/LocalVariableRangeList.java
  11. 27
      jode/jode/decompiler/LocalVariableTable.java
  12. 77
      jode/jode/decompiler/MethodAnalyzer.java
  13. 2
      jode/jode/decompiler/TabbedPrintWriter.java
  14. 10
      jode/jode/expr/ArrayLengthOperator.java
  15. 14
      jode/jode/expr/ArrayLoadOperator.java
  16. 39
      jode/jode/expr/ArrayStoreOperator.java
  17. 15
      jode/jode/expr/AssignOperator.java
  18. 19
      jode/jode/expr/BinaryOperator.java
  19. 13
      jode/jode/expr/CheckCastOperator.java
  20. 15
      jode/jode/expr/CompareBinaryOperator.java
  21. 39
      jode/jode/expr/CompareToIntOperator.java
  22. 23
      jode/jode/expr/CompareUnaryOperator.java
  23. 12
      jode/jode/expr/ConstOperator.java
  24. 30
      jode/jode/expr/ConstantArrayOperator.java
  25. 7
      jode/jode/expr/ConstructorOperator.java
  26. 10
      jode/jode/expr/ConvertOperator.java
  27. 10
      jode/jode/expr/DupOperator.java
  28. 22
      jode/jode/expr/EmptyStringOperator.java
  29. 178
      jode/jode/expr/Expression.java
  30. 21
      jode/jode/expr/GetFieldOperator.java
  31. 55
      jode/jode/expr/IIncOperator.java
  32. 14
      jode/jode/expr/IfThenElseOperator.java
  33. 14
      jode/jode/expr/InstanceOfOperator.java
  34. 32
      jode/jode/expr/Instruction.java
  35. 282
      jode/jode/expr/InstructionHeader.java
  36. 31
      jode/jode/expr/InvokeOperator.java
  37. 55
      jode/jode/expr/JsrInstructionHeader.java
  38. 10
      jode/jode/expr/JsrOperator.java
  39. 54
      jode/jode/expr/LocalLoadOperator.java
  40. 19
      jode/jode/expr/LocalPostFixOperator.java
  41. 75
      jode/jode/expr/LocalStoreOperator.java
  42. 11
      jode/jode/expr/LocalVarOperator.java
  43. 35
      jode/jode/expr/MethodInstructionHeader.java
  44. 6
      jode/jode/expr/MonitorEnterOperator.java
  45. 8
      jode/jode/expr/MonitorExitOperator.java
  46. 21
      jode/jode/expr/NewArrayOperator.java
  47. 10
      jode/jode/expr/NewOperator.java
  48. 8
      jode/jode/expr/NoArgOperator.java
  49. 18
      jode/jode/expr/NopOperator.java
  50. 45
      jode/jode/expr/Operator.java
  51. 8
      jode/jode/expr/PopOperator.java
  52. 35
      jode/jode/expr/PostFixOperator.java
  53. 23
      jode/jode/expr/PutFieldOperator.java
  54. 45
      jode/jode/expr/RetInstructionHeader.java
  55. 13
      jode/jode/expr/RetOperator.java
  56. 10
      jode/jode/expr/ReturnOperator.java
  57. 10
      jode/jode/expr/ShiftOperator.java
  58. 8
      jode/jode/expr/SimpleOperator.java
  59. 34
      jode/jode/expr/StoreInstruction.java
  60. 27
      jode/jode/expr/StringAddOperator.java
  61. 9
      jode/jode/expr/SwapOperator.java
  62. 6
      jode/jode/expr/ThrowOperator.java
  63. 13
      jode/jode/expr/UnaryOperator.java
  64. 319
      jode/jode/type/ClassRangeType.java
  65. 199
      jode/jode/type/MyType.java
  66. 22
      jode/jode/type/UnknownSuperType.java

@ -6,7 +6,12 @@ public class Decompiler {
public static void main(String[] params) {
JodeEnvironment env = new JodeEnvironment();
for (int i=0; i<params.length; i++) {
env.doClass(params[i]);
if (params[i].equals("-v"))
env.isVerbose = true;
else if (params[i].equals("-debug"))
env.isDebugging = true;
else
env.doClass(params[i]);
}
}
}

@ -1,220 +1,24 @@
package jode;
import java.io.*;
import sun.tools.java.Type;
import sun.tools.java.*;
public interface Opcodes {
public final static int NOP_OP = 0;
public final static int ACONST_NULL_OP = 1;
public final static int ICONST_M1_OP = 2;
public final static int ICONST_0_OP = 3;
public final static int ICONST_1_OP = 4;
public final static int ICONST_2_OP = 5;
public final static int ICONST_3_OP = 6;
public final static int ICONST_4_OP = 7;
public final static int ICONST_5_OP = 8;
public final static int LCONST_0_OP = 9;
public final static int LCONST_1_OP = 10;
public final static int FCONST_0_OP = 11;
public final static int FCONST_1_OP = 12;
public final static int FCONST_2_OP = 13;
public final static int DCONST_0_OP = 14;
public final static int DCONST_1_OP = 15;
public final static int BIPUSH_OP = 16;
public final static int SIPUSH_OP = 17;
public final static int LDC_OP = 18;
public final static int LDC_W_OP = 19;
public final static int LDC2_W_OP = 20;
public final static int ILOAD_OP = 21;
public final static int LLOAD_OP = 22;
public final static int FLOAD_OP = 23;
public final static int DLOAD_OP = 24;
public final static int ALOAD_OP = 25;
public final static int ILOAD_0_OP = 26;
public final static int ILOAD_1_OP = 27;
public final static int ILOAD_2_OP = 28;
public final static int ILOAD_3_OP = 29;
public final static int LLOAD_0_OP = 30;
public final static int LLOAD_1_OP = 31;
public final static int LLOAD_2_OP = 32;
public final static int LLOAD_3_OP = 33;
public final static int FLOAD_0_OP = 34;
public final static int FLOAD_1_OP = 35;
public final static int FLOAD_2_OP = 36;
public final static int FLOAD_3_OP = 37;
public final static int DLOAD_0_OP = 38;
public final static int DLOAD_1_OP = 39;
public final static int DLOAD_2_OP = 40;
public final static int DLOAD_3_OP = 41;
public final static int ALOAD_0_OP = 42;
public final static int ALOAD_1_OP = 43;
public final static int ALOAD_2_OP = 44;
public final static int ALOAD_3_OP = 45;
public final static int IALOAD_OP = 46;
public final static int LALOAD_OP = 47;
public final static int FALOAD_OP = 48;
public final static int DALOAD_OP = 49;
public final static int AALOAD_OP = 50;
public final static int BALOAD_OP = 51;
public final static int CALOAD_OP = 52;
public final static int SALOAD_OP = 53;
public final static int ISTORE_OP = 54;
public final static int LSTORE_OP = 55;
public final static int FSTORE_OP = 56;
public final static int DSTORE_OP = 57;
public final static int ASTORE_OP = 58;
public final static int ISTORE_0_OP = 59;
public final static int ISTORE_1_OP = 60;
public final static int ISTORE_2_OP = 61;
public final static int ISTORE_3_OP = 62;
public final static int LSTORE_0_OP = 63;
public final static int LSTORE_1_OP = 64;
public final static int LSTORE_2_OP = 65;
public final static int LSTORE_3_OP = 66;
public final static int FSTORE_0_OP = 67;
public final static int FSTORE_1_OP = 68;
public final static int FSTORE_2_OP = 69;
public final static int FSTORE_3_OP = 70;
public final static int DSTORE_0_OP = 71;
public final static int DSTORE_1_OP = 72;
public final static int DSTORE_2_OP = 73;
public final static int DSTORE_3_OP = 74;
public final static int ASTORE_0_OP = 75;
public final static int ASTORE_1_OP = 76;
public final static int ASTORE_2_OP = 77;
public final static int ASTORE_3_OP = 78;
public final static int IASTORE_OP = 79;
public final static int LASTORE_OP = 80;
public final static int FASTORE_OP = 81;
public final static int DASTORE_OP = 82;
public final static int AASTORE_OP = 83;
public final static int BASTORE_OP = 84;
public final static int CASTORE_OP = 85;
public final static int SASTORE_OP = 86;
public final static int POP_OP = 87;
public final static int POP2_OP = 88;
public final static int DUP_OP = 89;
public final static int DUP_X1_OP = 90;
public final static int DUP_X2_OP = 91;
public final static int DUP2_OP = 92;
public final static int DUP2_X1_OP = 93;
public final static int DUP2_X2_OP = 94;
public final static int SWAP_OP = 95;
public final static int IADD_OP = 96;
public final static int LADD_OP = 97;
public final static int FADD_OP = 98;
public final static int DADD_OP = 99;
public final static int ISUB_OP = 100;
public final static int LSUB_OP = 101;
public final static int FSUB_OP = 102;
public final static int DSUB_OP = 103;
public final static int IMUL_OP = 104;
public final static int LMUL_OP = 105;
public final static int FMUL_OP = 106;
public final static int DMUL_OP = 107;
public final static int IDIV_OP = 108;
public final static int LDIV_OP = 109;
public final static int FDIV_OP = 110;
public final static int DDIV_OP = 111;
public final static int IREM_OP = 112;
public final static int LREM_OP = 113;
public final static int FREM_OP = 114;
public final static int DREM_OP = 115;
public final static int INEG_OP = 116;
public final static int LNEG_OP = 117;
public final static int FNEG_OP = 118;
public final static int DNEG_OP = 119;
public final static int ISHL_OP = 120;
public final static int LSHL_OP = 121;
public final static int ISHR_OP = 122;
public final static int LSHR_OP = 123;
public final static int IUSHR_OP = 124;
public final static int LUSHR_OP = 125;
public final static int IAND_OP = 126;
public final static int LAND_OP = 127;
public final static int IOR_OP = 128;
public final static int LOR_OP = 129;
public final static int IXOR_OP = 130;
public final static int LXOR_OP = 131;
public final static int IINC_OP = 132;
public final static int I2L_OP = 133;
public final static int I2F_OP = 134;
public final static int I2D_OP = 135;
public final static int L2I_OP = 136;
public final static int L2F_OP = 137;
public final static int L2D_OP = 138;
public final static int F2I_OP = 139;
public final static int F2L_OP = 140;
public final static int F2D_OP = 141;
public final static int D2I_OP = 142;
public final static int D2L_OP = 143;
public final static int D2F_OP = 144;
public final static int I2B_OP = 145;
public final static int I2C_OP = 146;
public final static int I2S_OP = 147;
public final static int LCMP_OP = 148;
public final static int FCMPL_OP = 149;
public final static int FCMPG_OP = 150;
public final static int DCMPL_OP = 151;
public final static int DCMPG_OP = 152;
public final static int IFEQ_OP = 153;
public final static int IFNE_OP = 154;
public final static int IFLT_OP = 155;
public final static int IFGE_OP = 156;
public final static int IFGT_OP = 157;
public final static int IFLE_OP = 158;
public final static int IF_ICMPEQ_OP = 159;
public final static int IF_ICMPNE_OP = 160;
public final static int IF_ICMPLT_OP = 161;
public final static int IF_ICMPGE_OP = 162;
public final static int IF_ICMPGT_OP = 163;
public final static int IF_ICMPLE_OP = 164;
public final static int IF_ACMPEQ_OP = 165;
public final static int IF_ACMPNE_OP = 166;
public final static int GOTO_OP = 167;
public final static int JSR_OP = 168;
public final static int RET_OP = 169;
public final static int TABLESWITCH_OP = 170;
public final static int LOOKUPSWITCH_OP = 171;
public final static int IRETURN_OP = 172;
public final static int LRETURN_OP = 173;
public final static int FRETURN_OP = 174;
public final static int DRETURN_OP = 175;
public final static int ARETURN_OP = 176;
public final static int RETURN_OP = 177;
public final static int GETSTATIC_OP = 178;
public final static int PUTSTATIC_OP = 179;
public final static int GETFIELD_OP = 180;
public final static int PUTFIELD_OP = 181;
public final static int INVOKEVIRTUAL_OP = 182;
public final static int INVOKESPECIAL_OP = 183;
public final static int INVOKESTATIC_OP = 184;
public final static int INVOKEINTERFACE_OP = 185;
public final static int NEW_OP = 187;
public final static int NEWARRAY_OP = 188;
public final static int ANEWARRAY_OP = 189;
public final static int ARRAYLENGTH_OP = 190;
public final static int ATHROW_OP = 191;
public final static int CHECKCAST_OP = 192;
public final static int INSTANCEOF_OP = 193;
public final static int MONITORENTER_OP = 194;
public final static int MONITOREXIT_OP = 195;
public final static int WIDE_OP = 196;
public final static int MULTIANEWARRAY_OP = 197;
public final static int IFNULL_OP = 198;
public final static int IFNONNULL_OP = 199;
public final static int GOTO_W_OP = 200;
public final static int JSR_W_OP = 201;
/**
* This is an abstract class which creates InstructionHeader for the
* opcodes in an byte stream.
*/
public abstract class Opcodes implements RuntimeConstants{
public final static Type ALL_INT_TYPE = UnknownType.tUInt;
public final static Type ALL_INT_TYPE = MyType.tUInt;
public final static Type INT_TYPE = Type.tInt;
public final static Type LONG_TYPE = Type.tLong;
public final static Type FLOAT_TYPE = Type.tFloat;
public final static Type DOUBLE_TYPE = Type.tDouble;
public final static Type OBJECT_TYPE = UnknownType.tUObject;
public final static Type OBJECT_TYPE = MyType.tUObject;
public final static Type BOOLEAN_TYPE = Type.tBoolean;
public final static Type BYTE_TYPE = Type.tByte;
public final static Type CHAR_TYPE = Type.tChar;
public final static Type SHORT_TYPE = Type.tShort;
public final static Type VOID_TYPE = Type.tVoid;
public final static Type types[][] = {
@ -222,4 +26,439 @@ public interface Opcodes {
{ INT_TYPE, LONG_TYPE, FLOAT_TYPE, DOUBLE_TYPE, OBJECT_TYPE,
BYTE_TYPE, CHAR_TYPE, SHORT_TYPE }
};
/**
* Read an opcode out of a data input stream containing the bytecode.
* @param addr The current address.
* @param stream The stream containing the java byte code.
* @param ca The Code Analyzer
* (where further information can be get from).
* @return The InstructionHeader representing this opcode
* or null if the stream is empty.
* @exception IOException if an read error occured.
* @exception ClassFormatError if an invalid opcode is detected.
*/
public static
InstructionHeader readOpcode(int addr, DataInputStream stream,
CodeAnalyzer ca)
throws IOException, ClassFormatError
{
try {
int opcode = stream.readUnsignedByte();
switch (opcode) {
case opc_nop:
return new InstructionHeader(addr, 1, new NopOperator());
case opc_aconst_null:
return new InstructionHeader
(addr, 1, new ConstOperator(OBJECT_TYPE, "null"));
case opc_iconst_m1:
case opc_iconst_0: case opc_iconst_1: case opc_iconst_2:
case opc_iconst_3: case opc_iconst_4: case opc_iconst_5:
return new InstructionHeader
(addr, 1, new ConstOperator
(ALL_INT_TYPE, Integer.toString(opcode - opc_iconst_0)));
case opc_lconst_0: case opc_lconst_1:
return new InstructionHeader
(addr, 1, new ConstOperator
(LONG_TYPE,
Integer.toString(opcode - opc_lconst_0) + "L"));
case opc_fconst_0: case opc_fconst_1: case opc_fconst_2:
return new InstructionHeader
(addr, 1, new ConstOperator
(FLOAT_TYPE,
Integer.toString(opcode - opc_fconst_0) + ".0F"));
case opc_dconst_0: case opc_dconst_1:
return new InstructionHeader
(addr, 1, new ConstOperator
(DOUBLE_TYPE,
Integer.toString(opcode - opc_dconst_0) + ".0"));
case opc_bipush:
return new InstructionHeader
(addr, 2, new ConstOperator
(ALL_INT_TYPE, Integer.toString(stream.readByte())));
case opc_sipush:
return new InstructionHeader
(addr, 3, new ConstOperator
(ALL_INT_TYPE, Integer.toString(stream.readShort())));
case opc_ldc: {
int index = stream.readUnsignedByte();
return new InstructionHeader
(addr, 2, new ConstOperator
(ca.env.getConstantType(index),
ca.env.getConstant(index).toString()));
}
case opc_ldc_w:
case opc_ldc2_w: {
int index = stream.readUnsignedShort();
return new InstructionHeader
(addr, 3, new ConstOperator
(ca.env.getConstantType(index),
ca.env.getConstant(index).toString()));
}
case opc_iload: case opc_lload:
case opc_fload: case opc_dload: case opc_aload:
return new InstructionHeader
(addr, 2, new LocalLoadOperator
(types[0][opcode-opc_iload],
stream.readUnsignedByte()));
case opc_iload_0: case opc_iload_1: case opc_iload_2: case opc_iload_3:
case opc_lload_0: case opc_lload_1: case opc_lload_2: case opc_lload_3:
case opc_fload_0: case opc_fload_1: case opc_fload_2: case opc_fload_3:
case opc_dload_0: case opc_dload_1: case opc_dload_2: case opc_dload_3:
case opc_aload_0: case opc_aload_1: case opc_aload_2: case opc_aload_3:
return new InstructionHeader
(addr, 1, new LocalLoadOperator
(types[0][(opcode-opc_iload_0)/4],
(opcode-opc_iload_0) & 3));
case opc_iaload: case opc_laload:
case opc_faload: case opc_daload: case opc_aaload:
case opc_baload: case opc_caload: case opc_saload:
return new InstructionHeader
(addr, 1, new ArrayLoadOperator
(types[1][opcode - opc_iaload]));
case opc_istore: case opc_lstore:
case opc_fstore: case opc_dstore: case opc_astore:
return new InstructionHeader
(addr, 2, new LocalStoreOperator
(types[0][opcode-opc_istore],
stream.readUnsignedByte(),
Operator.ASSIGN_OP));
case opc_istore_0: case opc_istore_1:
case opc_istore_2: case opc_istore_3:
case opc_lstore_0: case opc_lstore_1:
case opc_lstore_2: case opc_lstore_3:
case opc_fstore_0: case opc_fstore_1:
case opc_fstore_2: case opc_fstore_3:
case opc_dstore_0: case opc_dstore_1:
case opc_dstore_2: case opc_dstore_3:
case opc_astore_0: case opc_astore_1:
case opc_astore_2: case opc_astore_3:
return new InstructionHeader
(addr, 1, new LocalStoreOperator
(types[0][(opcode-opc_istore_0)/4],
(opcode-opc_istore_0) & 3,
Operator.ASSIGN_OP));
case opc_iastore: case opc_lastore:
case opc_fastore: case opc_dastore: case opc_aastore:
case opc_bastore: case opc_castore: case opc_sastore:
return new InstructionHeader
(addr, 1, new ArrayStoreOperator
(types[1][opcode - opc_iastore]));
case opc_pop: case opc_pop2:
return new InstructionHeader
(addr, 1, new PopOperator(opcode - opc_pop + 1));
case opc_dup: case opc_dup_x1: case opc_dup_x2:
case opc_dup2: case opc_dup2_x1: case opc_dup2_x2:
return new InstructionHeader
(addr, 1, new DupOperator
((opcode - opc_dup)%3, (opcode - opc_dup)/3+1));
case opc_swap:
return new InstructionHeader(addr, 1, new SwapOperator());
case opc_iadd: case opc_ladd: case opc_fadd: case opc_dadd:
case opc_isub: case opc_lsub: case opc_fsub: case opc_dsub:
case opc_imul: case opc_lmul: case opc_fmul: case opc_dmul:
case opc_idiv: case opc_ldiv: case opc_fdiv: case opc_ddiv:
case opc_irem: case opc_lrem: case opc_frem: case opc_drem:
return new InstructionHeader
(addr, 1, new BinaryOperator
(types[0][(opcode - opc_iadd)%4],
(opcode - opc_iadd)/4+Operator.ADD_OP));
case opc_ineg: case opc_lneg: case opc_fneg: case opc_dneg:
return new InstructionHeader
(addr, 1, new UnaryOperator
(types[0][opcode - opc_ineg], Operator.NEG_OP));
case opc_ishl: case opc_lshl:
case opc_ishr: case opc_lshr:
case opc_iushr: case opc_lushr:
return new InstructionHeader
(addr, 1, new ShiftOperator
(types[0][(opcode - opc_ishl)%2],
(opcode - opc_ishl)/2 + Operator.SHIFT_OP));
case opc_iand: case opc_land:
case opc_ior : case opc_lor :
case opc_ixor: case opc_lxor:
return new InstructionHeader
(addr, 1, new BinaryOperator
(types[0][(opcode - opc_iand)%2],
(opcode - opc_iand)/2 + Operator.AND_OP));
case opc_iinc: {
int local = stream.readUnsignedByte();
int value = stream.readByte();
int operation = Operator.ADD_OP;
if (value < 0) {
value = -value;
operation = Operator.NEG_OP;
}
return new InstructionHeader
(addr, 3, new IIncOperator
(local, Integer.toString(value),
operation + Operator.OPASSIGN_OP));
}
case opc_i2l: case opc_i2f: case opc_i2d:
case opc_l2i: case opc_l2f: case opc_l2d:
case opc_f2i: case opc_f2l: case opc_f2d:
case opc_d2i: case opc_d2l: case opc_d2f: {
int from = (opcode-opc_i2l)/3;
int to = (opcode-opc_i2l)%3;
if (to >= 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<dimension; i++)
baseType = baseType.getElementType();
return new InstructionHeader
(addr, 4,
new NewArrayOperator
(type, ca.env.getTypeString(baseType), dimension));
}
case opc_ifnull: case opc_ifnonnull:
return InstructionHeader.conditional
(addr, 3, addr+stream.readShort(),
new CompareUnaryOperator
(OBJECT_TYPE, opcode - opc_ifnull+Operator.COMPARE_OP));
case opc_goto_w:
return InstructionHeader.jump
(addr, 5, addr + stream.readInt(), new NopOperator());
case opc_jsr_w:
return InstructionHeader.jump
(addr, 5, addr+stream.readInt(), new JsrOperator());
default:
throw new ClassFormatError("Invalid opcode "+opcode);
}
} catch (ClassCastException ex) {
ex.printStackTrace();
throw new ClassFormatError("Constant has wrong type");
}
}
}

@ -30,10 +30,8 @@ public class ClassAnalyzer implements Analyzer {
}
for (f= cdef.getFirstField(); f != null; f = f.getNextField()) {
if (f.getType().getTypeCode() == Constants.TC_METHOD) {
System.err.println("analyzing method: "+f.getName());
fields[i] = new MethodAnalyzer(f, env);
} else {
System.err.println("analyzing field: "+f.getName());
fields[i] = new FieldAnalyzer(f, env);
}
fields[i++].analyze();
@ -48,7 +46,7 @@ public class ClassAnalyzer implements Analyzer {
if (modif.length() > 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());

File diff suppressed because it is too large Load Diff

@ -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(";");
}
}

@ -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());

@ -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. <p>
* 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);
}
}

@ -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);
}

@ -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<maxlocals; i++) {
if (reads[i] != null) {
reads[i] = reads[i].getLocalInfo();
if (prevReads[i] == null) {
changed = true;
} else if (prevReads[i].getLocalInfo() != reads[i]) {
prevReads[i].combineWith(reads[i]);
changed = true;
}
}
}
if (!changed)
continue;
}
if (!(instr instanceof MethodInstructionHeader)) {
if (instr.getInstruction() instanceof LocalVarOperator) {
LocalVarOperator op =
(LocalVarOperator)instr.getInstruction();
int slot = op.getSlot();
LocalInfo li = combine(slot, op.getLocalInfo(),
reads[slot]);
LocalInfo[] newReads = new LocalInfo[maxlocals];
System.arraycopy(reads, 0, newReads, 0, maxlocals);
op.setLocalInfo(li);
if (op.isRead())
newReads[slot] = li;
else
newReads[slot] = null;
reads = newReads;
}
predec = instr.getPredecessors().elements();
while (predec.hasMoreElements()) {
instrStack.push(predec.nextElement());
readsStack.push(reads);
}
}
done.put(instr, reads);
}
// System.err.println("");
reads = (LocalInfo[]) done.get(mih);
Type[] paramTypes = mdef.getType().getArgumentTypes();
int length = (mdef.isStatic() ? 0 : 1) + paramTypes.length;
argLocals = new LocalInfo[length];
int offset = 0;
if (!mdef.isStatic()) {
LocalInfo li = reads[0];
if (li == null)
li = new LocalInfo(0);
li.setName(Constants.idThis);
li.setType(mdef.getClassDefinition().getType());
argLocals[0] = li.getLocalInfo();
offset++;
}
for (int i=0; i< paramTypes.length; i++) {
LocalInfo li = reads[i+offset];
if (li == null)
li = new LocalInfo(i+offset);
li.setType(paramTypes[i]);
argLocals[offset+i] = li.getLocalInfo();
}
}
public void createLocalInfo(CodeAnalyzer code) {
// System.err.println("createLocalInfo");
MethodInstructionHeader mih = code.methodHeader;
if (lvt == null)
analyze(mih);
else {
int length = (mdef.isStatic() ? 0 : 1) +
mdef.getType().getArgumentTypes().length;
argLocals = new LocalInfo[length];
for (int i=0; i < length; i++)
argLocals[i] = lvt.getLocal(i).getInfo(-1);
for (InstructionHeader ih = mih.getNextInstruction();
ih != null; ih = ih.getNextInstruction()) {
if (ih.getInstruction() instanceof LocalVarOperator) {
LocalVarOperator op =
(LocalVarOperator)ih.getInstruction();
int slot = op.getSlot();
LocalInfo li = lvt.getLocal(slot).getInfo(ih.getAddress());
op.setLocalInfo(li);
}
}
}
}
public LocalInfo getLocal(int i) {
return argLocals[i];
}
public void dumpSource(TabbedPrintWriter writer)
throws java.io.IOException
{
Enumeration enum = locals.elements();
while (enum.hasMoreElements()) {
LocalInfo li = (LocalInfo) enum.nextElement();
if (!li.isShadow())
writer.println(env.getTypeString(li.getType(),
li.getName())+";");
}
}
}

@ -8,11 +8,12 @@ public class LocalVariableRangeList implements LocalVariable {
int length;
MyLocalInfo next;
MyLocalInfo(int s, int l, Identifier n, Type t) {
MyLocalInfo(int slot, int s, int l, Identifier n, Type t) {
super (slot);
start = s;
length = l;
name = n;
type = t;
setName(n);
setType(t);
next = null;
}
}
@ -45,7 +46,7 @@ public class LocalVariableRangeList implements LocalVariable {
while (li != null && addr > 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");
}
}

@ -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; i<count; i++) {
int start = stream.readUnsignedShort();
int start = stream.readUnsignedShort()-2; /*XXX*/
int length = stream.readUnsignedShort();
int name_i = stream.readUnsignedShort();
int desc_i = stream.readUnsignedShort();
int slot = stream.readUnsignedShort();
LocalVariableRangeList lv =
(LocalVariableRangeList)locals.elementAt(slot);
LocalVariableRangeList lv = locals[slot];
if (lv == null) {
lv = new LocalVariableRangeList(slot);
locals.setElementAt(lv, slot);
locals[slot] = lv;
}
lv.addLocal(start, length,
Identifier.lookup((String)
@ -42,14 +43,10 @@ public class LocalVariableTable {
readfromclass = true;
}
public LocalVariable getLocal(int slot)
throws ArrayOutOfBoundsException
public LocalVariableRangeList getLocal(int slot)
throws ArrayIndexOutOfBoundsException
{
LocalVariable lv = (LocalVariable)locals.elementAt(slot);
if (lv == null) {
lv = new LocalVariable(slot);
locals.setElementAt(lv, slot);
}
LocalVariableRangeList lv = locals[slot];
return lv;
}
}

@ -7,7 +7,7 @@ public class MethodAnalyzer implements Analyzer, Constants {
FieldDefinition mdef;
JodeEnvironment env;
CodeAnalyzer code = null;
LocalVariableTable lvt;
LocalVariableAnalyzer lva;
public MethodAnalyzer(FieldDefinition fd, JodeEnvironment e)
{
@ -19,60 +19,32 @@ public class MethodAnalyzer implements Analyzer, Constants {
new BinaryCode(bytecode,
env.getConstantPool(),
env);
lvt = new LocalVariableTable(bc.getMaxLocals());
readLVT(bc);
lva = new LocalVariableAnalyzer(env, mdef, bc.getMaxLocals());
lva.read(bc);
code = new CodeAnalyzer(this, bc, env);
}
}
public void readLVT(BinaryCode bc) {
BinaryAttribute attr = bc.getAttributes();
while (attr != null) {
if (attr.getName() == idLocalVariableTable) {
DataInputStream stream =
new DataInputStream
(new ByteArrayInputStream(attr.getData()));
try {
lvt.read(env, stream);
} catch (IOException ex) {
throw new ClassFormatError(ex.toString());
}
}
attr = attr.getNextAttribute();
}
if (!lvt.isReadFromClass()) {
int offset = 0;
if (!mdef.isStatic()) {
LocalInfo li = lvt.getLocal(0);
li.name = "this";
li.type = mdef.getClassDefinition().getType();
offset++;
}
Type[] paramTypes = mdef.getType().getArgumentTypes();
for (int i=0; i< paramTypes.length; i++) {
LocalInfo li = lvt.getLocal(offset+i);
li.type = paramTypes[i];
}
}
public int getParamCount() {
return (mdef.isStatic()?0:1)+
mdef.getType().getArgumentTypes().length;
}
public void analyze()
throws ClassFormatError
{
if (code == null)
return;
if (env.isVerbose)
System.err.print(mdef.getName().toString()+": locals ");
lva.createLocalInfo(code);
if (env.isVerbose) {
System.err.println("");
System.err.print("code ");
}
code.analyze();
}
public LocalVariable getLocal(int i) {
return lvt.getLocal(i);
}
public Identifier getLocalName(int i, int addr) {
Identifier name = lvt.getLocal(i).getName(addr);
if (name != null)
return name;
if (!mdef.isStatic() && i == 0)
return idThis;
return Identifier.lookup("local_"+i+"@"+addr);
if (env.isVerbose)
System.err.println("");
}
public void dumpSource(TabbedPrintWriter writer)
@ -88,17 +60,19 @@ public class MethodAnalyzer implements Analyzer, Constants {
if (mdef.isConstructor())
writer.print(mdef.getClassDeclaration().getName().toString());
else
writer.print(mdef.getType().getReturnType().toString()+" "+
mdef.getName().toString());
writer.print(env.getTypeString(mdef.getType().getReturnType())+
" "+ mdef.getName().toString());
writer.print("(");
Type[] paramTypes = mdef.getType().getArgumentTypes();
int offset = mdef.isStatic()?0:1;
for (int i=0; i<paramTypes.length; i++) {
if (i>0)
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("}");

@ -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);

@ -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";
}
}

@ -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]+"]";
}
}

@ -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]+"]";
}
}

@ -1,15 +1,18 @@
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);
}
}

@ -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];
}
}

@ -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];
}
}

@ -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];
}
}

@ -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];
}
}

@ -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");
}
}

@ -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;
}
}

@ -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();
}
}

@ -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)

@ -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];
}
}

@ -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;
}
}

@ -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 "\"\"";
}
}

@ -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<subExpressions.length; i++) {
expr[i] = subExpressions[i].
toString(ca, operator.getOperandPriority(i));
toString(operator.getOperandPriority(i));
}
String result = operator.toString(ca, expr);
String result = operator.toString(expr);
if (operator.getPriority() < minPriority) {
result = "("+result+")";
}
@ -93,36 +113,114 @@ public class Expression extends Instruction {
return result;
}
public boolean equals(Expression expr) {
if (this == expr)
public boolean equals(Object o) {
if (this == o)
return true;
if (!(o instanceof Expression))
return false;
Expression expr = (Expression) o;
if (!operator.equals(expr.operator) ||
subExpressions.length != expr.subExpressions.length)
return false;
for (int i=0; i<subExpressions.length; i++) {
if (subExpressions[i] != expr.subExpressions[i])
if (!subExpressions[i].equals(expr.subExpressions[i]))
return false;
}
return true;
}
public void dumpSource(TabbedPrintWriter writer, CodeAnalyzer ca)
throws java.io.IOException
{
if (writer.verbosity > 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;
}
}

@ -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;
}
}

@ -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;
}
}

@ -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];
}
}

@ -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;
}
}

@ -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();
}

@ -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 <em>count</em instructions.
*/
public void combine(int count, Instruction newInstr) {
InstructionHeader last = this;
this.instr = newInstr;
for (int i=1; i < count; i++) {
last = last.getSuccessors()[0];
length += last.length;
}
switchType = last.switchType;
cases = last.cases;
succs = last.succs;
successors = last.successors;
nextInstruction = last.nextInstruction;
for (int i=0; i< successors.length; i++) {
successors[i].predecessors.removeElement(last);
successors[i].predecessors.addElement(this);
}
}
/**
* This method replaces two conditional InstructionHeaders by a
* single one. You must make sure that this and the next instruction
* are both conditional Instructions and the destinations matches.
*
* @param newCondition the new instruction; this should be equivalent
* to the old two conditions.
*/
public void combineConditional(Instruction newCondition) {
nextInstruction.successors[0].predecessors.
removeElement(nextInstruction);
nextInstruction.successors[1].predecessors.
removeElement(nextInstruction);
instr = newCondition;
succs[0] = nextInstruction.succs[0]; // aid debugging
successors[0] = nextInstruction.successors[0];
if (successors[1] != nextInstruction.successors[1]) {
succs[1] = nextInstruction.succs[1]; // aid debugging
successors[1] = nextInstruction.successors[1];
successors[1].predecessors.addElement(this);
} else {
successors[0].predecessors.addElement(this);
}
length += nextInstruction.length; // aid debugging
nextInstruction = nextInstruction.nextInstruction;
}
}

@ -2,14 +2,16 @@ package jode;
import sun.tools.java.*;
public class InvokeOperator extends Operator {
CodeAnalyzer codeAnalyzer;
boolean staticFlag;
boolean specialFlag;
FieldDefinition field;
public InvokeOperator(int addr, int length,
public InvokeOperator(CodeAnalyzer codeAnalyzer,
boolean staticFlag, boolean specialFlag,
FieldDefinition field) {
super(addr,length, field.getType().getReturnType(), 0);
super(field.getType().getReturnType(), 0);
this.codeAnalyzer = codeAnalyzer;
this.staticFlag = staticFlag;
this.specialFlag = specialFlag;
this.field = field;
@ -40,10 +42,10 @@ public class InvokeOperator extends Operator {
public Type getOperandType(int i) {
if (!staticFlag) {
if (i == 0)
return field.getClassDeclaration().getType();
return MyType.tSubType(field.getClassDeclaration().getType());
i--;
}
return field.getType().getArgumentTypes()[i];
return MyType.tSubType(field.getType().getArgumentTypes()[i]);
}
public void setOperandType(Type types[]) {
@ -53,33 +55,33 @@ public class InvokeOperator extends Operator {
return field.isConstructor();
}
public String toString(CodeAnalyzer ca, String[] operands) {
public String toString(String[] operands) {
String object;
int arg = 0;
if (staticFlag) {
if (field.getClassDefinition() == ca.getClassDefinition())
if (field.getClassDefinition() == codeAnalyzer.getClassDefinition())
object = "";
else
object = ca.
object = codeAnalyzer.
getTypeString(field.getClassDeclaration().getType());
} else {
if (operands[arg].equals("this")) {
if (specialFlag &&
(field.getClassDeclaration() ==
ca.getClassDefinition().getSuperClass() ||
codeAnalyzer.getClassDefinition().getSuperClass() ||
(field.getClassDeclaration().getName() ==
Constants.idJavaLangObject &&
ca.getClassDefinition().getSuperClass() == null)))
codeAnalyzer.getClassDefinition().getSuperClass() == null)))
object = "super";
else if (specialFlag)
object = "(("+ca.getTypeString
object = "(("+codeAnalyzer.getTypeString
(field.getClassDeclaration().getType())+
") this)";
else
object = "";
} else {
if (specialFlag)
object = "(("+ca.getTypeString
object = "(("+codeAnalyzer.getTypeString
(field.getClassDeclaration().getType())+
") "+operands[arg]+")";
else
@ -107,4 +109,11 @@ public class InvokeOperator extends Operator {
}
return method+"("+params+")";
}
public boolean equals(Object o) {
return (o instanceof InvokeOperator) &&
((InvokeOperator)o).field == field &&
((InvokeOperator)o).staticFlag == staticFlag &&
((InvokeOperator)o).specialFlag == specialFlag;
}
}

@ -0,0 +1,55 @@
package jode;
/**
* This is an InstructionHeader for an JSR (jump subroutine) opcode.
* @author Jochen Hoenicke
*/
public class JsrInstructionHeader extends InstructionHeader {
int dest;
InstructionHeader destination;
/**
* Create an InstructionHeader for a conditional or unconditional
* Jsr.
* @param addr The address of this instruction.
* @param length The length of this instruction.
* @param dest The destination address of the Jsr.
* @param instr The undelying Instruction, the type of must be
* <ul><li> boolean for a conditional Jsr. </li>
* <li> void for an unconditional Jsr. </li></ul>
*/
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;
}
}

@ -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";
}
}

@ -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);
}
}

@ -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();
}
}

@ -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();
}
}

@ -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);
}

@ -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) {
}
}

@ -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];
}
}

@ -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];
}
}

@ -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("]");
}

@ -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;
}
}

@ -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() {

@ -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";
}
}

@ -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);
}
}

@ -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];
}
}

@ -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();
}
}

@ -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;
}
}

@ -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];
}
}

@ -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";
}
}

@ -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]);

@ -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]);
}
}

@ -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]);
}
}
}

@ -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()];
}
}

@ -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];
}
}

@ -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";
}
}

@ -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];
}
}

@ -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];
}
}

@ -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. <p>
*
* 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. <p>
*
* @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 <x, null>
// tUnknown, object <tObject, object>
// Fahrrad , Fahrzeug error
// Fahrzeug, Fahrrad <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);
/* <null, object> -> <tObject, object>
* 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
* <em>after</em> 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+">";
// }
}

@ -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. <p>
*
* The type tInt (which is the same as Type.tInt) is a good example
* for the implicit range &lt;tInt -- tBoolean&gt;. Most other
* standard types stand for the range consisting only of themselve.
* The explicit form is the class range type <p>
*
* The main operation on a type range is the intersection. To do this
* on class ranges we need two more operations: specialization and
* generalization. <p>
*
* specialization chooses the startpoint of two intervals which
* lies in the open range &lt;sp -- null&gt;, where sp is the startpoint
* of the other interval, or returns tError on failure.<p>
*
* generalization chooses the endpoint of two intervals which lies in
* the open range &lt;null -- ep&gt;, where ep is the endpoint of
* the other interval, or returns tError on failure.<p>
*/
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 &lt;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;
}
}

@ -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 "<superclass of "+
String.valueOf(elemType.typeString(string, flag1, flag2))+">";
}
}
Loading…
Cancel
Save