Get rid of sun.tools.* and use gnu.bytecode instead

git-svn-id: https://svn.code.sf.net/p/jode/code/trunk@53 379699f6-c40d-0410-875b-85095c16579e
stable
jochen 26 years ago
parent 94846b8034
commit 01aa264edd
  1. 9
      jode/jode/Decompiler.java
  2. 275
      jode/jode/bytecode/Opcodes.java
  3. 72
      jode/jode/bytecode/SearchPath.java
  4. 175
      jode/jode/decompiler/ClassAnalyzer.java
  5. 80
      jode/jode/decompiler/CodeAnalyzer.java
  6. 39
      jode/jode/decompiler/FieldAnalyzer.java
  7. 163
      jode/jode/decompiler/ImportHandler.java
  8. 13
      jode/jode/decompiler/LocalInfo.java
  9. 5
      jode/jode/decompiler/LocalVariableRangeList.java
  10. 67
      jode/jode/decompiler/LocalVariableTable.java
  11. 142
      jode/jode/decompiler/MethodAnalyzer.java
  12. 47
      jode/jode/expr/ComplexExpression.java
  13. 25
      jode/jode/expr/ConstOperator.java
  14. 20
      jode/jode/expr/ConstructorOperator.java
  15. 25
      jode/jode/expr/GetFieldOperator.java
  16. 107
      jode/jode/expr/InvokeOperator.java
  17. 19
      jode/jode/expr/NewArrayOperator.java
  18. 7
      jode/jode/expr/Operator.java
  19. 25
      jode/jode/expr/PutFieldOperator.java
  20. 6
      jode/jode/flow/CatchBlock.java
  21. 5
      jode/jode/type/ClassInterfacesType.java
  22. 65
      jode/jode/type/MethodType.java
  23. 31
      jode/jode/type/Type.java

