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. 78
      jode/jode/decompiler/CodeAnalyzer.java
  6. 39
      jode/jode/decompiler/FieldAnalyzer.java
  7. 161
      jode/jode/decompiler/ImportHandler.java
  8. 13
      jode/jode/decompiler/LocalInfo.java
  9. 5
      jode/jode/decompiler/LocalVariableRangeList.java
  10. 63
      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;
import sun.tools.java.*;
import java.lang.reflect.Modifier;
public class Decompiler {
public static boolean isVerbose = false;
@ -29,6 +27,8 @@ public class Decompiler {
public static boolean debugInOut = false;
public static boolean showLVT = false;
public static boolean doChecks = false;
public static int importPackageLimit = 3;
public static int importClassLimit = 3;
public static void main(String[] params) {
JodeEnvironment env = new JodeEnvironment();
@ -47,7 +47,10 @@ public class Decompiler {
showLVT = true;
else if (params[i].equals("-check"))
doChecks = true;
else
else if (params[i].equals("-import")) {
importPackageLimit = Integer.parseInt(params[++i]);
importClassLimit = Integer.parseInt(params[++i]);
} else
env.doClass(params[i]);
}
}

@ -20,13 +20,14 @@
package jode;
import jode.flow.*;
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
* 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 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 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[][] = {
{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();
return createNormal
(ca, addr, 2, new ConstOperator
(ca.env.getConstantType(index),
ca.env.getConstant(index).toString()));
(ca.method.classAnalyzer.getConstantType(index),
ca.method.classAnalyzer.getConstantString(index)));
}
case opc_ldc_w:
case opc_ldc2_w: {
int index = stream.readUnsignedShort();
return createNormal
(ca, addr, 3, new ConstOperator
(ca.env.getConstantType(index),
ca.env.getConstant(index).toString()));
(ca.method.classAnalyzer.getConstantType(index),
ca.method.classAnalyzer.getConstantString(index)));
}
case opc_iload: case opc_lload:
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_freturn: case opc_dreturn: case opc_areturn: {
Type retType =
Type.tSubType(Type.tType(ca.getMethod().mdef.getType()
.getReturnType()));
Type retType = Type.tSubType(ca.getMethod().getReturnType());
return createBlock
(ca, addr, 1, new ReturnBlock(new NopOperator(retType)));
}
@ -396,14 +599,14 @@ public abstract class Opcodes implements RuntimeConstants {
return createNormal
(ca, addr, 3, new GetFieldOperator
(ca, opcode == opc_getstatic,
(FieldDefinition)ca.env.getConstant
(CpoolRef)ca.method.classAnalyzer.getConstant
(stream.readUnsignedShort())));
case opc_putstatic:
case opc_putfield:
return createNormal
(ca, addr, 3, new PutFieldOperator
(ca, opcode == opc_putstatic,
(FieldDefinition)ca.env.getConstant
(CpoolRef)ca.method.classAnalyzer.getConstant
(stream.readUnsignedShort())));
case opc_invokevirtual:
case opc_invokespecial:
@ -412,23 +615,23 @@ public abstract class Opcodes implements RuntimeConstants {
(ca, addr, 3, new InvokeOperator
(ca,
opcode == opc_invokestatic, opcode == opc_invokespecial,
(FieldDefinition)ca.env.getConstant
(CpoolRef)ca.method.classAnalyzer.getConstant
(stream.readUnsignedShort())));
case opc_invokeinterface: {
FlowBlock fb = createNormal
(ca, addr, 5, new InvokeOperator
(ca, false, false,
(FieldDefinition)ca.env.getConstant
(CpoolRef)ca.method.classAnalyzer.getConstant
(stream.readUnsignedShort())));
int reserved = stream.readUnsignedShort();
return fb;
}
case opc_new: {
ClassDeclaration cldec = (ClassDeclaration)
ca.env.getConstant(stream.readUnsignedShort());
Type type = Type.tClassOrArray(cldec.getName());
CpoolClass cpcls = (CpoolClass)
ca.method.classAnalyzer.getConstant(stream.readUnsignedShort());
Type type = Type.tClassOrArray(cpcls.getName().getString());
return createNormal
(ca, addr, 3, new NewOperator(type, ca.env.getTypeString(type)));
(ca, addr, 3, new NewOperator(type, type.toString()));
}
case opc_newarray: {
Type type;
@ -445,18 +648,15 @@ public abstract class Opcodes implements RuntimeConstants {
throw new ClassFormatError("Invalid newarray operand");
}
return createNormal
(ca, addr, 2,
new NewArrayOperator(Type.tArray(type),
type.toString(), 1));
(ca, addr, 2, new NewArrayOperator(Type.tArray(type), 1));
}
case opc_anewarray: {
ClassDeclaration cldec = (ClassDeclaration) ca.env.getConstant
CpoolClass cpcls = (CpoolClass)
ca.method.classAnalyzer.getConstant
(stream.readUnsignedShort());
Identifier ident = cldec.getName();
Type type = Type.tClassOrArray(cldec.getName());
Type type = Type.tClassOrArray(cpcls.getName().getString());
return createNormal
(ca, addr, 3, new NewArrayOperator
(Type.tArray(type), ca.env.getTypeString(type),1));
(ca, addr, 3, new NewArrayOperator(Type.tArray(type), 1));
}
case opc_arraylength:
return createNormal
@ -466,20 +666,22 @@ public abstract class Opcodes implements RuntimeConstants {
(ca, addr, 1,
new ThrowBlock(new NopOperator(Type.tUObject)));
case opc_checkcast: {
ClassDeclaration cldec = (ClassDeclaration) ca.env.getConstant
CpoolClass cpcls = (CpoolClass)
ca.method.classAnalyzer.getConstant
(stream.readUnsignedShort());
Type type = Type.tClassOrArray(cldec.getName());
Type type = Type.tClassOrArray(cpcls.getName().getString());
return createNormal
(ca, addr, 3, new CheckCastOperator
(type, ca.env.getTypeString(type)));
(type, type.toString()));
}
case opc_instanceof: {
ClassDeclaration cldec = (ClassDeclaration) ca.env.getConstant
CpoolClass cpcls = (CpoolClass)
ca.method.classAnalyzer.getConstant
(stream.readUnsignedShort());
Type type = Type.tClassOrArray(cldec.getName());
Type type = Type.tClassOrArray(cpcls.getName().getString());
return createNormal
(ca, addr, 3,
new InstanceOfOperator(type, ca.env.getTypeString(type)));
new InstanceOfOperator(type, type.toString()));
}
case opc_monitorenter:
return createNormal(ca, addr, 1,
@ -528,17 +730,14 @@ public abstract class Opcodes implements RuntimeConstants {
}
}
case opc_multianewarray: {
ClassDeclaration cldec = (ClassDeclaration) ca.env.getConstant
CpoolClass cpcls = (CpoolClass)
ca.method.classAnalyzer.getConstant
(stream.readUnsignedShort());
Type type = Type.tClassOrArray(cldec.getName());
Type type = Type.tClassOrArray(cpcls.getName().getString());
int dimension = stream.readUnsignedByte();
Type baseType = type;
for (int i=0; i<dimension; i++)
baseType = ((ArrayType)baseType).getElementType();
return createNormal
(ca, addr, 4,
new NewArrayOperator
(type, ca.env.getTypeString(baseType), dimension));
new NewArrayOperator(type, dimension));
}
case opc_ifnull: case opc_ifnonnull:
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;
import java.lang.reflect.Modifier;
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 {
BinaryClass cdef;
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;
env = e;
this.parent = parent;
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() {
int numFields = 0, i=0;
FieldDefinition f;
for (f= cdef.getInnerClassField(); f != null; f = f.getNextField())
numFields++;
for (f= cdef.getFirstField(); f != null; f = f.getNextField())
numFields++;
fields = new Analyzer[numFields];
for (f= cdef.getInnerClassField(); f != null; f = f.getNextField()) {
System.err.println("analyzing inner: "+f.getName());
fields[i] = new ClassAnalyzer((BinaryClass) f.getInnerClass(), env);
fields[i++].analyze();
Field[] fields = clazz.getDeclaredFields();
Method[] methods = clazz.getDeclaredMethods();
Constructor[] constrs = clazz.getDeclaredConstructors();
Class[] clazzes = clazz.getDeclaredClasses();
analyzers = new Analyzer[fields.length + methods.length
+ constrs.length + clazzes.length];
for (int j=0; j< clazzes.length; j++, i++) {
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) {
fields[i] = new MethodAnalyzer(f, env);
} else {
fields[i] = new FieldAnalyzer(f, env);
}
fields[i++].analyze();
for (int j=0; j< fields.length; j++, i++) {
analyzers[i] = new FieldAnalyzer(this, fields[j], env);
analyzers[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
{
if (cdef.getSource() != null)
writer.println("/* Original source: "+cdef.getSource()+" */");
// if (cdef.getSource() != null)
// writer.println("/* Original source: "+cdef.getSource()+" */");
if (cdef.getName().isQualified())
writer.println("package " + cdef.getName().getQualifier() + ";");
/* XXX imports */
writer.println("");
String modif = Modifier.toString(cdef.getModifiers());
String modif = Modifier.toString(clazz.getModifiers());
if (modif.length() > 0)
writer.print(modif + " ");
writer.print((cdef.isInterface())?"interface ":"class ");
writer.println(cdef.getName().getName().toString());
writer.print((clazz.isInterface())?"interface ":"class ");
writer.println(env.classString(clazz));
writer.tab();
if (cdef.getSuperClass() != null)
writer.println("extends "+cdef.getSuperClass().getName().toString());
ClassDeclaration interfaces[] = cdef.getInterfaces();
Class superClazz = clazz.getSuperclass();
if (superClazz != null &&
superClazz != new Object().getClass()) {
writer.println("extends "+env.classString(superClazz));
}
Class interfaces[] = clazz.getInterfaces();
if (interfaces.length > 0) {
writer.print("implements ");
for (int i=0; i < interfaces.length; i++) {
if (i > 0)
writer.print(", ");
writer.print(interfaces[i].getName().toString());
writer.print(env.classString(interfaces[i]));
}
writer.println("");
}
@ -89,11 +109,86 @@ public class ClassAnalyzer implements Analyzer {
writer.println("{");
writer.tab();
for (int i=0; i< fields.length; i++)
fields[i].dumpSource(writer);
for (int i=0; i< analyzers.length; i++)
analyzers[i].dumpSource(writer);
writer.untab();
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,17 +18,22 @@
*/
package jode;
import sun.tools.java.*;
import java.util.Stack;
import java.io.*;
import jode.flow.FlowBlock;
import jode.flow.Jump;
import jode.flow.StructuredBlock;
import jode.flow.RawTryCatchBlock;
public class CodeAnalyzer implements Analyzer, Constants {
import java.util.Stack;
import java.io.DataInputStream;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import gnu.bytecode.CodeAttr;
import gnu.bytecode.Attribute;
import gnu.bytecode.LocalVarsAttr;
import gnu.bytecode.CpoolClass;
BinaryCode bincode;
public class CodeAnalyzer implements Analyzer {
FlowBlock methodHeader;
MethodAnalyzer method;
@ -43,25 +48,15 @@ public class CodeAnalyzer implements Analyzer, Constants {
*/
public MethodAnalyzer getMethod() {return method;}
void readCode()
void readCode(CodeAttr bincode)
throws ClassFormatError
{
BinaryAttribute attr = bincode.getAttributes();
while (attr != null) {
if (attr.getName() == Constants.idLocalVariableTable) {
DataInputStream stream =
new DataInputStream
(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();
}
LocalVarsAttr attr =
(LocalVarsAttr) Attribute.get(bincode, "LocalVariableTable");
if (attr != null)
lvt = new LocalVariableTable(bincode.getMaxLocals(),
method.classAnalyzer, attr);
byte[] code = bincode.getCode();
FlowBlock[] instr = new FlowBlock[code.length];
@ -84,27 +79,30 @@ public class CodeAnalyzer implements Analyzer, Constants {
methodHeader = instr[0];
methodHeader.makeStartBlock();
BinaryExceptionHandler[] handlers = bincode.getExceptionHandlers();
for (int i=0; i<handlers.length; i++) {
StructuredBlock tryBlock = instr[handlers[i].startPC].getBlock();
short[] handlers = gnu.bytecode.Spy.getExceptionHandlers(bincode);
for (int i=0; i<handlers.length; i += 4) {
StructuredBlock tryBlock = instr[handlers[i + 0]].getBlock();
while (tryBlock instanceof RawTryCatchBlock
&& (((RawTryCatchBlock) tryBlock).getCatchAddr()
> handlers[i].handlerPC)) {
> handlers[i + 2])) {
tryBlock = ((RawTryCatchBlock)tryBlock).getTryBlock();
}
Type type =
(handlers[i].exceptionClass != null)?
Type.tClass(handlers[i].exceptionClass.getName().toString()) : null;
Type type = 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 Jump(instr[handlers[i].endPC]),
new Jump(instr[handlers[i].handlerPC]));
new Jump(instr[handlers[i + 1]]),
new Jump(instr[handlers[i + 2]]));
}
int paramCount = method.mdef.getType().getArgumentTypes().length
+ (method.mdef.isStatic() ? 0 : 1);
int paramCount = method.getParamCount();
param = new jode.flow.VariableSet();
for (int i=0; i<paramCount; i++)
param.addElement(getLocalInfo(0, i));
@ -117,13 +115,12 @@ public class CodeAnalyzer implements Analyzer, Constants {
methodHeader.dumpSource(writer);
}
public CodeAnalyzer(MethodAnalyzer ma, BinaryCode bc, JodeEnvironment e)
public CodeAnalyzer(MethodAnalyzer ma, CodeAttr bc, JodeEnvironment e)
throws ClassFormatError
{
method = ma;
env = e;
bincode = bc;
readCode();
readCode(bc);
}
public LocalInfo getLocalInfo(int addr, int slot) {
@ -142,12 +139,17 @@ public class CodeAnalyzer implements Analyzer, Constants {
methodHeader.analyze();
}
public void useClass(Class clazz)
{
env.useClass(clazz);
}
public String getTypeString(Type type) {
return env.getTypeString(type);
return method.classAnalyzer.getTypeString(type);
}
public ClassDefinition getClassDefinition() {
return env.getClassDefinition();
public Class getClazz() {
return method.classAnalyzer.clazz;
}
}

@ -18,23 +18,35 @@
*/
package jode;
import sun.tools.java.*;
import java.lang.reflect.Modifier;
import java.lang.reflect.*;
import gnu.bytecode.Attribute;
import gnu.bytecode.MiscAttr;
public class FieldAnalyzer implements Analyzer {
FieldDefinition fdef;
ClassAnalyzer clazz;
int constantValue;
Field field;
JodeEnvironment env;
public FieldAnalyzer(FieldDefinition fd, JodeEnvironment e)
public FieldAnalyzer(ClassAnalyzer cla, Field fd, JodeEnvironment e)
{
fdef = fd;
clazz = cla;
field = fd;
env = e;
}
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)
return value + 256;
else
@ -44,20 +56,15 @@ public class FieldAnalyzer implements Analyzer {
public void dumpSource(TabbedPrintWriter writer)
throws java.io.IOException
{
String modif = Modifier.toString(fdef.getModifiers());
String modif = Modifier.toString(field.getModifiers());
if (modif.length() > 0)
writer.print(modif+" ");
writer.print(env.getTypeString(Type.tType(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.print(Type.tType(field.getType()).toString()
+ " " + field.getName());
if (constantValue != 0) {
writer.print(" = "+clazz.getConstantString(constantValue));
}
writer.println(";");
}
}

@ -18,72 +18,45 @@
*/
package jode;
import sun.tools.java.*;
import sun.tools.util.*;
import java.util.*;
public class JodeEnvironment extends LoadEnvironment {
public class JodeEnvironment {
Hashtable imports = new Hashtable();
BinaryClass main;
Identifier pkg;
ClassAnalyzer main;
String className;
String pkg;
SearchPath classPath;
JodeEnvironment() {
super(null);
Type.setEnvironment(this);
path = new ClassPath(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();
classPath = new SearchPath(System.getProperty("java.class.path"));
}
public String getTypeString(Type type, Identifier name) {
return type.toString() + " " + name.toString();
}
public java.io.InputStream getClassStream(Class clazz)
throws java.io.IOException {
return classPath.getFile(clazz.getName().
replace('.', java.io.File.separatorChar)
+".class");
public ClassDefinition getClassDefinition() {
return main;
}
public void dumpHeader(TabbedPrintWriter writer)
throws java.io.IOException
{
writer.println("/* Decompiled by JoDe (Jochen's Decompiler) */");
if (pkg != null && pkg != Constants.idNull)
writer.println("/* "+ className + " - Decompiled by JoDe (Jochen's Decompiler)\n * Send comments or bug reports to Jochen Hoenicke <jochenh@bigfoot.com>\n */");
if (pkg.length() != 0)
writer.println("package "+pkg+";");
Enumeration enum = imports.keys();
while (enum.hasMoreElements()) {
Identifier packageName = (Identifier) enum.nextElement();
Integer vote = (Integer) imports.get(packageName);
if (vote.intValue() > 3)
writer.println("import "+packageName+";");
String importName = (String) enum.nextElement();
Integer vote = (Integer) imports.get(importName);
if (vote.intValue() >=
(importName.endsWith(".*")
? Decompiler.importPackageLimit
: Decompiler.importClassLimit))
writer.println("import "+importName+";");
}
writer.println("");
}
@ -94,25 +67,85 @@ public class JodeEnvironment extends LoadEnvironment {
public void doClass(String className)
{
Class clazz;
try {
clazz = Class.forName(className);
} catch (ClassNotFoundException ex) {
System.err.println("Class `"+className+"' 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 {
Identifier ident = Identifier.lookup(className);
error(ident.toString());
if (!classExists(ident)) {
error("`"+ident+"' not found");
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;
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()

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

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

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

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

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

@ -24,8 +24,6 @@ public class ConstOperator extends NoArgOperator {
public ConstOperator(Type type, String value) {
super(type);
if (type == Type.tString)
value = quoted(value);
this.value = value;
}
@ -37,29 +35,6 @@ public class ConstOperator extends NoArgOperator {
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) {
return (o instanceof ConstOperator) &&
((ConstOperator)o).value.equals(value);

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

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

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

@ -22,13 +22,11 @@ package jode;
public class NewArrayOperator extends SimpleOperator {
String baseTypeString;
public NewArrayOperator(Type arrayType, String baseTypeString,
int dimensions) {
public NewArrayOperator(Type arrayType, int dimensions) {
super(arrayType, 0, dimensions);
for (int i=0; i< dimensions; i++) {
operandTypes[i] = Type.tInt;
}
this.baseTypeString = baseTypeString;
}
public int getPriority() {
@ -40,11 +38,16 @@ public class NewArrayOperator extends SimpleOperator {
}
public String toString(String[] operands) {
StringBuffer result
= new StringBuffer("new ").append(baseTypeString);
for (int i=0; i< getOperandCount(); i++) {
result.append("[").append(operands[i]).append("]");
StringBuffer arrays = new StringBuffer();
Type flat = type;
int i = 0;
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;
}
/**
* Sets the return type of this operator.
*/
public void setType(Type type) {
this.type = type;
}
public String getOperatorString() {
return opString[operator];
}

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

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

@ -17,7 +17,6 @@
* $Id$
*/
package jode;
import sun.tools.java.*;
import java.util.Vector;
import java.util.Stack;
@ -370,9 +369,9 @@ public class ClassInterfacesType extends Type {
return sb.append("}").toString();
} else {
if (clazz != null)
return clazz.getName();
return env.classString(clazz);
else if (ifaces.length > 0)
return ifaces[0].getName();
return env.classString(ifaces[0]);
else
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;
/**
* 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
* explicit. <p>
*
@ -138,16 +138,31 @@ public class Type {
int index = type.indexOf(';');
if (index != type.length()-1)
return tError;
return tClass(type.substring(1, index).replace('/', '.'));
return tClass(type.substring(1, index));
}
throw new AssertError("Unknown type signature: "+type);
}
public static final Type tType(sun.tools.java.Type type) {
return tType(type.getTypeSignature());
public static final Type tType(Class clazz) {
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) {
clazzname = clazzname.replace(java.io.File.separatorChar, '.');
Object result = classHash.get(clazzname);
if (result == null) {
result = new ClassInterfacesType(clazzname);
@ -184,11 +199,11 @@ public class Type {
return tUnknown.createRangeType(type.getBottom());
}
public static Type tClassOrArray(sun.tools.java.Identifier ident) {
if (ident.toString().charAt(0) == '[')
return Type.tType(ident.toString());
public static Type tClassOrArray(String ident) {
if (ident.charAt(0) == '[')
return Type.tType(ident);
else
return Type.tClass(ident.toString());
return Type.tClass(ident);
}
public static void setEnvironment(JodeEnvironment e) {

Loading…
Cancel
Save