@ -18,8 +18,6 @@
*/ */
package jode; package jode;
import sun.tools.java.*;
import java.lang.reflect.Modifier;
public class Decompiler { public class Decompiler {
public static boolean isVerbose = false; public static boolean isVerbose = false;
@ -29,6 +27,8 @@ public class Decompiler {
public static boolean debugInOut = false; public static boolean debugInOut = false;
public static boolean showLVT = false; public static boolean showLVT = false;
public static boolean doChecks = false; public static boolean doChecks = false;
public static int importPackageLimit = 3;
public static int importClassLimit = 3;
public static void main(String[] params) { public static void main(String[] params) {
JodeEnvironment env = new JodeEnvironment(); JodeEnvironment env = new JodeEnvironment();
@ -47,7 +47,10 @@ public class Decompiler {
showLVT = true; showLVT = true;
else if (params[i].equals("-check")) else if (params[i].equals("-check"))
doChecks = true; doChecks = true;
else else if (params[i].equals("-import")) {
importPackageLimit = Integer.parseInt(params[++i]);
importClassLimit = Integer.parseInt(params[++i]);
} else
env.doClass(params[i]); env.doClass(params[i]);
} }
} }

@ -20,13 +20,14 @@
package jode; package jode;
import jode.flow.*; import jode.flow.*;
import java.io.*; import java.io.*;
import sun.tools.java.*; import gnu.bytecode.CpoolRef;
import gnu.bytecode.CpoolClass;
/** /**
* This is an abstract class which creates flow blocks for the * This is an abstract class which creates flow blocks for the
* opcodes in a byte stream. * opcodes in a byte stream.
*/ */
public abstract class Opcodes implements RuntimeConstants { public abstract class Opcodes {
public final static Type ALL_INT_TYPE = Type.tUInt; public final static Type ALL_INT_TYPE = Type.tUInt;
public final static Type BOOL_INT_TYPE = Type.tBoolInt; public final static Type BOOL_INT_TYPE = Type.tBoolInt;
@ -42,6 +43,210 @@ public abstract class Opcodes implements RuntimeConstants {
public final static Type SHORT_TYPE = Type.tShort; public final static Type SHORT_TYPE = Type.tShort;
public final static Type VOID_TYPE = Type.tVoid; public final static Type VOID_TYPE = Type.tVoid;
public static final int opc_nop = 0;
public static final int opc_aconst_null = 1;
public static final int opc_iconst_m1 = 2;
public static final int opc_iconst_0 = 3;
public static final int opc_iconst_1 = 4;
public static final int opc_iconst_2 = 5;
public static final int opc_iconst_3 = 6;
public static final int opc_iconst_4 = 7;
public static final int opc_iconst_5 = 8;
public static final int opc_lconst_0 = 9;
public static final int opc_lconst_1 = 10;
public static final int opc_fconst_0 = 11;
public static final int opc_fconst_1 = 12;
public static final int opc_fconst_2 = 13;
public static final int opc_dconst_0 = 14;
public static final int opc_dconst_1 = 15;
public static final int opc_bipush = 16;
public static final int opc_sipush = 17;
public static final int opc_ldc = 18;
public static final int opc_ldc_w = 19;
public static final int opc_ldc2_w = 20;
public static final int opc_iload = 21;
public static final int opc_lload = 22;
public static final int opc_fload = 23;
public static final int opc_dload = 24;
public static final int opc_aload = 25;
public static final int opc_iload_0 = 26;
public static final int opc_iload_1 = 27;
public static final int opc_iload_2 = 28;
public static final int opc_iload_3 = 29;
public static final int opc_lload_0 = 30;
public static final int opc_lload_1 = 31;
public static final int opc_lload_2 = 32;
public static final int opc_lload_3 = 33;
public static final int opc_fload_0 = 34;
public static final int opc_fload_1 = 35;
public static final int opc_fload_2 = 36;
public static final int opc_fload_3 = 37;
public static final int opc_dload_0 = 38;
public static final int opc_dload_1 = 39;
public static final int opc_dload_2 = 40;
public static final int opc_dload_3 = 41;
public static final int opc_aload_0 = 42;
public static final int opc_aload_1 = 43;
public static final int opc_aload_2 = 44;
public static final int opc_aload_3 = 45;
public static final int opc_iaload = 46;
public static final int opc_laload = 47;
public static final int opc_faload = 48;
public static final int opc_daload = 49;
public static final int opc_aaload = 50;
public static final int opc_baload = 51;
public static final int opc_caload = 52;
public static final int opc_saload = 53;
public static final int opc_istore = 54;
public static final int opc_lstore = 55;
public static final int opc_fstore = 56;
public static final int opc_dstore = 57;
public static final int opc_astore = 58;
public static final int opc_istore_0 = 59;
public static final int opc_istore_1 = 60;
public static final int opc_istore_2 = 61;
public static final int opc_istore_3 = 62;
public static final int opc_lstore_0 = 63;
public static final int opc_lstore_1 = 64;
public static final int opc_lstore_2 = 65;
public static final int opc_lstore_3 = 66;
public static final int opc_fstore_0 = 67;
public static final int opc_fstore_1 = 68;
public static final int opc_fstore_2 = 69;
public static final int opc_fstore_3 = 70;
public static final int opc_dstore_0 = 71;
public static final int opc_dstore_1 = 72;
public static final int opc_dstore_2 = 73;
public static final int opc_dstore_3 = 74;
public static final int opc_astore_0 = 75;
public static final int opc_astore_1 = 76;
public static final int opc_astore_2 = 77;
public static final int opc_astore_3 = 78;
public static final int opc_iastore = 79;
public static final int opc_lastore = 80;
public static final int opc_fastore = 81;
public static final int opc_dastore = 82;
public static final int opc_aastore = 83;
public static final int opc_bastore = 84;
public static final int opc_castore = 85;
public static final int opc_sastore = 86;
public static final int opc_pop = 87;
public static final int opc_pop2 = 88;
public static final int opc_dup = 89;
public static final int opc_dup_x1 = 90;
public static final int opc_dup_x2 = 91;
public static final int opc_dup2 = 92;
public static final int opc_dup2_x1 = 93;
public static final int opc_dup2_x2 = 94;
public static final int opc_swap = 95;
public static final int opc_iadd = 96;
public static final int opc_ladd = 97;
public static final int opc_fadd = 98;
public static final int opc_dadd = 99;
public static final int opc_isub = 100;
public static final int opc_lsub = 101;
public static final int opc_fsub = 102;
public static final int opc_dsub = 103;
public static final int opc_imul = 104;
public static final int opc_lmul = 105;
public static final int opc_fmul = 106;
public static final int opc_dmul = 107;
public static final int opc_idiv = 108;
public static final int opc_ldiv = 109;
public static final int opc_fdiv = 110;
public static final int opc_ddiv = 111;
public static final int opc_irem = 112;
public static final int opc_lrem = 113;
public static final int opc_frem = 114;
public static final int opc_drem = 115;
public static final int opc_ineg = 116;
public static final int opc_lneg = 117;
public static final int opc_fneg = 118;
public static final int opc_dneg = 119;
public static final int opc_ishl = 120;
public static final int opc_lshl = 121;
public static final int opc_ishr = 122;
public static final int opc_lshr = 123;
public static final int opc_iushr = 124;
public static final int opc_lushr = 125;
public static final int opc_iand = 126;
public static final int opc_land = 127;
public static final int opc_ior = 128;
public static final int opc_lor = 129;
public static final int opc_ixor = 130;
public static final int opc_lxor = 131;
public static final int opc_iinc = 132;
public static final int opc_i2l = 133;
public static final int opc_i2f = 134;
public static final int opc_i2d = 135;
public static final int opc_l2i = 136;
public static final int opc_l2f = 137;
public static final int opc_l2d = 138;
public static final int opc_f2i = 139;
public static final int opc_f2l = 140;
public static final int opc_f2d = 141;
public static final int opc_d2i = 142;
public static final int opc_d2l = 143;
public static final int opc_d2f = 144;
public static final int opc_i2b = 145;
public static final int opc_i2c = 146;
public static final int opc_i2s = 147;
public static final int opc_lcmp = 148;
public static final int opc_fcmpl = 149;
public static final int opc_fcmpg = 150;
public static final int opc_dcmpl = 151;
public static final int opc_dcmpg = 152;
public static final int opc_ifeq = 153;
public static final int opc_ifne = 154;
public static final int opc_iflt = 155;
public static final int opc_ifge = 156;
public static final int opc_ifgt = 157;
public static final int opc_ifle = 158;
public static final int opc_if_icmpeq = 159;
public static final int opc_if_icmpne = 160;
public static final int opc_if_icmplt = 161;
public static final int opc_if_icmpge = 162;
public static final int opc_if_icmpgt = 163;
public static final int opc_if_icmple = 164;
public static final int opc_if_acmpeq = 165;
public static final int opc_if_acmpne = 166;
public static final int opc_goto = 167;
public static final int opc_jsr = 168;
public static final int opc_ret = 169;
public static final int opc_tableswitch = 170;
public static final int opc_lookupswitch = 171;
public static final int opc_ireturn = 172;
public static final int opc_lreturn = 173;
public static final int opc_freturn = 174;
public static final int opc_dreturn = 175;
public static final int opc_areturn = 176;
public static final int opc_return = 177;
public static final int opc_getstatic = 178;
public static final int opc_putstatic = 179;
public static final int opc_getfield = 180;
public static final int opc_putfield = 181;
public static final int opc_invokevirtual = 182;
public static final int opc_invokespecial = 183;
public static final int opc_invokestatic = 184;
public static final int opc_invokeinterface = 185;
public static final int opc_xxxunusedxxx = 186;
public static final int opc_new = 187;
public static final int opc_newarray = 188;
public static final int opc_anewarray = 189;
public static final int opc_arraylength = 190;
public static final int opc_athrow = 191;
public static final int opc_checkcast = 192;
public static final int opc_instanceof = 193;
public static final int opc_monitorenter = 194;
public static final int opc_monitorexit = 195;
public static final int opc_wide = 196;
public static final int opc_multianewarray = 197;
public static final int opc_ifnull = 198;
public static final int opc_ifnonnull = 199;
public static final int opc_goto_w = 200;
public static final int opc_jsr_w = 201;
public static final int opc_breakpoint = 202;
public final static Type types[][] = { public final static Type types[][] = {
{BOOL_INT_TYPE, LONG_TYPE, FLOAT_TYPE, DOUBLE_TYPE, OBJECT_TYPE }, {BOOL_INT_TYPE, LONG_TYPE, FLOAT_TYPE, DOUBLE_TYPE, OBJECT_TYPE },
@ -173,16 +378,16 @@ public abstract class Opcodes implements RuntimeConstants {
int index = stream.readUnsignedByte(); int index = stream.readUnsignedByte();
return createNormal return createNormal
(ca, addr, 2, new ConstOperator (ca, addr, 2, new ConstOperator
(ca.env.getConstantType(index), (ca.method.classAnalyzer.getConstantType(index),
ca.env.getConstant(index).toString())); ca.method.classAnalyzer.getConstantString(index)));
} }
case opc_ldc_w: case opc_ldc_w:
case opc_ldc2_w: { case opc_ldc2_w: {
int index = stream.readUnsignedShort(); int index = stream.readUnsignedShort();
return createNormal return createNormal
(ca, addr, 3, new ConstOperator (ca, addr, 3, new ConstOperator
(ca.env.getConstantType(index), (ca.method.classAnalyzer.getConstantType(index),
ca.env.getConstant(index).toString())); ca.method.classAnalyzer.getConstantString(index)));
} }
case opc_iload: case opc_lload: case opc_iload: case opc_lload:
case opc_fload: case opc_dload: case opc_aload: case opc_fload: case opc_dload: case opc_aload:
@ -381,9 +586,7 @@ public abstract class Opcodes implements RuntimeConstants {
} }
case opc_ireturn: case opc_lreturn: case opc_ireturn: case opc_lreturn:
case opc_freturn: case opc_dreturn: case opc_areturn: { case opc_freturn: case opc_dreturn: case opc_areturn: {
Type retType = Type retType = Type.tSubType(ca.getMethod().getReturnType());
Type.tSubType(Type.tType(ca.getMethod().mdef.getType()
.getReturnType()));
return createBlock return createBlock
(ca, addr, 1, new ReturnBlock(new NopOperator(retType))); (ca, addr, 1, new ReturnBlock(new NopOperator(retType)));
} }
@ -396,14 +599,14 @@ public abstract class Opcodes implements RuntimeConstants {
return createNormal return createNormal
(ca, addr, 3, new GetFieldOperator (ca, addr, 3, new GetFieldOperator
(ca, opcode == opc_getstatic, (ca, opcode == opc_getstatic,
(FieldDefinition)ca.env.getConstant (CpoolRef)ca.method.classAnalyzer.getConstant
(stream.readUnsignedShort()))); (stream.readUnsignedShort())));
case opc_putstatic: case opc_putstatic:
case opc_putfield: case opc_putfield:
return createNormal return createNormal
(ca, addr, 3, new PutFieldOperator (ca, addr, 3, new PutFieldOperator
(ca, opcode == opc_putstatic, (ca, opcode == opc_putstatic,
(FieldDefinition)ca.env.getConstant (CpoolRef)ca.method.classAnalyzer.getConstant
(stream.readUnsignedShort()))); (stream.readUnsignedShort())));
case opc_invokevirtual: case opc_invokevirtual:
case opc_invokespecial: case opc_invokespecial:
@ -412,23 +615,23 @@ public abstract class Opcodes implements RuntimeConstants {
(ca, addr, 3, new InvokeOperator (ca, addr, 3, new InvokeOperator
(ca, (ca,
opcode == opc_invokestatic, opcode == opc_invokespecial, opcode == opc_invokestatic, opcode == opc_invokespecial,
(FieldDefinition)ca.env.getConstant (CpoolRef)ca.method.classAnalyzer.getConstant
(stream.readUnsignedShort()))); (stream.readUnsignedShort())));
case opc_invokeinterface: { case opc_invokeinterface: {
FlowBlock fb = createNormal FlowBlock fb = createNormal
(ca, addr, 5, new InvokeOperator (ca, addr, 5, new InvokeOperator
(ca, false, false, (ca, false, false,
(FieldDefinition)ca.env.getConstant (CpoolRef)ca.method.classAnalyzer.getConstant
(stream.readUnsignedShort()))); (stream.readUnsignedShort())));
int reserved = stream.readUnsignedShort(); int reserved = stream.readUnsignedShort();
return fb; return fb;
} }
case opc_new: { case opc_new: {
ClassDeclaration cldec = (ClassDeclaration) CpoolClass cpcls = (CpoolClass)
ca.env.getConstant(stream.readUnsignedShort()); ca.method.classAnalyzer.getConstant(stream.readUnsignedShort());
Type type = Type.tClassOrArray(cldec.getName()); Type type = Type.tClassOrArray(cpcls.getName().getString());
return createNormal return createNormal
(ca, addr, 3, new NewOperator(type, ca.env.getTypeString(type))); (ca, addr, 3, new NewOperator(type, type.toString()));
} }
case opc_newarray: { case opc_newarray: {
Type type; Type type;
@ -445,18 +648,15 @@ public abstract class Opcodes implements RuntimeConstants {
throw new ClassFormatError("Invalid newarray operand"); throw new ClassFormatError("Invalid newarray operand");
} }
return createNormal return createNormal
(ca, addr, 2, (ca, addr, 2, new NewArrayOperator(Type.tArray(type), 1));
new NewArrayOperator(Type.tArray(type),
type.toString(), 1));
} }
case opc_anewarray: { case opc_anewarray: {
ClassDeclaration cldec = (ClassDeclaration) ca.env.getConstant CpoolClass cpcls = (CpoolClass)
ca.method.classAnalyzer.getConstant
(stream.readUnsignedShort()); (stream.readUnsignedShort());
Identifier ident = cldec.getName(); Type type = Type.tClassOrArray(cpcls.getName().getString());
Type type = Type.tClassOrArray(cldec.getName());
return createNormal return createNormal
(ca, addr, 3, new NewArrayOperator (ca, addr, 3, new NewArrayOperator(Type.tArray(type), 1));
(Type.tArray(type), ca.env.getTypeString(type),1));
} }
case opc_arraylength: case opc_arraylength:
return createNormal return createNormal
@ -466,20 +666,22 @@ public abstract class Opcodes implements RuntimeConstants {
(ca, addr, 1, (ca, addr, 1,
new ThrowBlock(new NopOperator(Type.tUObject))); new ThrowBlock(new NopOperator(Type.tUObject)));
case opc_checkcast: { case opc_checkcast: {
ClassDeclaration cldec = (ClassDeclaration) ca.env.getConstant CpoolClass cpcls = (CpoolClass)
ca.method.classAnalyzer.getConstant
(stream.readUnsignedShort()); (stream.readUnsignedShort());
Type type = Type.tClassOrArray(cldec.getName()); Type type = Type.tClassOrArray(cpcls.getName().getString());
return createNormal return createNormal
(ca, addr, 3, new CheckCastOperator (ca, addr, 3, new CheckCastOperator
(type, ca.env.getTypeString(type))); (type, type.toString()));
} }
case opc_instanceof: { case opc_instanceof: {
ClassDeclaration cldec = (ClassDeclaration) ca.env.getConstant CpoolClass cpcls = (CpoolClass)
ca.method.classAnalyzer.getConstant
(stream.readUnsignedShort()); (stream.readUnsignedShort());
Type type = Type.tClassOrArray(cldec.getName()); Type type = Type.tClassOrArray(cpcls.getName().getString());
return createNormal return createNormal
(ca, addr, 3, (ca, addr, 3,
new InstanceOfOperator(type, ca.env.getTypeString(type))); new InstanceOfOperator(type, type.toString()));
} }
case opc_monitorenter: case opc_monitorenter:
return createNormal(ca, addr, 1, return createNormal(ca, addr, 1,
@ -528,17 +730,14 @@ public abstract class Opcodes implements RuntimeConstants {
} }
} }
case opc_multianewarray: { case opc_multianewarray: {
ClassDeclaration cldec = (ClassDeclaration) ca.env.getConstant CpoolClass cpcls = (CpoolClass)
ca.method.classAnalyzer.getConstant
(stream.readUnsignedShort()); (stream.readUnsignedShort());
Type type = Type.tClassOrArray(cldec.getName()); Type type = Type.tClassOrArray(cpcls.getName().getString());
int dimension = stream.readUnsignedByte(); int dimension = stream.readUnsignedByte();
Type baseType = type;
for (int i=0; i<dimension; i++)
baseType = ((ArrayType)baseType).getElementType();
return createNormal return createNormal
(ca, addr, 4, (ca, addr, 4,
new NewArrayOperator new NewArrayOperator(type, dimension));
(type, ca.env.getTypeString(baseType), dimension));
} }
case opc_ifnull: case opc_ifnonnull: case opc_ifnull: case opc_ifnonnull:
return createIfGoto return createIfGoto

@ -0,0 +1,72 @@
/* SearchPath - Copyright (C) 1997-1998 Jochen Hoenicke.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id$
*/
package jode;
import java.io.*;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import java.util.StringTokenizer;
/**
* This class represents a path of multiple directories and/or zip files,
* where we can search for file names.
*
* @author Jochen Hoenicke
*/
public class SearchPath {
File[] dirs;
ZipFile[] zips;
public SearchPath(String path) {
StringTokenizer tokenizer =
new StringTokenizer(path, File.pathSeparator);
int length = tokenizer.countTokens();
dirs = new File[length];
zips = new ZipFile[length];
for (int i=0; i< length; i++) {
dirs[i] = new File(tokenizer.nextToken());
if (!dirs[i].isDirectory()) {
try {
zips[i] = new ZipFile(dirs[i]);
} catch (java.io.IOException ex) {
/* disable this entry */
dirs[i] = null;
}
}
}
}
public InputStream getFile(String filename) throws IOException {
for (int i=0; i<dirs.length; i++) {
if (dirs[i] == null)
continue;
if (zips[i] != null) {
ZipEntry ze = zips[i].getEntry(filename);
if (ze != null)
return zips[i].getInputStream(ze);
} else {
File f = new File(dirs[i], filename);
if (f.exists())
return new FileInputStream(f);
}
}
throw new FileNotFoundException(filename);
}
}

@ -18,70 +18,90 @@
*/ */
package jode; package jode;
import java.lang.reflect.Modifier;
import java.io.IOException; import java.io.IOException;
import sun.tools.java.*; import java.lang.reflect.*;
import gnu.bytecode.ClassType;
import gnu.bytecode.ConstantPool;
import gnu.bytecode.CpoolEntry;
import gnu.bytecode.CpoolString;
import gnu.bytecode.CpoolValue1;
import gnu.bytecode.CpoolValue2;
public class ClassAnalyzer implements Analyzer { public class ClassAnalyzer implements Analyzer {
BinaryClass cdef;
JodeEnvironment env; JodeEnvironment env;
Analyzer fields[]; Analyzer analyzers[];
Class clazz;
ClassType classType;
ClassAnalyzer parent;
public ClassAnalyzer(BinaryClass bc, JodeEnvironment e) public ClassAnalyzer(ClassAnalyzer parent, Class clazz,
JodeEnvironment env)
{ {
cdef = bc; this.parent = parent;
env = e; this.clazz = clazz;
this.env = env;
try {
this.classType = gnu.bytecode.ClassFileInput.
readClassType(env.getClassStream(clazz));
} catch (java.io.IOException ex) {
ex.printStackTrace();
}
} }
public void analyze() { public void analyze() {
int numFields = 0, i=0; int numFields = 0, i=0;
FieldDefinition f; Field[] fields = clazz.getDeclaredFields();
for (f= cdef.getInnerClassField(); f != null; f = f.getNextField()) Method[] methods = clazz.getDeclaredMethods();
numFields++; Constructor[] constrs = clazz.getDeclaredConstructors();
for (f= cdef.getFirstField(); f != null; f = f.getNextField()) Class[] clazzes = clazz.getDeclaredClasses();
numFields++;
fields = new Analyzer[numFields]; analyzers = new Analyzer[fields.length + methods.length
for (f= cdef.getInnerClassField(); f != null; f = f.getNextField()) { + constrs.length + clazzes.length];
System.err.println("analyzing inner: "+f.getName());
fields[i] = new ClassAnalyzer((BinaryClass) f.getInnerClass(), env); for (int j=0; j< clazzes.length; j++, i++) {
fields[i++].analyze(); analyzers[i] = new ClassAnalyzer(this, clazzes[j], env);
analyzers[i].analyze();
} }
for (f= cdef.getFirstField(); f != null; f = f.getNextField()) {
if (f.getType().getTypeCode() == Constants.TC_METHOD) { for (int j=0; j< fields.length; j++, i++) {
fields[i] = new MethodAnalyzer(f, env); analyzers[i] = new FieldAnalyzer(this, fields[j], env);
} else { analyzers[i].analyze();
fields[i] = new FieldAnalyzer(f, env); }
}
fields[i++].analyze(); for (int j=0; j< constrs.length; j++, i++) {
analyzers[i] = new MethodAnalyzer(this, constrs[j], env);
analyzers[i].analyze();
}
for (int j=0; j< methods.length; j++, i++) {
analyzers[i] = new MethodAnalyzer(this, methods[j], env);
analyzers[i].analyze();
} }
} }
public void dumpSource(TabbedPrintWriter writer) throws IOException public void dumpSource(TabbedPrintWriter writer) throws IOException
{ {
if (cdef.getSource() != null) // if (cdef.getSource() != null)
writer.println("/* Original source: "+cdef.getSource()+" */"); // writer.println("/* Original source: "+cdef.getSource()+" */");
if (cdef.getName().isQualified()) String modif = Modifier.toString(clazz.getModifiers());
writer.println("package " + cdef.getName().getQualifier() + ";");
/* XXX imports */
writer.println("");
String modif = Modifier.toString(cdef.getModifiers());
if (modif.length() > 0) if (modif.length() > 0)
writer.print(modif + " "); writer.print(modif + " ");
writer.print((cdef.isInterface())?"interface ":"class "); writer.print((clazz.isInterface())?"interface ":"class ");
writer.println(cdef.getName().getName().toString()); writer.println(env.classString(clazz));
writer.tab(); writer.tab();
if (cdef.getSuperClass() != null) Class superClazz = clazz.getSuperclass();
writer.println("extends "+cdef.getSuperClass().getName().toString()); if (superClazz != null &&
ClassDeclaration interfaces[] = cdef.getInterfaces(); superClazz != new Object().getClass()) {
writer.println("extends "+env.classString(superClazz));
}
Class interfaces[] = clazz.getInterfaces();
if (interfaces.length > 0) { if (interfaces.length > 0) {
writer.print("implements "); writer.print("implements ");
for (int i=0; i < interfaces.length; i++) { for (int i=0; i < interfaces.length; i++) {
if (i > 0) if (i > 0)
writer.print(", "); writer.print(", ");
writer.print(interfaces[i].getName().toString()); writer.print(env.classString(interfaces[i]));
} }
writer.println(""); writer.println("");
} }
@ -89,11 +109,86 @@ public class ClassAnalyzer implements Analyzer {
writer.println("{"); writer.println("{");
writer.tab(); writer.tab();
for (int i=0; i< fields.length; i++) for (int i=0; i< analyzers.length; i++)
fields[i].dumpSource(writer); analyzers[i].dumpSource(writer);
writer.untab(); writer.untab();
writer.println("}"); writer.println("}");
} }
public ConstantPool getConstantPool() {
return classType.getConstants();
}
public CpoolEntry getConstant(int i) {
return classType.getConstant(i);
}
public Type getConstantType(int i)
throws ClassFormatError
{
int t = classType.getConstant(i).getTag();
switch(t) {
case ConstantPool.INTEGER: return Type.tInt ;
case ConstantPool.FLOAT : return Type.tFloat ;
case ConstantPool.LONG : return Type.tLong ;
case ConstantPool.DOUBLE : return Type.tDouble;
case ConstantPool.STRING : return Type.tString;
default:
throw new ClassFormatError("invalid constant type: "+t);
}
}
private static String quoted(String str) {
StringBuffer result = new StringBuffer("\"");
for (int i=0; i< str.length(); i++) {
switch (str.charAt(i)) {
case '\t':
result.append("\\t");
break;
case '\n':
result.append("\\n");
break;
case '\\':
result.append("\\\\");
break;
case '\"':
result.append("\\\"");
break;
default:
result.append(str.charAt(i));
}
}
return result.append("\"").toString();
}
public String getConstantString(int i)
{
CpoolEntry constant = classType.getConstant(i);
switch (constant.getTag()) {
case ConstantPool.INTEGER:
return Integer.toString(((CpoolValue1)constant).getValue());
case ConstantPool.FLOAT:
return Float.toString
(Float.intBitsToFloat(((CpoolValue1)constant).getValue()));
case ConstantPool.LONG:
return Long.toString(((CpoolValue2)constant).getValue());
case ConstantPool.DOUBLE:
return Double.toString
(Double.longBitsToDouble(((CpoolValue2)constant).getValue()));
case ConstantPool.STRING:
return quoted(((CpoolString)constant).getString().getString());
}
throw new AssertError("unknown constant type");
}
public String getTypeString(Type type) {
return type.toString();
}
public String getTypeString(Type type, String name) {
return type.toString() + " " + name;
}
} }

@ -18,18 +18,23 @@
*/ */
package jode; package jode;
import sun.tools.java.*;
import java.util.Stack;
import java.io.*;
import jode.flow.FlowBlock; import jode.flow.FlowBlock;
import jode.flow.Jump; import jode.flow.Jump;
import jode.flow.StructuredBlock; import jode.flow.StructuredBlock;
import jode.flow.RawTryCatchBlock; import jode.flow.RawTryCatchBlock;
public class CodeAnalyzer implements Analyzer, Constants { import java.util.Stack;
import java.io.DataInputStream;
BinaryCode bincode; import java.io.ByteArrayInputStream;
import java.io.IOException;
import gnu.bytecode.CodeAttr;
import gnu.bytecode.Attribute;
import gnu.bytecode.LocalVarsAttr;
import gnu.bytecode.CpoolClass;
public class CodeAnalyzer implements Analyzer {
FlowBlock methodHeader; FlowBlock methodHeader;
MethodAnalyzer method; MethodAnalyzer method;
public JodeEnvironment env; public JodeEnvironment env;
@ -43,25 +48,15 @@ public class CodeAnalyzer implements Analyzer, Constants {
*/ */
public MethodAnalyzer getMethod() {return method;} public MethodAnalyzer getMethod() {return method;}
void readCode() void readCode(CodeAttr bincode)
throws ClassFormatError throws ClassFormatError
{ {
BinaryAttribute attr = bincode.getAttributes(); LocalVarsAttr attr =
while (attr != null) { (LocalVarsAttr) Attribute.get(bincode, "LocalVariableTable");
if (attr.getName() == Constants.idLocalVariableTable) { if (attr != null)
DataInputStream stream = lvt = new LocalVariableTable(bincode.getMaxLocals(),
new DataInputStream method.classAnalyzer, attr);
(new ByteArrayInputStream(attr.getData()));
try {
lvt = new LocalVariableTable(bincode.getMaxLocals());
lvt.read(env, stream);
} catch (IOException ex) {
throw new ClassFormatError(ex.toString());
}
}
attr = attr.getNextAttribute();
}
byte[] code = bincode.getCode(); byte[] code = bincode.getCode();
FlowBlock[] instr = new FlowBlock[code.length]; FlowBlock[] instr = new FlowBlock[code.length];
@ -84,27 +79,30 @@ public class CodeAnalyzer implements Analyzer, Constants {
methodHeader = instr[0]; methodHeader = instr[0];
methodHeader.makeStartBlock(); methodHeader.makeStartBlock();
BinaryExceptionHandler[] handlers = bincode.getExceptionHandlers(); short[] handlers = gnu.bytecode.Spy.getExceptionHandlers(bincode);
for (int i=0; i<handlers.length; i++) { for (int i=0; i<handlers.length; i += 4) {
StructuredBlock tryBlock = instr[handlers[i].startPC].getBlock(); StructuredBlock tryBlock = instr[handlers[i + 0]].getBlock();
while (tryBlock instanceof RawTryCatchBlock while (tryBlock instanceof RawTryCatchBlock
&& (((RawTryCatchBlock) tryBlock).getCatchAddr() && (((RawTryCatchBlock) tryBlock).getCatchAddr()
> handlers[i].handlerPC)) { > handlers[i + 2])) {
tryBlock = ((RawTryCatchBlock)tryBlock).getTryBlock(); tryBlock = ((RawTryCatchBlock)tryBlock).getTryBlock();
} }
Type type = Type type = null;
(handlers[i].exceptionClass != null)?
Type.tClass(handlers[i].exceptionClass.getName().toString()) : null; if (handlers[i + 3 ] != 0) {
CpoolClass cpcls = (CpoolClass)
method.classAnalyzer.getConstant(handlers[i + 3]);
type = Type.tClass(cpcls.getName().getString());
}
new RawTryCatchBlock(type, tryBlock, new RawTryCatchBlock(type, tryBlock,
new Jump(instr[handlers[i].endPC]), new Jump(instr[handlers[i + 1]]),
new Jump(instr[handlers[i].handlerPC])); new Jump(instr[handlers[i + 2]]));
} }
int paramCount = method.mdef.getType().getArgumentTypes().length int paramCount = method.getParamCount();
+ (method.mdef.isStatic() ? 0 : 1);
param = new jode.flow.VariableSet(); param = new jode.flow.VariableSet();
for (int i=0; i<paramCount; i++) for (int i=0; i<paramCount; i++)
param.addElement(getLocalInfo(0, i)); param.addElement(getLocalInfo(0, i));
@ -117,13 +115,12 @@ public class CodeAnalyzer implements Analyzer, Constants {
methodHeader.dumpSource(writer); methodHeader.dumpSource(writer);
} }
public CodeAnalyzer(MethodAnalyzer ma, BinaryCode bc, JodeEnvironment e) public CodeAnalyzer(MethodAnalyzer ma, CodeAttr bc, JodeEnvironment e)
throws ClassFormatError throws ClassFormatError
{ {
method = ma; method = ma;
env = e; env = e;
bincode = bc; readCode(bc);
readCode();
} }
public LocalInfo getLocalInfo(int addr, int slot) { public LocalInfo getLocalInfo(int addr, int slot) {
@ -142,12 +139,17 @@ public class CodeAnalyzer implements Analyzer, Constants {
methodHeader.analyze(); methodHeader.analyze();
} }
public void useClass(Class clazz)
{
env.useClass(clazz);
}
public String getTypeString(Type type) { public String getTypeString(Type type) {
return env.getTypeString(type); return method.classAnalyzer.getTypeString(type);
} }
public ClassDefinition getClassDefinition() { public Class getClazz() {
return env.getClassDefinition(); return method.classAnalyzer.clazz;
} }
} }

@ -18,23 +18,35 @@
*/ */
package jode; package jode;
import sun.tools.java.*; import java.lang.reflect.*;
import java.lang.reflect.Modifier; import gnu.bytecode.Attribute;
import gnu.bytecode.MiscAttr;
public class FieldAnalyzer implements Analyzer { public class FieldAnalyzer implements Analyzer {
FieldDefinition fdef; ClassAnalyzer clazz;
int constantValue;
Field field;
JodeEnvironment env; JodeEnvironment env;
public FieldAnalyzer(FieldDefinition fd, JodeEnvironment e) public FieldAnalyzer(ClassAnalyzer cla, Field fd, JodeEnvironment e)
{ {
fdef = fd; clazz = cla;
field = fd;
env = e; env = e;
} }
public void analyze() { public void analyze() {
constantValue = 0;
Attribute attribute =
Attribute.get(clazz.classType.getField(field.getName()),
"ConstantValue");
if (attribute != null) {
byte[] data = gnu.bytecode.Spy.getAttribute((MiscAttr)attribute);
constantValue = (unsigned(data[0]) << 8) | unsigned(data[1]);
}
} }
public int unsigned(byte value) { private final int unsigned(byte value) {
if (value < 0) if (value < 0)
return value + 256; return value + 256;
else else
@ -44,20 +56,15 @@ public class FieldAnalyzer implements Analyzer {
public void dumpSource(TabbedPrintWriter writer) public void dumpSource(TabbedPrintWriter writer)
throws java.io.IOException throws java.io.IOException
{ {
String modif = Modifier.toString(fdef.getModifiers()); String modif = Modifier.toString(field.getModifiers());
if (modif.length() > 0) if (modif.length() > 0)
writer.print(modif+" "); writer.print(modif+" ");
writer.print(env.getTypeString(Type.tType(fdef.getType()), writer.print(Type.tType(field.getType()).toString()
fdef.getName())); + " " + field.getName());
byte[] attrib = if (constantValue != 0) {
((BinaryField) fdef).getAttribute(Constants.idConstantValue); writer.print(" = "+clazz.getConstantString(constantValue));
if (attrib != null) {
int index = (unsigned(attrib[0]) << 8) | unsigned(attrib[1]);
writer.print(" = "+env.getConstant(index).toString());
} }
writer.println(";"); writer.println(";");
} }
} }

@ -18,72 +18,45 @@
*/ */
package jode; package jode;
import sun.tools.java.*;
import sun.tools.util.*;
import java.util.*; import java.util.*;
public class JodeEnvironment extends LoadEnvironment { public class JodeEnvironment {
Hashtable imports = new Hashtable(); Hashtable imports = new Hashtable();
BinaryClass main; ClassAnalyzer main;
Identifier pkg; String className;
String pkg;
SearchPath classPath;
JodeEnvironment() { JodeEnvironment() {
super(null);
Type.setEnvironment(this); Type.setEnvironment(this);
path = new ClassPath(System.getProperty("java.class.path")); classPath = new SearchPath(System.getProperty("java.class.path"));
}
public BinaryConstantPool getConstantPool() {
return main.getConstants();
}
public Object getConstant(int i) {
return main.getConstants().getConstant(i, this);
}
public Type getConstantType(int i)
throws ClassFormatError
{
int t = main.getConstants().getConstantType(i);
switch(t) {
case 3: return Type.tInt ;
case 4: return Type.tFloat ;
case 5: return Type.tLong ;
case 6: return Type.tDouble;
case 8: return Type.tString;
default:
throw new ClassFormatError("invalid constant type: "+t);
}
}
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.toString() + " " + name.toString();
} }
public ClassDefinition getClassDefinition() { public java.io.InputStream getClassStream(Class clazz)
return main; throws java.io.IOException {
return classPath.getFile(clazz.getName().
replace('.', java.io.File.separatorChar)
+".class");
} }
public void dumpHeader(TabbedPrintWriter writer) public void dumpHeader(TabbedPrintWriter writer)
throws java.io.IOException throws java.io.IOException
{ {
writer.println("/* Decompiled by JoDe (Jochen's Decompiler) */"); writer.println("/* "+ className + " - Decompiled by JoDe (Jochen's Decompiler)\n * Send comments or bug reports to Jochen Hoenicke <jochenh@bigfoot.com>\n */");
if (pkg != null && pkg != Constants.idNull) if (pkg.length() != 0)
writer.println("package "+pkg+";"); writer.println("package "+pkg+";");
Enumeration enum = imports.keys(); Enumeration enum = imports.keys();
while (enum.hasMoreElements()) { while (enum.hasMoreElements()) {
Identifier packageName = (Identifier) enum.nextElement(); String importName = (String) enum.nextElement();
Integer vote = (Integer) imports.get(packageName); Integer vote = (Integer) imports.get(importName);
if (vote.intValue() > 3) if (vote.intValue() >=
writer.println("import "+packageName+";"); (importName.endsWith(".*")
? Decompiler.importPackageLimit
: Decompiler.importClassLimit))
writer.println("import "+importName+";");
} }
writer.println(""); writer.println("");
} }
@ -94,25 +67,85 @@ public class JodeEnvironment extends LoadEnvironment {
public void doClass(String className) public void doClass(String className)
{ {
Class clazz;
try { try {
Identifier ident = Identifier.lookup(className); clazz = Class.forName(className);
error(ident.toString()); } catch (ClassNotFoundException ex) {
if (!classExists(ident)) { System.err.println("Class `"+className+"' not found");
error("`"+ident+"' not found"); return;
} catch (IllegalArgumentException ex) {
System.err.println("`"+className+"' is not a class name");
return;
}
System.err.println(className);
int pkgdelim = className.lastIndexOf('.');
pkg = (pkgdelim == -1)? "" : className.substring(0, pkgdelim);
this.className = (pkgdelim == -1) ? className
: className.substring(pkgdelim+1);
main = new ClassAnalyzer(null, clazz, this);
main.analyze();
TabbedPrintWriter writer =
new TabbedPrintWriter(System.out, " ");
try {
dumpHeader(writer);
main.dumpSource(writer);
} catch (java.io.IOException e) {
e.printStackTrace();
}
}
/* Marks the clazz as used, so that it will be imported if used often
* enough.
*/
public void useClass(Class clazz) {
String name = clazz.getName();
int pkgdelim = name.lastIndexOf('.');
if (pkgdelim != -1) {
String pkgName = name.substring(0, pkgdelim);
if (pkgName.equals(pkg)
|| pkgName.equals("java.lang"))
return;
Integer i = (Integer) imports.get(pkgName+".*");
i = (i == null)? new Integer(1): new Integer(i.intValue()+1);
imports.put(pkgName+".*", i);
if (i.intValue() >= Decompiler.importPackageLimit)
return; return;
i = (Integer) imports.get(name);
i = (i == null)? new Integer(1): new Integer(i.intValue()+1);
imports.put(name, i);
}
}
/**
* Check if clazz is imported and maybe remove package delimiter from
* full qualified class name.
* <p>
* Known Bug: If the same class name is in more than one imported package
* the name should be qualified, but isn't.
* @return a legal string representation of clazz.
*/
public String classString(Class clazz) {
String name = clazz.getName();
int pkgdelim = name.lastIndexOf('.');
if (pkgdelim != -1) {
String pkgName = name.substring(0, pkgdelim);
Integer i;
if (pkgName.equals(pkg)
|| pkgName.equals("java.lang")
|| ( (i = (Integer)imports.get(pkgName+".*")) != null
&& i.intValue() >= Decompiler.importPackageLimit )
|| ( (i = (Integer)imports.get(name)) != null
&& i.intValue() >= Decompiler.importClassLimit )) {
return name.substring(pkgdelim+1);
} }
pkg = ident.getQualifier();
main = (BinaryClass)getClassDefinition(ident);
ClassAnalyzer a = new ClassAnalyzer(main, this);
a.analyze();
TabbedPrintWriter writer =
new TabbedPrintWriter(System.out, " ");
a.dumpSource(writer);
} catch (ClassNotFound e) {
error(e.toString());
} catch (java.io.IOException e) {
error(e.toString());
} }
return name;
} }
protected int loadFileFlags() protected int loadFileFlags()

@ -18,7 +18,6 @@
*/ */
package jode; package jode;
import sun.tools.java.Identifier;
import java.util.Enumeration; import java.util.Enumeration;
import java.util.Vector; import java.util.Vector;
@ -36,7 +35,7 @@ import java.util.Vector;
public class LocalInfo { public class LocalInfo {
private static int serialnr = 0; private static int serialnr = 0;
private int slot; private int slot;
private Identifier name; private String name;
private Type type; private Type type;
private LocalInfo shadow; private LocalInfo shadow;
private Vector operators = new Vector(); private Vector operators = new Vector();
@ -46,9 +45,7 @@ public class LocalInfo {
*/ */
/** /**
* Create a new local info. The name will be an identifier * Create a new local info. The name will be a string
* of the form local_x__yyy, where x is the slot number and
* yyy a unique number.
* @param slot The slot of this variable. * @param slot The slot of this variable.
*/ */
public LocalInfo(int slot) { public LocalInfo(int slot) {
@ -108,7 +105,7 @@ public class LocalInfo {
/** /**
* Get the name of this local. * Get the name of this local.
*/ */
public Identifier getName() { public String getName() {
if (shadow != null) { if (shadow != null) {
while (shadow.shadow != null) { while (shadow.shadow != null) {
shadow = shadow.shadow; shadow = shadow.shadow;
@ -116,7 +113,7 @@ public class LocalInfo {
return shadow.getName(); return shadow.getName();
} }
if (name == null) if (name == null)
name = Identifier.lookup("local_"+slot+"__"+serialnr++); name = "local_"+slot+"__"+serialnr++;
return name; return name;
} }
@ -131,7 +128,7 @@ public class LocalInfo {
/** /**
* Set the name of this local. * Set the name of this local.
*/ */
public void setName(Identifier name) { public void setName(String name) {
if (shadow != null) if (shadow != null)
shadow.setName(name); shadow.setName(name);
else else

@ -18,7 +18,6 @@
*/ */
package jode; package jode;
import sun.tools.java.*;
public class LocalVariableRangeList { public class LocalVariableRangeList {
@ -27,7 +26,7 @@ public class LocalVariableRangeList {
int length; int length;
MyLocalInfo next; MyLocalInfo next;
MyLocalInfo(int slot, int s, int l, Identifier n, Type t) { MyLocalInfo(int slot, int s, int l, String n, Type t) {
super (slot); super (slot);
start = s; start = s;
length = l; length = l;
@ -72,7 +71,7 @@ public class LocalVariableRangeList {
} }
public void addLocal(int start, int length, public void addLocal(int start, int length,
Identifier name, Type type) { String name, Type type) {
MyLocalInfo li = new MyLocalInfo(slot,start,length,name,type); MyLocalInfo li = new MyLocalInfo(slot,start,length,name,type);
add (li); add (li);
} }

@ -18,61 +18,42 @@
*/ */
package jode; package jode;
import sun.tools.java.Identifier; import java.util.Enumeration;
import java.io.*; import gnu.bytecode.CpoolUtf8;
import gnu.bytecode.LocalVarsAttr;
import gnu.bytecode.Variable;
import gnu.bytecode.Spy;
public class LocalVariableTable { public class LocalVariableTable {
LocalVariableRangeList[] locals; LocalVariableRangeList[] locals;
boolean readfromclass;
public LocalVariableTable(int size) { public LocalVariableTable(int size,
locals = new LocalVariableRangeList[size]; ClassAnalyzer cla, LocalVarsAttr attr) {
readfromclass = false;
}
public int getSize() {
return locals.length;
}
public boolean isReadFromClass() { locals = new LocalVariableRangeList[size];
return readfromclass; for (int i=0; i<size; i++)
} locals[i] = new LocalVariableRangeList(i);
public void read(JodeEnvironment env, DataInputStream stream) Enumeration vars = attr.allVars();
throws IOException while (vars.hasMoreElements()) {
{ Variable var = (Variable) vars.nextElement();
int count = stream.readUnsignedShort();
for (int i=0; i<count; i++) { int start = Spy.getStartPC(var);
int start = stream.readUnsignedShort(); int end = Spy.getEndPC(var);
int length = stream.readUnsignedShort(); int slot = Spy.getSlot(var);
int name_i = stream.readUnsignedShort(); String name = var.getName();
int desc_i = stream.readUnsignedShort(); Type type = Type.tType(var.getType().getSignature());
int slot = stream.readUnsignedShort(); locals[slot].addLocal(start, end-start, name, type);
LocalVariableRangeList lv = locals[slot];
if (lv == null) {
lv = new LocalVariableRangeList(slot);
locals[slot] = lv;
}
lv.addLocal(start, length,
Identifier.lookup((String)
env.getConstantPool().
getValue(name_i)),
Type.tType(env.getConstantPool().getType(desc_i)));
if (Decompiler.showLVT) if (Decompiler.showLVT)
System.err.println(""+env.getConstantPool().getValue(name_i) System.err.println(name + ": " + type
+": "+env.getConstantPool().getType(desc_i) +" range "+start+" - "+end
+" range "+start+" - "+(start+length)
+" slot "+slot); +" slot "+slot);
} }
readfromclass = true;
} }
public LocalVariableRangeList getLocal(int slot) public LocalVariableRangeList getLocal(int slot)
throws ArrayIndexOutOfBoundsException throws ArrayIndexOutOfBoundsException
{ {
LocalVariableRangeList lv = locals[slot]; return locals[slot];
if (lv == null)
lv = new LocalVariableRangeList(slot);
return lv;
} }
} }

@ -18,32 +18,76 @@
*/ */
package jode; package jode;
import sun.tools.java.*; import java.lang.reflect.*;
import java.lang.reflect.Modifier; import gnu.bytecode.Attribute;
import java.io.*; import gnu.bytecode.CodeAttr;
public class MethodAnalyzer implements Analyzer, Constants { public class MethodAnalyzer implements Analyzer {
FieldDefinition mdef;
JodeEnvironment env; JodeEnvironment env;
CodeAnalyzer code = null; CodeAnalyzer code = null;
ClassAnalyzer classAnalyzer;
boolean isConstructor;
Method method;
Constructor constr;
public MethodAnalyzer(FieldDefinition fd, JodeEnvironment e) private MethodAnalyzer(ClassAnalyzer cla, Method m, Constructor c,
JodeEnvironment e)
{ {
mdef = fd; classAnalyzer = cla;
method = m;
constr = c;
isConstructor = (c != null);
env = e; env = e;
byte bytecode[] = ((BinaryField) mdef).getAttribute(Constants.idCode);
if (bytecode != null) { String name = isConstructor ? "<init>" : m.getName();
BinaryCode bc = Class[] paramTypes = (isConstructor
new BinaryCode(bytecode, ? c.getParameterTypes()
env.getConstantPool(), : m.getParameterTypes());
env);
code = new CodeAnalyzer(this, bc, env); gnu.bytecode.Method mdef = cla.classType.getMethods();
while (mdef != null) {
if (mdef.getName().equals(name)) {
gnu.bytecode.Type[] argtypes = mdef.getParameterTypes();
if (argtypes.length == paramTypes.length) {
int i;
for (i=0; i<argtypes.length; i++) {
if (!Type.tType(paramTypes[i]).equals(Type.tType(argtypes[i].getSignature())))
break;
}
if (i == argtypes.length)
break;
}
}
mdef = mdef.getNext();
} }
Attribute attr = Attribute.get(mdef, "Code");
if (attr != null && attr instanceof CodeAttr)
code = new CodeAnalyzer(this, (CodeAttr) attr, env);
}
public MethodAnalyzer(ClassAnalyzer cla, Method method,
JodeEnvironment env)
{
this(cla, method, null, env);
}
public MethodAnalyzer(ClassAnalyzer cla, Constructor constr,
JodeEnvironment env)
{
this(cla, null, constr, env);
} }
public int getParamCount() { public int getParamCount() {
return (mdef.isStatic()?0:1)+ return isConstructor
mdef.getType().getArgumentTypes().length; ? (constr.getParameterTypes().length + 1)
: ((Modifier.isStatic(method.getModifiers()) ? 0 : 1)
+ method.getParameterTypes().length);
}
public Type getReturnType() {
return isConstructor
? Type.tVoid : Type.tType(method.getReturnType());
} }
public void analyze() public void analyze()
@ -53,17 +97,16 @@ public class MethodAnalyzer implements Analyzer, Constants {
return; return;
int offset = 0; int offset = 0;
if (!mdef.isStatic()) { if (isConstructor || !Modifier.isStatic(method.getModifiers())) {
LocalInfo clazz = code.getParamInfo(0); LocalInfo clazz = code.getParamInfo(0);
clazz.setType(Type.tClass(mdef.getClassDefinition() clazz.setType(Type.tType(this.classAnalyzer.clazz));
.getName().toString())); clazz.setName("this");
clazz.setName(Constants.idThis);
offset++; offset++;
} }
sun.tools.java.Type[] paramTypes = mdef.getType().getArgumentTypes(); Class[] paramTypes = isConstructor
? constr.getParameterTypes() : method.getParameterTypes();
for (int i=0; i< paramTypes.length; i++) for (int i=0; i< paramTypes.length; i++)
code.getParamInfo(offset+i).setType code.getParamInfo(offset+i).setType(Type.tType(paramTypes[i]));
(Type.tType(paramTypes[i].getTypeSignature()));
// We do the code.analyze() in dumpSource, to get // We do the code.analyze() in dumpSource, to get
// immediate output. // immediate output.
@ -74,41 +117,47 @@ public class MethodAnalyzer implements Analyzer, Constants {
{ {
if (code != null) { if (code != null) {
if (Decompiler.isVerbose) if (Decompiler.isVerbose)
System.err.print(mdef.getName().toString()+": "); System.err.print((isConstructor
? "<init>" : method.getName())+": ");
code.analyze(); code.analyze();
if (Decompiler.isVerbose) if (Decompiler.isVerbose)
System.err.println(""); System.err.println("");
} }
writer.println(""); writer.println("");
String modif = Modifier.toString(mdef.getModifiers()); String modif = Modifier.toString(isConstructor
? constr.getModifiers()
: method.getModifiers());
if (modif.length() > 0) if (modif.length() > 0)
writer.print(modif+" "); writer.print(modif+" ");
if (mdef.isInitializer()) { if (isConstructor && Modifier.isStatic(constr.getModifiers()))
writer.print(""); /* static block */ writer.print(""); /* static block */
} else { else {
if (mdef.isConstructor()) if (isConstructor)
writer.print(mdef.getClassDeclaration().getName().toString()); writer.print(env.classString(classAnalyzer.clazz));
else else
writer.print(env.getTypeString writer.print(Type.tType(method.getReturnType()).toString()
(Type.tType(mdef.getType().getReturnType())) + " " + method.getName());
+ " " + mdef.getName().toString());
writer.print("("); writer.print("(");
sun.tools.java.Type[] paramTypes = Class[] paramTypes = isConstructor
mdef.getType().getArgumentTypes(); ? constr.getParameterTypes() : method.getParameterTypes();
int offset = mdef.isStatic()?0:1; int offset = (!isConstructor
&& Modifier.isStatic(method.getModifiers()))?0:1;
for (int i=0; i<paramTypes.length; i++) { for (int i=0; i<paramTypes.length; i++) {
if (i>0) if (i>0)
writer.print(", "); writer.print(", ");
writer.print if (code == null) {
((code == null)? writer.print(classAnalyzer.getTypeString
env.getTypeString(Type.tType(paramTypes[i])): (Type.tType(paramTypes[i])));
env.getTypeString(Type.tType(paramTypes[i]), } else {
code.getParamInfo(i+offset).getName())); LocalInfo li = code.getParamInfo(i+offset);
writer.print(li.getType().toString()+" "+li.getName());
}
} }
writer.print(")"); writer.print(")");
} }
IdentifierToken[] exceptions = mdef.getExceptionIds(); Class[] exceptions = isConstructor
? constr.getExceptionTypes() : method.getExceptionTypes();
if (exceptions != null && exceptions.length > 0) { if (exceptions != null && exceptions.length > 0) {
writer.println(""); writer.println("");
writer.print("throws "); writer.print("throws ");
@ -116,7 +165,7 @@ public class MethodAnalyzer implements Analyzer, Constants {
if (exceptions[i] != null) { if (exceptions[i] != null) {
if (i > 0) if (i > 0)
writer.print(", "); writer.print(", ");
writer.print(env.getTypeString(exceptions[i].getName())); writer.print(env.classString(exceptions[i]));
} }
} }
} }
@ -129,13 +178,4 @@ public class MethodAnalyzer implements Analyzer, Constants {
} else } else
writer.println(";"); writer.println(";");
} }
/*
public byte[] getAttribute(Identifier identifier)
{
if (mdef instanceof BinaryField)
return ((BinaryField)mdef).getAttribute(identifier);
return null;
}
*/
} }

@ -18,7 +18,6 @@
*/ */
package jode; package jode;
import sun.tools.java.Constants;
public class ComplexExpression extends Expression { public class ComplexExpression extends Expression {
Operator operator; Operator operator;
@ -181,14 +180,14 @@ public class ComplexExpression extends Expression {
new EmptyStringOperator(); new EmptyStringOperator();
Expression simplifyStringBuffer() { Expression simplifyStringBuffer() {
sun.tools.java.FieldDefinition field; gnu.bytecode.CpoolRef field;
if (operator instanceof InvokeOperator && if (operator instanceof InvokeOperator
(field = ((InvokeOperator)operator).getField()) && ((field = ((InvokeOperator)operator).getField())
.getClassDefinition().getName() .getCpoolClass().getName().getString()
== Constants.idJavaLangStringBuffer .equals("java.lang.StringBuffer"))
&& !((InvokeOperator)operator).isStatic() && && !((InvokeOperator)operator).isStatic() &&
field.getName() == Constants.idAppend && field.getNameAndType().getName().getString().equals("append") &&
field.getType().getArgumentTypes().length == 1) { ((InvokeOperator)operator).getMethodType().getArgumentTypes().length == 1) {
Expression e = subExpressions[0].simplifyStringBuffer(); Expression e = subExpressions[0].simplifyStringBuffer();
if (e == null) if (e == null)
@ -286,26 +285,26 @@ public class ComplexExpression extends Expression {
return subExpressions[0].simplify(); return subExpressions[0].simplify();
} }
if (operator instanceof InvokeOperator && if (operator instanceof InvokeOperator
((InvokeOperator)operator).getField() && (((InvokeOperator)operator).getField()
.getName() == Constants.idToString && .getNameAndType().getName().getString().equals("toString"))
!((InvokeOperator)operator).isStatic() && && !((InvokeOperator)operator).isStatic()
((InvokeOperator)operator).getField() && (((InvokeOperator)operator).getField()
.getClassDefinition().getName() .getCpoolClass().getName().getString()
== Constants.idJavaLangStringBuffer && .equals("java.lang.StringBuffer"))
subExpressions.length == 1) { && subExpressions.length == 1) {
Instruction simple = subExpressions[0].simplifyStringBuffer(); Instruction simple = subExpressions[0].simplifyStringBuffer();
if (simple != null) if (simple != null)
return simple; return simple;
} }
if (operator instanceof InvokeOperator && if (operator instanceof InvokeOperator
((InvokeOperator)operator).getField() && (((InvokeOperator)operator).getField()
.getName() == Constants.idValueOf && .getNameAndType().getName().getString().equals("valueOf"))
((InvokeOperator)operator).isStatic() && && ((InvokeOperator)operator).isStatic()
((InvokeOperator)operator).getField() && (((InvokeOperator)operator).getField()
.getClassDefinition().getName() .getCpoolClass().getName().getString()
== Constants.idJavaLangString && .equals("java.lang.String"))
subExpressions.length == 1) { && subExpressions.length == 1) {
if (subExpressions[0].getType() == Type.tString) if (subExpressions[0].getType() == Type.tString)
return subExpressions[0].simplify(); return subExpressions[0].simplify();
else { else {

@ -24,8 +24,6 @@ public class ConstOperator extends NoArgOperator {
public ConstOperator(Type type, String value) { public ConstOperator(Type type, String value) {
super(type); super(type);
if (type == Type.tString)
value = quoted(value);
this.value = value; this.value = value;
} }
@ -37,29 +35,6 @@ public class ConstOperator extends NoArgOperator {
return 1000; return 1000;
} }
public static String quoted(String str) {
StringBuffer result = new StringBuffer("\"");
for (int i=0; i< str.length(); i++) {
switch (str.charAt(i)) {
case '\t':
result.append("\\t");
break;
case '\n':
result.append("\\n");
break;
case '\\':
result.append("\\\\");
break;
case '\"':
result.append("\\\"");
break;
default:
result.append(str.charAt(i));
}
}
return result.append("\"").toString();
}
public boolean equals(Object o) { public boolean equals(Object o) {
return (o instanceof ConstOperator) && return (o instanceof ConstOperator) &&
((ConstOperator)o).value.equals(value); ((ConstOperator)o).value.equals(value);

@ -18,13 +18,17 @@
*/ */
package jode; package jode;
import sun.tools.java.FieldDefinition; import gnu.bytecode.CpoolRef;
public class ConstructorOperator extends Operator { public class ConstructorOperator extends Operator {
FieldDefinition field; CpoolRef field;
MethodType methodType;
Type classType;
public ConstructorOperator(Type type, FieldDefinition field) { public ConstructorOperator(Type type, CpoolRef field) {
super(type, 0); super(type, 0);
methodType = new MethodType(field.getNameAndType().
getType().getString());
this.field = field; this.field = field;
} }
@ -33,7 +37,7 @@ public class ConstructorOperator extends Operator {
} }
public int getOperandCount() { public int getOperandCount() {
return 1 + field.getType().getArgumentTypes().length; return 1 + methodType.getArgumentTypes().length;
} }
public int getOperandPriority(int i) { public int getOperandPriority(int i) {
@ -44,10 +48,8 @@ public class ConstructorOperator extends Operator {
public Type getOperandType(int i) { public Type getOperandType(int i) {
if (i == 0) if (i == 0)
return Type.tSubType(Type.tClass(field.getClassDeclaration() return Type.tSubType(type);
.getName().toString())); return Type.tSubType(methodType.getArgumentTypes()[i-1]);
return Type.tSubType(Type.tType(field.getType()
.getArgumentTypes()[i-1]));
} }
public void setOperandType(Type types[]) { public void setOperandType(Type types[]) {
@ -55,7 +57,7 @@ public class ConstructorOperator extends Operator {
public String toString(String[] operands) { public String toString(String[] operands) {
StringBuffer result = new StringBuffer(operands[0]).append("("); StringBuffer result = new StringBuffer(operands[0]).append("(");
for (int i=0; i < field.getType().getArgumentTypes().length; i++) { for (int i=0; i < methodType.getArgumentTypes().length; i++) {
if (i>0) if (i>0)
result.append(", "); result.append(", ");
result.append(operands[i+1]); result.append(operands[i+1]);

@ -18,16 +18,16 @@
*/ */
package jode; package jode;
import sun.tools.java.*; import gnu.bytecode.CpoolRef;
public class GetFieldOperator extends Operator { public class GetFieldOperator extends Operator {
boolean staticFlag; boolean staticFlag;
FieldDefinition field; CpoolRef field;
CodeAnalyzer codeAnalyzer; CodeAnalyzer codeAnalyzer;
public GetFieldOperator(CodeAnalyzer codeAnalyzer, boolean staticFlag, public GetFieldOperator(CodeAnalyzer codeAnalyzer, boolean staticFlag,
FieldDefinition field) { CpoolRef field) {
super(Type.tType(field.getType()), 0); super(Type.tType(field.getNameAndType().getType().getString()), 0);
this.codeAnalyzer = codeAnalyzer; this.codeAnalyzer = codeAnalyzer;
this.staticFlag = staticFlag; this.staticFlag = staticFlag;
this.field = field; this.field = field;
@ -54,8 +54,8 @@ public class GetFieldOperator extends Operator {
/* shouldn't be called */ /* shouldn't be called */
throw new RuntimeException("Field is static"); throw new RuntimeException("Field is static");
} }
return Type.tSubType(Type.tClass(field.getClassDeclaration() return Type.tSubType(Type.tClass(field.getCpoolClass()
.getName().toString())); .getName().getString()));
} }
public void setOperandType(Type types[]) { public void setOperandType(Type types[]) {
@ -64,18 +64,19 @@ public class GetFieldOperator extends Operator {
public String toString(String[] operands) { public String toString(String[] operands) {
String object; String object;
if (staticFlag) { if (staticFlag) {
if (field.getClassDefinition() == codeAnalyzer.getClassDefinition()) if (field.getCpoolClass().getName().getString()
return field.getName().toString(); .equals(codeAnalyzer.getClazz().getName()))
return field.getNameAndType().getName().getString();
object = object =
codeAnalyzer.getTypeString codeAnalyzer.getTypeString
(Type.tClass(field.getClassDeclaration() (Type.tClass(field.getCpoolClass()
.getName().toString())); .getName().getString()));
} else { } else {
if (operands[0].equals("this")) if (operands[0].equals("this"))
return field.getName().toString(); return field.getNameAndType().getName().getString();
object = operands[0]; object = operands[0];
} }
return object + "." + field.getName(); return object + "." + field.getNameAndType().getName().getString();
} }
public boolean equals(Object o) { public boolean equals(Object o) {

@ -18,19 +18,24 @@
*/ */
package jode; package jode;
import sun.tools.java.*; import gnu.bytecode.CpoolRef;
public class InvokeOperator extends Operator { public final class InvokeOperator extends Operator {
CodeAnalyzer codeAnalyzer; CodeAnalyzer codeAnalyzer;
boolean staticFlag; boolean staticFlag;
boolean specialFlag; boolean specialFlag;
FieldDefinition field; MethodType methodType;
Type classType;
CpoolRef field;
public InvokeOperator(CodeAnalyzer codeAnalyzer, public InvokeOperator(CodeAnalyzer codeAnalyzer,
boolean staticFlag, boolean specialFlag, boolean staticFlag, boolean specialFlag,
FieldDefinition field) { CpoolRef field) {
super(Type.tType(field.getType().getReturnType().getTypeSignature()), super(Type.tError, 0);
0); methodType = new MethodType(field.getNameAndType().
getType().getString());
classType = Type.tClass(field.getCpoolClass().getName().getString());
setType(methodType.getReturnType());
this.codeAnalyzer = codeAnalyzer; this.codeAnalyzer = codeAnalyzer;
this.staticFlag = staticFlag; this.staticFlag = staticFlag;
this.specialFlag = specialFlag; this.specialFlag = specialFlag;
@ -41,12 +46,16 @@ public class InvokeOperator extends Operator {
return staticFlag; return staticFlag;
} }
public FieldDefinition getField() { public CpoolRef getField() {
return field; return field;
} }
public MethodType getMethodType() {
return methodType;
}
public Type getClassType() { public Type getClassType() {
return Type.tClass(field.getClassDeclaration().getName().toString()); return classType;
} }
public int getPriority() { public int getPriority() {
@ -54,7 +63,7 @@ public class InvokeOperator extends Operator {
} }
public int getOperandCount() { public int getOperandCount() {
return (staticFlag?0:1) + field.getType().getArgumentTypes().length; return (staticFlag?0:1) + methodType.getArgumentTypes().length;
} }
public int getOperandPriority(int i) { public int getOperandPriority(int i) {
@ -69,65 +78,49 @@ public class InvokeOperator extends Operator {
return Type.tSubType(getClassType()); return Type.tSubType(getClassType());
i--; i--;
} }
return Type.tSubType(Type.tType(field.getType(). return Type.tSubType(methodType.getArgumentTypes()[i]);
getArgumentTypes()[i].
getTypeSignature()));
} }
public void setOperandType(Type types[]) { public void setOperandType(Type types[]) {
} }
public boolean isConstructor() { public boolean isConstructor() {
return field.isConstructor(); return field.getNameAndType().getName().getString().equals("<init>");
} }
public String toString(String[] operands) { public String toString(String[] operands) {
String object; String object =
int arg = 0; staticFlag
if (staticFlag) { ? ((field.getCpoolClass().getName().getString()
if (field.getClassDefinition() == codeAnalyzer.getClassDefinition()) .replace(java.io.File.separatorChar, '.')
object = ""; .equals(codeAnalyzer.getClazz().getName()))
else ? ""
object = codeAnalyzer. : codeAnalyzer.getTypeString(getClassType()))
getTypeString(getClassType()); : (operands[0].equals("this")
} else { ? (specialFlag
if (operands[arg].equals("this")) { ? ( (field.getCpoolClass().getName().getString()
if (specialFlag .replace(java.io.File.separatorChar, '.')
&& (field.getClassDeclaration() .equals(codeAnalyzer.getClazz()
== codeAnalyzer.getClassDefinition().getSuperClass())) .getSuperclass().getName()))
// || (field.getClassDeclaration().getName() ? "super"
// == Constants.idJavaLangObject : "((" + codeAnalyzer.getTypeString(getClassType())
// && codeAnalyzer.getClassDefinition() + ") this)" )
// .getSuperClass() == null))) : "")
object = "super"; : (specialFlag
else if (specialFlag) ? "((" + codeAnalyzer.getTypeString(getClassType())
object = "(("+codeAnalyzer.getTypeString(getClassType()) + ") " + operands[0]+")"
+ ") this)"; : operands[0] ));
else
object = ""; int arg = staticFlag ? 0 : 1;
} else {
if (specialFlag)
object = "((" + codeAnalyzer.getTypeString(getClassType())
+ ") " + operands[arg]+")";
else
object = operands[arg];
}
arg++;
}
String method; String method;
if (isConstructor()) { if (isConstructor())
if (object.length() == 0) method = (object.length() == 0 ? "this" : object);
method = "this"; else
else method = (object.length() == 0 ? "" : object + ".")
method = object; + field.getNameAndType().getName().getString();
} else {
if (object.length() == 0)
method = field.getName().toString();
else
method = object+"."+field.getName().toString();
}
StringBuffer params = new StringBuffer(); StringBuffer params = new StringBuffer();
for (int i=0; i < field.getType().getArgumentTypes().length; i++) { for (int i=0; i < methodType.getArgumentTypes().length; i++) {
if (i>0) if (i>0)
params.append(", "); params.append(", ");
params.append(operands[arg++]); params.append(operands[arg++]);

@ -22,13 +22,11 @@ package jode;
public class NewArrayOperator extends SimpleOperator { public class NewArrayOperator extends SimpleOperator {
String baseTypeString; String baseTypeString;
public NewArrayOperator(Type arrayType, String baseTypeString, public NewArrayOperator(Type arrayType, int dimensions) {
int dimensions) {
super(arrayType, 0, dimensions); super(arrayType, 0, dimensions);
for (int i=0; i< dimensions; i++) { for (int i=0; i< dimensions; i++) {
operandTypes[i] = Type.tInt; operandTypes[i] = Type.tInt;
} }
this.baseTypeString = baseTypeString;
} }
public int getPriority() { public int getPriority() {
@ -40,11 +38,16 @@ public class NewArrayOperator extends SimpleOperator {
} }
public String toString(String[] operands) { public String toString(String[] operands) {
StringBuffer result StringBuffer arrays = new StringBuffer();
= new StringBuffer("new ").append(baseTypeString); Type flat = type;
for (int i=0; i< getOperandCount(); i++) { int i = 0;
result.append("[").append(operands[i]).append("]"); while (flat instanceof ArrayType) {
flat = ((ArrayType)flat).getElementType();
if (i < getOperandCount())
arrays.append("[").append(operands[i++]).append("]");
else
arrays.append("[]");
} }
return result.toString(); return "new "+flat.toString()+arrays;
} }
} }

@ -69,13 +69,6 @@ public abstract class Operator extends Expression {
operator = op; operator = op;
} }
/**
* Sets the return type of this operator.
*/
public void setType(Type type) {
this.type = type;
}
public String getOperatorString() { public String getOperatorString() {
return opString[operator]; return opString[operator];
} }

@ -18,16 +18,16 @@
*/ */
package jode; package jode;
import sun.tools.java.*; import gnu.bytecode.CpoolRef;
public class PutFieldOperator extends StoreInstruction { public class PutFieldOperator extends StoreInstruction {
CodeAnalyzer codeAnalyzer; CodeAnalyzer codeAnalyzer;
boolean staticFlag; boolean staticFlag;
FieldDefinition field; CpoolRef field;
public PutFieldOperator(CodeAnalyzer codeAnalyzer, boolean staticFlag, public PutFieldOperator(CodeAnalyzer codeAnalyzer, boolean staticFlag,
FieldDefinition field) { CpoolRef field) {
super(Type.tType(field.getType()), ASSIGN_OP); super(Type.tType(field.getNameAndType().getType().getString()), ASSIGN_OP);
this.codeAnalyzer = codeAnalyzer; this.codeAnalyzer = codeAnalyzer;
this.staticFlag = staticFlag; this.staticFlag = staticFlag;
this.field = field; this.field = field;
@ -55,8 +55,8 @@ public class PutFieldOperator extends StoreInstruction {
/* shouldn't be called */ /* shouldn't be called */
throw new AssertError("Field is static"); throw new AssertError("Field is static");
} }
return Type.tSubType(Type.tClass(field.getClassDefinition() return Type.tSubType(Type.tClass(field.getCpoolClass()
.getName().toString())); .getName().getString()));
} }
public void setLValueOperandType(Type[] t) { public void setLValueOperandType(Type[] t) {
@ -70,18 +70,17 @@ public class PutFieldOperator extends StoreInstruction {
public String getLValueString(String[] operands) { public String getLValueString(String[] operands) {
String object; String object;
if (staticFlag) { if (staticFlag) {
if (field.getClassDefinition() if (field.getCpoolClass().getName().getString()
== codeAnalyzer.getClassDefinition()) .equals(codeAnalyzer.getClazz().getName()))
return field.getName().toString(); return field.getNameAndType().getName().getString();
object = codeAnalyzer.getTypeString object = codeAnalyzer.getTypeString
(Type.tClass(field.getClassDeclaration() (Type.tClass(field.getCpoolClass().getName().getString()));
.getName().toString()))+".";
} else { } else {
if (operands[0].equals("this")) if (operands[0].equals("this"))
return field.getName().toString(); return field.getNameAndType().getName().getString();
object = operands[0]; object = operands[0];
} }
return object + "." + field.getName(); return object + "." + field.getNameAndType().getName().getString();
} }
public boolean equals(Object o) { public boolean equals(Object o) {

@ -19,7 +19,6 @@
package jode.flow; package jode.flow;
import jode.Type; import jode.Type;
import jode.LocalInfo; import jode.LocalInfo;
import sun.tools.java.Identifier;
/** /**
* *
@ -72,8 +71,7 @@ public class CatchBlock extends StructuredBlock {
if (instr instanceof jode.PopOperator) { if (instr instanceof jode.PopOperator) {
exceptionLocal = new LocalInfo(-1); exceptionLocal = new LocalInfo(-1);
exceptionLocal.setName exceptionLocal.setName("exception_"+(serialno++)+"_");
(Identifier.lookup("exception_"+(serialno++)+"_"));
exceptionLocal.setType(exceptionType); exceptionLocal.setType(exceptionType);
} else if (instr instanceof jode.LocalStoreOperator) { } else if (instr instanceof jode.LocalStoreOperator) {
exceptionLocal = exceptionLocal =
@ -92,7 +90,7 @@ public class CatchBlock extends StructuredBlock {
} }
if (exceptionLocal == null) { if (exceptionLocal == null) {
exceptionLocal = new LocalInfo(-1); exceptionLocal = new LocalInfo(-1);
exceptionLocal.setName(Identifier.lookup("ERROR!!!")); exceptionLocal.setName("ERROR!!!");
exceptionLocal.setType(exceptionType); exceptionLocal.setType(exceptionType);
} }
used.addElement(exceptionLocal); used.addElement(exceptionLocal);

@ -17,7 +17,6 @@
* $Id$ * $Id$
*/ */
package jode; package jode;
import sun.tools.java.*;
import java.util.Vector; import java.util.Vector;
import java.util.Stack; import java.util.Stack;
@ -370,9 +369,9 @@ public class ClassInterfacesType extends Type {
return sb.append("}").toString(); return sb.append("}").toString();
} else { } else {
if (clazz != null) if (clazz != null)
return clazz.getName(); return env.classString(clazz);
else if (ifaces.length > 0) else if (ifaces.length > 0)
return ifaces[0].getName(); return env.classString(ifaces[0]);
else else
return "{<error>}"; return "{<error>}";
} }

@ -0,0 +1,65 @@
/* MethodType Copyright (C) 1997-1998 Jochen Hoenicke.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id$
*/
package jode;
/**
* This type represents an method type.
*
* @author Jochen Hoenicke
*/
public class MethodType {
Type[] argumentTypes;
Type returnType;
Type elementType;
public MethodType(String signature) {
int index = 1, types = 0;
while (signature.charAt(index) != ')') {
types++;
while (signature.charAt(index) == '[')
index++;
if (signature.charAt(index) == 'L')
index = signature.indexOf(';', index);
index++;
}
argumentTypes = new Type[types];
index = 1;
types = 0;
while (signature.charAt(index) != ')') {
int lastindex = index;
while (signature.charAt(index) == '[')
index++;
if (signature.charAt(index) == 'L')
index = signature.indexOf(';', index);
index++;
argumentTypes[types++]
= Type.tType(signature.substring(lastindex,index));
}
returnType = Type.tType(signature.substring(index+1));
}
public Type[] getArgumentTypes() {
return argumentTypes;
}
public Type getReturnType() {
return returnType;
}
}

@ -21,7 +21,7 @@ package jode;
import java.util.Hashtable; import java.util.Hashtable;
/** /**
* This is my type class. It differs from sun.tools.java.Type, in * This is my type class. It differs from java.lang.class, in
* that it maintains a type range. This type range may be implicit or * that it maintains a type range. This type range may be implicit or
* explicit. <p> * explicit. <p>
* *
@ -138,16 +138,31 @@ public class Type {
int index = type.indexOf(';'); int index = type.indexOf(';');
if (index != type.length()-1) if (index != type.length()-1)
return tError; return tError;
return tClass(type.substring(1, index).replace('/', '.')); return tClass(type.substring(1, index));
} }
throw new AssertError("Unknown type signature: "+type); throw new AssertError("Unknown type signature: "+type);
} }
public static final Type tType(sun.tools.java.Type type) { public static final Type tType(Class clazz) {
return tType(type.getTypeSignature()); if (clazz.isArray())
return tArray(tType(clazz.getComponentType()));
if (clazz.isPrimitive()) {
return clazz == Boolean.TYPE ? tBoolean
: clazz == Byte.TYPE ? tByte
: clazz == Character.TYPE ? tChar
: clazz == Short.TYPE ? tShort
: clazz == Integer.TYPE ? tInt
: clazz == Float.TYPE ? tFloat
: clazz == Long.TYPE ? tLong
: clazz == Double.TYPE ? tDouble
: clazz == Void.TYPE ? tVoid
: tError;
}
return tClass(clazz.getName());
} }
public static final Type tClass(String clazzname) { public static final Type tClass(String clazzname) {
clazzname = clazzname.replace(java.io.File.separatorChar, '.');
Object result = classHash.get(clazzname); Object result = classHash.get(clazzname);
if (result == null) { if (result == null) {
result = new ClassInterfacesType(clazzname); result = new ClassInterfacesType(clazzname);
@ -184,11 +199,11 @@ public class Type {
return tUnknown.createRangeType(type.getBottom()); return tUnknown.createRangeType(type.getBottom());
} }
public static Type tClassOrArray(sun.tools.java.Identifier ident) { public static Type tClassOrArray(String ident) {
if (ident.toString().charAt(0) == '[') if (ident.charAt(0) == '[')
return Type.tType(ident.toString()); return Type.tType(ident);
else else
return Type.tClass(ident.toString()); return Type.tClass(ident);
} }
public static void setEnvironment(JodeEnvironment e) { public static void setEnvironment(JodeEnvironment e) {

Loading…
Cancel
Save