Much type improvements

git-svn-id: https://svn.code.sf.net/p/jode/code/trunk@58 379699f6-c40d-0410-875b-85095c16579e
stable
jochen 26 years ago
parent 671bd91c6f
commit d131840eec
  1. 32
      jode/jode/Decompiler.java
  2. 22
      jode/jode/bytecode/Opcodes.java
  3. 41
      jode/jode/decompiler/ClassAnalyzer.java
  4. 51
      jode/jode/decompiler/CodeAnalyzer.java
  5. 1
      jode/jode/decompiler/FieldAnalyzer.java
  6. 41
      jode/jode/decompiler/ImportHandler.java
  7. 22
      jode/jode/decompiler/LocalInfo.java
  8. 28
      jode/jode/decompiler/MethodAnalyzer.java
  9. 7
      jode/jode/decompiler/TabbedPrintWriter.java
  10. 4
      jode/jode/expr/ArrayLoadOperator.java
  11. 15
      jode/jode/expr/ArrayStoreOperator.java
  12. 3
      jode/jode/expr/BinaryOperator.java
  13. 6
      jode/jode/expr/CompareBinaryOperator.java
  14. 186
      jode/jode/expr/ComplexExpression.java
  15. 23
      jode/jode/expr/ConstOperator.java
  16. 4
      jode/jode/expr/ConstantArrayOperator.java
  17. 4
      jode/jode/expr/ConstructorOperator.java
  18. 3
      jode/jode/expr/Expression.java
  19. 4
      jode/jode/expr/GetFieldOperator.java
  20. 1
      jode/jode/expr/IIncOperator.java
  21. 25
      jode/jode/expr/InvokeOperator.java
  22. 5
      jode/jode/expr/LocalLoadOperator.java
  23. 12
      jode/jode/expr/LocalStoreOperator.java
  24. 2
      jode/jode/expr/NewArrayOperator.java
  25. 7
      jode/jode/expr/Operator.java
  26. 5
      jode/jode/expr/PutFieldOperator.java
  27. 16
      jode/jode/expr/StoreInstruction.java
  28. 4
      jode/jode/type/ArrayType.java
  29. 40
      jode/jode/type/ClassInterfacesType.java
  30. 10
      jode/jode/type/RangeType.java
  31. 18
      jode/jode/type/Type.java

@ -25,20 +25,34 @@ public class Decompiler {
public static boolean isTypeDebugging = false;
public static boolean isFlowDebugging = false;
public static boolean debugInOut = false;
public static boolean debugAnalyze = false;
public static boolean showLVT = false;
public static boolean doChecks = false;
public static boolean immediateOutput = false;
public static int importPackageLimit = 3;
public static int importClassLimit = 3;
public static void usage() {
System.err.println("use: jode [-v][-imm][-debug][-analyze][-flow]"
+"[-type][-inout][-lvt][-check]"
+"[-import pkglimit clslimit]"
+" class1 [class2 ...]");
}
public static void main(String[] params) {
JodeEnvironment env = new JodeEnvironment();
for (int i=0; i<params.length; i++) {
int i;
for (i=0; i<params.length && params[i].startsWith("-"); i++) {
if (params[i].equals("-v"))
isVerbose = true;
else if (params[i].equals("-imm"))
immediateOutput = true;
else if (params[i].equals("-debug"))
isDebugging = true;
else if (params[i].equals("-type"))
isTypeDebugging = true;
else if (params[i].equals("-analyze"))
debugAnalyze = true;
else if (params[i].equals("-flow"))
isFlowDebugging = true;
else if (params[i].equals("-inout"))
@ -50,8 +64,20 @@ public class Decompiler {
else if (params[i].equals("-import")) {
importPackageLimit = Integer.parseInt(params[++i]);
importClassLimit = Integer.parseInt(params[++i]);
} else
env.doClass(params[i]);
} else if (params[i].equals("--")) {
i++;
break;
} else {
if (!params[i].startsWith("-h"))
System.err.println("Unknown option: "+params[i]);
usage();
return;
}
}
if (i == params.length)
usage();
else
for (; i< params.length; i++)
env.doClass(params[i]);
}
}

@ -43,6 +43,14 @@ public abstract class Opcodes {
public final static Type SHORT_TYPE = Type.tShort;
public final static Type VOID_TYPE = Type.tVoid;
public final static Type types[][] = {
{BOOL_INT_TYPE, LONG_TYPE, FLOAT_TYPE, DOUBLE_TYPE, OBJECT_TYPE },
{ INT_TYPE, LONG_TYPE, FLOAT_TYPE, DOUBLE_TYPE, OBJECT_TYPE,
BYTEBOOL_TYPE, CHAR_TYPE, SHORT_TYPE },
{ BYTE_TYPE, CHAR_TYPE, SHORT_TYPE },
{ ALL_INT_TYPE, LONG_TYPE, FLOAT_TYPE, DOUBLE_TYPE, OBJECT_TYPE }
};
public static final int opc_nop = 0;
public static final int opc_aconst_null = 1;
public static final int opc_iconst_m1 = 2;
@ -246,17 +254,7 @@ public abstract class Opcodes {
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 },
{ INT_TYPE, LONG_TYPE, FLOAT_TYPE, DOUBLE_TYPE, OBJECT_TYPE,
BYTEBOOL_TYPE, CHAR_TYPE, SHORT_TYPE },
{ BYTE_TYPE, CHAR_TYPE, SHORT_TYPE },
{ ALL_INT_TYPE, LONG_TYPE, FLOAT_TYPE, DOUBLE_TYPE, OBJECT_TYPE }
};
public static FlowBlock createNormal(CodeAnalyzer ca,
int addr, int length,
Instruction instr)
@ -473,7 +471,7 @@ public abstract class Opcodes {
case opc_ixor: case opc_lxor:
return createNormal
(ca, addr, 1, new BinaryOperator
(types[3][(opcode - opc_iand)%2],
(types[0][(opcode - opc_iand)%2],
(opcode - opc_iand)/2 + Operator.AND_OP));
case opc_iinc: {
int local = stream.readUnsignedByte();
@ -586,7 +584,7 @@ public abstract class Opcodes {
}
case opc_ireturn: case opc_lreturn:
case opc_freturn: case opc_dreturn: case opc_areturn: {
Type retType = Type.tSubType(ca.getMethod().getReturnType());
Type retType = ca.getMethod().getReturnType();
return createBlock
(ca, addr, 1, new ReturnBlock(new NopOperator(retType)));
}

@ -18,7 +18,6 @@
*/
package jode;
import java.io.IOException;
import java.lang.reflect.*;
import gnu.bytecode.ClassType;
import gnu.bytecode.ConstantPool;
@ -29,7 +28,7 @@ import gnu.bytecode.CpoolValue2;
public class ClassAnalyzer implements Analyzer {
JodeEnvironment env;
Analyzer analyzers[];
Analyzer[] analyzers;
Class clazz;
ClassType classType;
ClassAnalyzer parent;
@ -49,7 +48,8 @@ public class ClassAnalyzer implements Analyzer {
}
public void analyze() {
int numFields = 0, i=0;
int numFields = 0;
int i = 0;
Field[] fields = clazz.getDeclaredFields();
Method[] methods = clazz.getDeclaredMethods();
@ -59,43 +59,49 @@ public class ClassAnalyzer implements Analyzer {
analyzers = new Analyzer[fields.length + methods.length
+ constrs.length + clazzes.length];
for (int j=0; j< clazzes.length; j++, i++) {
for (int j=0; j< clazzes.length; j++) {
analyzers[i] = new ClassAnalyzer(this, clazzes[j], env);
analyzers[i].analyze();
analyzers[i++].analyze();
}
for (int j=0; j< fields.length; j++, i++) {
for (int j=0; j< fields.length; j++) {
analyzers[i] = new FieldAnalyzer(this, fields[j], env);
analyzers[i].analyze();
analyzers[i++].analyze();
}
for (int j=0; j< constrs.length; j++, i++) {
for (int j=0; j< constrs.length; j++) {
analyzers[i] = new MethodAnalyzer(this, constrs[j], env);
analyzers[i].analyze();
analyzers[i++].analyze();
}
for (int j=0; j< methods.length; j++, i++) {
for (int j=0; j< methods.length; j++) {
analyzers[i] = new MethodAnalyzer(this, methods[j], env);
analyzers[i].analyze();
analyzers[i++].analyze();
}
env.useClass(clazz);
if (clazz.getSuperclass() != null)
env.useClass(clazz.getSuperclass());
Class[] interfaces = clazz.getInterfaces();
for (int j=0; j< interfaces.length; j++)
env.useClass(interfaces[j]);
}
public void dumpSource(TabbedPrintWriter writer) throws IOException
public void dumpSource(TabbedPrintWriter writer) throws java.io.IOException
{
// if (cdef.getSource() != null)
// writer.println("/* Original source: "+cdef.getSource()+" */");
String modif = Modifier.toString(clazz.getModifiers());
String modif = Modifier.toString(clazz.getModifiers()
& ~Modifier.SYNCHRONIZED);
if (modif.length() > 0)
writer.print(modif + " ");
writer.print((clazz.isInterface())?"interface ":"class ");
writer.print(clazz.isInterface() ? "interface " : "class ");
writer.println(env.classString(clazz));
writer.tab();
Class superClazz = clazz.getSuperclass();
if (superClazz != null &&
superClazz != new Object().getClass()) {
if (superClazz != null && superClazz != Object.class) {
writer.println("extends "+env.classString(superClazz));
}
Class interfaces[] = clazz.getInterfaces();
Class[] interfaces = clazz.getInterfaces();
if (interfaces.length > 0) {
writer.print("implements ");
for (int i=0; i < interfaces.length; i++) {
@ -191,4 +197,3 @@ public class ClassAnalyzer implements Analyzer {
}
}

@ -24,6 +24,8 @@ import jode.flow.StructuredBlock;
import jode.flow.RawTryCatchBlock;
import java.util.Stack;
import java.util.Vector;
import java.util.Enumeration;
import java.io.DataInputStream;
import java.io.ByteArrayInputStream;
import java.io.IOException;
@ -39,6 +41,7 @@ public class CodeAnalyzer implements Analyzer {
MethodAnalyzer method;
public JodeEnvironment env;
Vector allLocals = new Vector();
jode.flow.VariableSet param;
LocalVariableTable lvt;
@ -72,36 +75,32 @@ public class CodeAnalyzer implements Analyzer {
} catch (IOException ex) {
throw new ClassFormatError(ex.toString());
}
for (int addr=0; addr<instr.length; ) {
instr[addr].resolveJumps(instr);
addr = instr[addr].getNextAddr();
}
methodHeader = instr[0];
methodHeader.makeStartBlock();
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 + 2])) {
FlowBlock startBlock = instr[handlers[i + 0]];
tryBlock = ((RawTryCatchBlock)tryBlock).getTryBlock();
}
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 + 1]]),
new Jump(instr[handlers[i + 2]]));
instr[handlers[i + 0]] =
new RawTryCatchBlock(type,
new Jump(instr[handlers[i + 1]]),
new Jump(instr[handlers[i + 2]])
).chainTo(instr[handlers[i + 0]]);
}
for (int addr=0; addr<instr.length; ) {
instr[addr].resolveJumps(instr);
addr = instr[addr].getNextAddr();
}
methodHeader = instr[0];
methodHeader.makeStartBlock();
int paramCount = method.getParamCount();
param = new jode.flow.VariableSet();
for (int i=0; i<paramCount; i++)
@ -124,10 +123,12 @@ public class CodeAnalyzer implements Analyzer {
}
public LocalInfo getLocalInfo(int addr, int slot) {
if (lvt != null)
return lvt.getLocal(slot).getInfo(addr);
else
return new LocalInfo(slot);
LocalInfo li = (lvt != null)
? lvt.getLocal(slot).getInfo(addr)
: new LocalInfo(slot);
if (!allLocals.contains(li))
allLocals.addElement(li);
return li;
}
public LocalInfo getParamInfo(int slot) {
@ -137,6 +138,12 @@ public class CodeAnalyzer implements Analyzer {
public void analyze()
{
methodHeader.analyze();
Enumeration enum = allLocals.elements();
while (enum.hasMoreElements()) {
LocalInfo li = (LocalInfo)enum.nextElement();
if (!li.isShadow())
li.getType().useType();
}
}
public void useClass(Class clazz)

@ -36,6 +36,7 @@ public class FieldAnalyzer implements Analyzer {
}
public void analyze() {
Type.tType(field.getType()).useType();
constantValue = 0;
Attribute attribute =
Attribute.get(clazz.classType.getField(field.getName()),

@ -38,7 +38,6 @@ public class JodeEnvironment {
return classPath.getFile(clazz.getName().
replace('.', java.io.File.separatorChar)
+".class");
}
public void dumpHeader(TabbedPrintWriter writer)
@ -52,11 +51,20 @@ public class JodeEnvironment {
while (enum.hasMoreElements()) {
String importName = (String) enum.nextElement();
Integer vote = (Integer) imports.get(importName);
if (vote.intValue() >=
(importName.endsWith(".*")
? Decompiler.importPackageLimit
: Decompiler.importClassLimit))
writer.println("import "+importName+";");
if (!importName.endsWith(".*")) {
if (vote.intValue() < Decompiler.importClassLimit)
continue;
int delim = importName.lastIndexOf(".");
Integer pkgvote = (Integer)
imports.get(importName.substring(0, delim)+".*");
if (pkgvote.intValue() >= Decompiler.importPackageLimit)
continue;
} else {
if (vote.intValue() < Decompiler.importPackageLimit)
continue;
}
writer.println("import "+importName+";");
}
writer.println("");
}
@ -109,14 +117,19 @@ public class JodeEnvironment {
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);
Integer i = (Integer) imports.get(name);
if (i== null) {
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 = new Integer(1);
} else
i = new Integer(i.intValue()+1);
imports.put(name, i);
}
}

@ -73,10 +73,22 @@ public class LocalInfo {
} else {
if (this != li) {
shadow = li;
// System.err.println("combining "+name+"("+type+") and "
// +li.name+"("+li.type+")");
li.setType(type);
boolean needTypeUpdate = !li.type.equals(type);
java.util.Enumeration enum = operators.elements();
while (enum.hasMoreElements()) {
shadow.operators.addElement(enum.nextElement());
LocalVarOperator lvo =
(LocalVarOperator) enum.nextElement();
if (needTypeUpdate) {
// System.err.println("updating "+lvo+" in "+((Expression)lvo).parent);
lvo.updateType();
}
shadow.operators.addElement(lvo);
}
/* Clear unused fields, to allow garbage collection.
@ -151,11 +163,15 @@ public class LocalInfo {
public Type setType(Type newType) {
LocalInfo li = getLocalInfo();
newType = li.type.intersection(newType);
// System.err.println(getName()+" setType, new: "+newType+" old: "+li.type);
if (!li.type.equals(newType)) {
li.type = newType;
java.util.Enumeration enum = li.operators.elements();
while (enum.hasMoreElements())
((LocalVarOperator)enum.nextElement()).updateType();
while (enum.hasMoreElements()) {
LocalVarOperator lvo = (LocalVarOperator) enum.nextElement();
// System.err.println("updating "+lvo+" in "+((Expression)lvo).parent);
lvo.updateType();
}
}
return li.type;
}

@ -103,19 +103,37 @@ public class MethodAnalyzer implements Analyzer {
clazz.setName("this");
offset++;
}
Class[] paramTypes = isConstructor
? constr.getParameterTypes() : method.getParameterTypes();
for (int i=0; i< paramTypes.length; i++)
code.getParamInfo(offset+i).setType(Type.tType(paramTypes[i]));
// We do the code.analyze() in dumpSource, to get
// immediate output.
Class[] exceptions = isConstructor
? constr.getExceptionTypes() : method.getExceptionTypes();
for (int i= 0; i< exceptions.length; i++)
env.useClass(exceptions[i]);
if (!isConstructor)
getReturnType().useType();
if (!Decompiler.immediateOutput) {
if (Decompiler.isVerbose)
System.err.print((isConstructor
? "<init>" : method.getName())+": ");
code.analyze();
if (Decompiler.isVerbose)
System.err.println("");
}
}
public void dumpSource(TabbedPrintWriter writer)
throws java.io.IOException
{
if (code != null) {
if (Decompiler.immediateOutput && code != null) {
// We do the code.analyze() here, to get
// immediate output.
if (Decompiler.isVerbose)
System.err.print((isConstructor
? "<init>" : method.getName())+": ");
@ -136,7 +154,7 @@ public class MethodAnalyzer implements Analyzer {
if (isConstructor)
writer.print(env.classString(classAnalyzer.clazz));
else
writer.print(Type.tType(method.getReturnType()).toString()
writer.print(getReturnType().toString()
+ " " + method.getName());
writer.print("(");
Class[] paramTypes = isConstructor

@ -33,6 +33,13 @@ public class TabbedPrintWriter {
atbol = true;
}
public TabbedPrintWriter (Writer os, String tabstr) {
pw = new PrintWriter(os);
this.tabstr=tabstr;
indent = new StringBuffer();
atbol = true;
}
public void tab() {
indent.append(tabstr);
}

@ -48,7 +48,9 @@ public class ArrayLoadOperator extends SimpleOperator {
public void setOperandType(Type[] t) {
super.setOperandType(t);
if (operandTypes[0] instanceof ArrayType)
if (operandTypes[0] == Type.tError)
type = Type.tError;
else if (operandTypes[0] instanceof ArrayType)
type = type.intersection
(((ArrayType)operandTypes[0]).getElementType());
else

@ -47,15 +47,6 @@ public class ArrayStoreOperator extends StoreInstruction {
return 0;
}
/**
* Sets the type of the lvalue (and rvalue).
* @return true since the operand types changed
*/
public boolean setLValueType(Type type) {
this.lvalueType = type;
return true;
}
public Type getLValueOperandType(int i) {
if (i == 0)
return Type.tArray(lvalueType);
@ -66,10 +57,10 @@ public class ArrayStoreOperator extends StoreInstruction {
public void setLValueOperandType(Type[] t) {
indexType = indexType.intersection(t[1]);
Type arrayType = t[0].intersection(Type.tArray(lvalueType));
if (arrayType instanceof ArrayType)
if (arrayType == Type.tError)
lvalueType = Type.tError;
else
lvalueType = ((ArrayType)arrayType).getElementType();
else
throw new AssertError("No Array type: "+arrayType);
}
public String getLValueString(String[] operands) {

@ -66,8 +66,7 @@ public class BinaryOperator extends Operator {
public void setOperandType(Type[] inputTypes) {
operandType = operandType
.intersection(inputTypes[0])
.intersection(inputTypes[1]);
.intersection(inputTypes[0]).intersection(inputTypes[1]);
type = operandType;
}

@ -45,10 +45,8 @@ public class CompareBinaryOperator extends SimpleOperator {
public void setOperandType(Type[] inputTypes) {
super.setOperandType(inputTypes);
Type operandType =
Type.tSubType(Type.tSuperType(operandTypes[0])
.intersection(Type.tSuperType(operandTypes[1])));
operandTypes[0] = operandTypes[1] = operandType;
operandTypes[0] = operandTypes[1] =
operandTypes[0].intersection(operandTypes[1]);
}
public boolean equals(Object o) {

@ -25,24 +25,16 @@ public class ComplexExpression extends Expression {
public ComplexExpression(Operator op, Expression[] sub) {
super(Type.tUnknown);
if (sub.length != op.getOperandCount())
throw new AssertError ("Operand count mismatch: "+
sub.length + " != " +
op.getOperandCount());
operator = op;
operator.parent = this;
subExpressions = sub;
operator.setExpression(this);
if (subExpressions.length != op.getOperandCount())
throw new AssertError ("Operand count mismatch: "+
subExpressions.length + " != " +
op.getOperandCount());
if (subExpressions.length > 0) {
Type types[] = new Type[subExpressions.length];
for (int i=0; i < types.length; i++) {
subExpressions[i].parent = this;
types[i] = subExpressions[i].getType();
}
operator.setOperandType(types);
updateSubTypes();
}
this.type = operator.getType();
for (int i=0; i< subExpressions.length; i++)
subExpressions[i].parent = this;
updateType();
}
public int getOperandCount() {
@ -74,8 +66,7 @@ public class ComplexExpression extends Expression {
Operator negop =
new UnaryOperator(Type.tBoolean, Operator.LOG_NOT_OP);
Expression[] e = { this };
return new ComplexExpression(negop, e);
return new ComplexExpression(negop, new Expression[] { this });
}
public Expression tryToCombine(Expression e) {
@ -118,18 +109,49 @@ public class ComplexExpression extends Expression {
void updateSubTypes() {
for (int i=0; i < subExpressions.length; i++) {
subExpressions[i].setType(operator.getOperandType(i));
if (i == 0 && operator instanceof ArrayStoreOperator) {
/* No rule without exception:
* We can always use tSubType, except for the
* array operand of an array store instruction.
*/
subExpressions[i].setType(operator.getOperandType(i));
} else
subExpressions[i].setType
(Type.tSubType(operator.getOperandType(i)));
}
}
public void updateType() {
updateSubTypes();
if (subExpressions.length > 0) {
Type types[] = new Type[subExpressions.length];
for (int i=0; i < types.length; i++) {
types[i] = subExpressions[i].getType();
while (true) {
boolean changed = false;
updateSubTypes();
for (int i=0; i < types.length; i++) {
if (i == 0 && operator instanceof ArrayStoreOperator) {
/* No rule without exception:
* We can always use tSuperType, except for the
* array operand of an array store instruction.
*/
types[i] = subExpressions[i].getType();
} else
types[i] = Type.tSuperType
(subExpressions[i].getType());
types[i] =
types[i].intersection(operator.getOperandType(i));
if (!types[i].equals(operator.getOperandType(i))) {
if (Decompiler.isTypeDebugging)
System.err.println("change in "+this+": "
+operator.getOperandType(i)
+"->"+types[i]);
changed = true;
}
}
if (changed)
operator.setOperandType(types);
else
break;
}
operator.setOperandType(types);
}
setType(operator.getType());
}
@ -140,6 +162,8 @@ public class ComplexExpression extends Expression {
type = newType;
operator.setType(type);
updateSubTypes();
if (parent != null)
parent.updateType();
}
}
@ -151,14 +175,22 @@ public class ComplexExpression extends Expression {
String[] expr = new String[subExpressions.length];
for (int i=0; i<subExpressions.length; i++) {
expr[i] = subExpressions[i].
toString(operator.getOperandPriority(i));
toString(Decompiler.isTypeDebugging
? 700 /* type cast priority */
: operator.getOperandPriority(i));
if (Decompiler.isTypeDebugging) {
expr[i] = "("+
(operator.getOperandType(i)
.equals(subExpressions[i].getType())
? "" : ""+subExpressions[i].getType()+"->")
+ operator.getOperandType(i)+") "+expr[i];
if (700 < operator.getOperandPriority(i))
expr[i] = "(" + expr[i] + ")";
}
else if (subExpressions[i].getType() == Type.tError)
expr[i] = "(/*type error */" + expr[i]+")";
}
String result = operator.toString(expr);
if (Decompiler.isTypeDebugging)
result = "("+operator.getType()+") ("+result+")";
else if (operator.getType() == Type.tError)
result = "(/*type error */" + result+")";
return result;
return operator.toString(expr);
}
public boolean equals(Object o) {
@ -186,6 +218,7 @@ public class ComplexExpression extends Expression {
if (operator instanceof InvokeOperator
&& ((field = ((InvokeOperator)operator).getField())
.getCpoolClass().getName().getString()
.replace(java.io.File.separatorChar, '.')
.equals("java.lang.StringBuffer"))
&& !((InvokeOperator)operator).isStatic() &&
field.getNameAndType().getName().getString().equals("append") &&
@ -199,9 +232,9 @@ public class ComplexExpression extends Expression {
subExpressions[1].getType().isOfType(Type.tString))
return subExpressions[1];
Expression[] exprs = { e,
(Expression)subExpressions[1].simplify() };
return new ComplexExpression(new StringAddOperator(), exprs);
return new ComplexExpression
(new StringAddOperator(), new Expression[]
{ e, (Expression)subExpressions[1].simplify() });
}
if (operator instanceof ConstructorOperator &&
operator.getType().isOfType(Type.tStringBuffer)) {
@ -224,45 +257,51 @@ public class ComplexExpression extends Expression {
(ConstOperator) subExpressions[1].getOperator();
ConstOperator c2 =
(ConstOperator) subExpressions[2].getOperator();
if (c1.getValue().equals("true") &&
c2.getValue().equals("false"))
if (c1.getValue().equals("1") &&
c2.getValue().equals("0"))
return subExpressions[0].simplify();
if (c2.getValue().equals("true") &&
c1.getValue().equals("false"))
if (c2.getValue().equals("1") &&
c1.getValue().equals("0"))
return subExpressions[0].negate().simplify();
}
}
// if ((operator instanceof AssignOperator ||
// operator instanceof StoreInstruction) &&
// subExpressions[subExpressions.length-1]
// .operator instanceof ConstOperator) {
// StoreInstruction store;
// if (operator instanceof AssignOperator)
// store = ((AssignOperator)operator).getStore();
// else
// store = (StoreInstruction)operator;
else if ((operator instanceof AssignOperator ||
operator instanceof StoreInstruction) &&
subExpressions[subExpressions.length-1]
.getOperator() instanceof ConstOperator) {
StoreInstruction store;
if (operator instanceof AssignOperator)
store = ((AssignOperator)operator).getStore();
else
store = (StoreInstruction)operator;
ConstOperator one = (ConstOperator)
subExpressions[subExpressions.length-1].getOperator();
// ConstOperator one = (ConstOperator)
// subExpressions[subExpressions.length-1].operator;
if ((operator.getOperatorIndex() ==
operator.OPASSIGN_OP+operator.ADD_OP ||
operator.getOperatorIndex() ==
operator.OPASSIGN_OP+operator.NEG_OP) &&
(one.getValue().equals("1") ||
one.getValue().equals("-1"))) {
// if ((operator.getOperatorIndex() ==
// operator.OPASSIGN_OP+operator.ADD_OP ||
// operator.getOperatorIndex() ==
// operator.OPASSIGN_OP+operator.NEG_OP) &&
// (one.getValue().equals("1") ||
// one.getValue().equals("-1"))) {
int op = ((operator.getOperatorIndex() ==
operator.OPASSIGN_OP+operator.ADD_OP) ==
one.getValue().equals("1"))?
operator.INC_OP : operator.DEC_OP;
// int op = ((operator.getOperatorIndex() ==
// operator.OPASSIGN_OP+operator.ADD_OP) ==
// one.getValue().equals("1"))?
// operator.INC_OP : operator.DEC_OP;
Operator ppfixop = new PrePostFixOperator
(store.getLValueType(), op, store,
operator instanceof StoreInstruction);
if (subExpressions.length == 1)
return ppfixop.simplify();
// return new PostFixOperator
// (store.getType(), op, store,
// operator instanceof StoreInstruction).simplify();
// }
// }
if (operator instanceof CompareUnaryOperator &&
operator = ppfixop;
ppfixop.parent = this;
}
}
else if (operator instanceof CompareUnaryOperator &&
subExpressions[0].getOperator() instanceof CompareToIntOperator) {
CompareBinaryOperator newOp = new CompareBinaryOperator
@ -277,7 +316,7 @@ public class ComplexExpression extends Expression {
} else
return newOp.simplify();
}
if (operator instanceof CompareUnaryOperator &&
else if (operator instanceof CompareUnaryOperator &&
operator.getOperandType(0).isOfType(Type.tBoolean)) {
/* xx == false */
if (operator.getOperatorIndex() == operator.EQUALS_OP)
@ -286,42 +325,39 @@ public class ComplexExpression extends Expression {
if (operator.getOperatorIndex() == operator.NOTEQUALS_OP)
return subExpressions[0].simplify();
}
if (operator instanceof InvokeOperator
else if (operator instanceof InvokeOperator
&& (((InvokeOperator)operator).getField()
.getNameAndType().getName().getString().equals("toString"))
&& !((InvokeOperator)operator).isStatic()
&& (((InvokeOperator)operator).getField()
.getCpoolClass().getName().getString()
.replace(java.io.File.separatorChar, '.')
.equals("java.lang.StringBuffer"))
&& subExpressions.length == 1) {
Instruction simple = subExpressions[0].simplifyStringBuffer();
if (simple != null)
return simple;
}
if (operator instanceof InvokeOperator
else if (operator instanceof InvokeOperator
&& (((InvokeOperator)operator).getField()
.getNameAndType().getName().getString().equals("valueOf"))
&& ((InvokeOperator)operator).isStatic()
&& (((InvokeOperator)operator).getField()
.getCpoolClass().getName().getString()
.replace(java.io.File.separatorChar, '.')
.equals("java.lang.String"))
&& subExpressions.length == 1) {
if (subExpressions[0].getType() == Type.tString)
return subExpressions[0].simplify();
else {
Expression[] exprs = {
emptyString,
(Expression) subExpressions[0].simplify()
};
return new ComplexExpression(new StringAddOperator(), exprs);
}
return new ComplexExpression
(new StringAddOperator(), new Expression[]
{ emptyString, (Expression) subExpressions[0].simplify() });
}
for (int i=0; i< subExpressions.length; i++) {
subExpressions[i] = (Expression) subExpressions[i].simplify();
subExpressions[i].parent = this;
}
return this;
}
}

@ -46,6 +46,29 @@ public class ConstOperator extends NoArgOperator {
return "false";
else if (value.equals("1"))
return "true";
} else if (parent != null) {
int opindex = parent.getOperator().getOperatorIndex();
if (opindex >= OPASSIGN_OP + ADD_OP
&& opindex < OPASSIGN_OP + ASSIGN_OP)
opindex -= OPASSIGN_OP;
if (opindex >= AND_OP && opindex < AND_OP + 3) {
/* For bit wise and/or/xor change representation.
*/
if (type.isOfType(Type.tUInt)) {
int i = Integer.parseInt(value);
if (i < -1)
return "~0x"+Integer.toHexString(-i-1);
else
return "0x"+Integer.toHexString(i);
} else if (type.equals(Type.tLong)) {
long l = Long.parseLong(value);
if (l < -1)
return "~0x"+Long.toHexString(-l-1);
else
return "0x"+Long.toHexString(l);
}
}
}
return value;
}

@ -24,7 +24,7 @@ public class ConstantArrayOperator extends SimpleOperator {
public ConstantArrayOperator(Type type, int size) {
super(type, 0, size);
for (int i=0; i< size; i++)
operandTypes[i] = Type.tSubType(((ArrayType)type).getElementType());
operandTypes[i] = ((ArrayType)type).getElementType();
}
public int getPriority() {
@ -37,7 +37,7 @@ public class ConstantArrayOperator extends SimpleOperator {
public String toString(String[] operands) {
StringBuffer result
= new StringBuffer("{");
= new StringBuffer("new "+type+" {");
for (int i=0; i< getOperandCount(); i++) {
if (i>0)
result.append(", ");

@ -48,8 +48,8 @@ public class ConstructorOperator extends Operator {
public Type getOperandType(int i) {
if (i == 0)
return Type.tSubType(type);
return Type.tSubType(methodType.getArgumentTypes()[i-1]);
return type;
return methodType.getArgumentTypes()[i-1];
}
public void setOperandType(Type types[]) {

@ -36,8 +36,7 @@ public abstract class Expression extends Instruction {
public Expression negate() {
Operator negop =
new UnaryOperator(Type.tBoolean, Operator.LOG_NOT_OP);
Expression[] e = { this };
return new ComplexExpression(negop, e);
return new ComplexExpression(negop, new Expression[] { this });
}
public Expression tryToCombine(Expression e) {

@ -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.getCpoolClass()
.getName().getString()));
return Type.tClass(field.getCpoolClass()
.getName().getString());
}
public void setOperandType(Type types[]) {

@ -28,6 +28,7 @@ implements LocalVarOperator {
super(Type.tVoid, operator);
this.local = local;
this.value = value;
local.setType(Type.tUInt);
local.setOperator(this);
}

@ -75,10 +75,10 @@ public final class InvokeOperator extends Operator {
public Type getOperandType(int i) {
if (!staticFlag) {
if (i == 0)
return Type.tSubType(getClassType());
return getClassType();
i--;
}
return Type.tSubType(methodType.getArgumentTypes()[i]);
return methodType.getArgumentTypes()[i];
}
public void setOperandType(Type types[]) {
@ -97,19 +97,14 @@ public final class InvokeOperator extends Operator {
? ""
: 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] ));
? ((specialFlag &&
(field.getCpoolClass().getName().getString()
.replace(java.io.File.separatorChar, '.')
.equals(codeAnalyzer.getClazz()
.getSuperclass().getName())))
? "super"
: "")
: operands[0]);
int arg = staticFlag ? 0 : 1;
String method;

@ -26,6 +26,7 @@ implements LocalVarOperator {
public LocalLoadOperator(Type type, LocalInfo local) {
super(type, "");
this.local = local;
local.setType(type);
local.setOperator(this);
}
@ -47,6 +48,10 @@ implements LocalVarOperator {
}
public void updateType() {
if (Decompiler.isTypeDebugging)
System.err.println("local "+local.getName()+" changed: "
+type+" to "+local.getType()
+" in "+parent);
super.setType(local.getType());
if (parent != null)
parent.updateType();

@ -26,6 +26,7 @@ implements LocalVarOperator {
public LocalStoreOperator(Type lvalueType, LocalInfo local, int operator) {
super(lvalueType, operator);
this.local = local;
local.setType(lvalueType);
local.setOperator(this);
}
@ -47,20 +48,13 @@ implements LocalVarOperator {
}
public Type getLValueType() {
// System.err.println("LocalStore.getType of "+local.getName()+": "+local.getType());
return local.getType();
}
public boolean setLValueType(Type type) {
// System.err.println("LocalStore.setType of "+local.getName()+": "+local.getType());
return super.setLValueType
(local.setType(Type.tSuperType(type)));
public void setLValueType(Type type) {
local.setType(type);
}
// public int getSlot() {
// return slot;
// }
public boolean matches(Operator loadop) {
return loadop instanceof LocalLoadOperator &&
((LocalLoadOperator)loadop).getLocalInfo().getLocalInfo()

@ -25,7 +25,7 @@ public class NewArrayOperator extends SimpleOperator {
public NewArrayOperator(Type arrayType, int dimensions) {
super(arrayType, 0, dimensions);
for (int i=0; i< dimensions; i++) {
operandTypes[i] = Type.tInt;
operandTypes[i] = Type.tUInt;
}
}

@ -45,8 +45,7 @@ public abstract class Operator extends Expression {
};
protected int operator;
protected Expression expression = null;
Operator (Type type, int op) {
super(type);
this.operator = op;
@ -54,10 +53,6 @@ public abstract class Operator extends Expression {
throw new AssertError("type == null");
}
public void setExpression(Expression expr) {
expression = expr;
}
public Operator getOperator() {
return this;
}

@ -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.getCpoolClass()
.getName().getString()));
return Type.tClass(field.getCpoolClass()
.getName().getString());
}
public void setLValueOperandType(Type[] t) {
@ -71,6 +71,7 @@ public class PutFieldOperator extends StoreInstruction {
String object;
if (staticFlag) {
if (field.getCpoolClass().getName().getString()
.replace(java.io.File.separatorChar, '.')
.equals(codeAnalyzer.getClazz().getName()))
return field.getNameAndType().getName().getString();
object = codeAnalyzer.getTypeString

@ -26,7 +26,7 @@ public abstract class StoreInstruction extends Operator {
public StoreInstruction(Type type, int operator) {
super(Type.tVoid, operator);
lvalueType = Type.tSubType(type);
lvalueType = type;
lvCasts = lvalueType.toString();
}
@ -42,11 +42,9 @@ public abstract class StoreInstruction extends Operator {
/**
* Sets the type of the lvalue (and rvalue).
* @return true if the operand types changed
*/
public boolean setLValueType(Type type) {
this.lvalueType = type;
return false;
public void setLValueType(Type type) {
lvalueType = lvalueType.intersection(type);
}
public abstract String getLValueString(String[] operands);
@ -64,16 +62,16 @@ public abstract class StoreInstruction extends Operator {
public Type getOperandType(int i) {
if (i == getLValueOperandCount())
return Type.tSubType(getLValueType());
return getLValueType();
else
return getLValueOperandType(i);
}
public void setOperandType(Type[] t) {
if (getLValueOperandCount() > 0)
int count = getLValueOperandCount();
if (count > 0)
setLValueOperandType(t);
setLValueType(lvalueType.intersection
(Type.tSuperType(t[getLValueOperandCount()])));
setLValueType(t[count]);
}
public int getOperandCount() {

@ -101,6 +101,10 @@ public class ArrayType extends Type {
: tError;
}
public boolean isClassType() {
return elementType.isClassType();
}
/**
* Marks this type as used, so that the class is imported.
*/

@ -37,16 +37,15 @@ public class ClassInterfacesType extends Type {
Class clazz;
Class ifaces[];
public final static Class cObject = new Object().getClass();
public final static Class cObject = Object.class;
public ClassInterfacesType(String clazzName) {
super(TC_CLASS);
try {
Class clazz = Class.forName(clazzName);
if (clazz.isInterface()) {
this.clazz = cObject;
ifaces = new Class[1];
ifaces[0] = clazz;
this.clazz = null;
ifaces = new Class[] {clazz};
} else {
this.clazz = clazz;
ifaces = new Class[0];
@ -59,9 +58,8 @@ public class ClassInterfacesType extends Type {
public ClassInterfacesType(Class clazz) {
super(TC_CLASS);
if (clazz.isInterface()) {
this.clazz = cObject;
ifaces = new Class[1];
ifaces[0] = clazz;
this.clazz = null;
ifaces = new Class[] { clazz };
} else {
this.clazz = clazz;
ifaces = new Class[0];
@ -172,8 +170,7 @@ public class ClassInterfacesType extends Type {
&& bottom.ifaces[0] == ifaces.elementAt(0))
return bottom;
Class[] ifaceArray =
new Class[ifaces.size()];
Class[] ifaceArray = new Class[ifaces.size()];
ifaces.copyInto(ifaceArray);
return tRange(bottom, create(clazz, ifaceArray));
}
@ -322,8 +319,9 @@ public class ClassInterfacesType extends Type {
iface_loop:
while (!allIfaces.isEmpty()) {
Class iface = (Class) allIfaces.pop();
if (clazz != null && implementedBy(iface, clazz))
/* We can skip this, as clazz does already imply it.
if ((clazz != null && implementedBy(iface, clazz))
|| ifaces.contains(iface))
/* We can skip this, as clazz or ifaces already imply it.
*/
continue iface_loop;
@ -351,6 +349,18 @@ public class ClassInterfacesType extends Type {
return create(clazz, ifaceArray);
}
/**
* Marks this type as used, so that the class is imported.
*/
public void useType() {
if (!jode.Decompiler.isTypeDebugging) {
if (clazz != null && clazz != cObject)
env.useClass(clazz);
else if (ifaces.length > 0)
env.useClass(ifaces[0]);
}
}
public String toString()
{
if (jode.Decompiler.isTypeDebugging) {
@ -368,15 +378,21 @@ public class ClassInterfacesType extends Type {
}
return sb.append("}").toString();
} else {
if (clazz != null)
if (clazz != null && clazz != cObject)
return env.classString(clazz);
else if (ifaces.length > 0)
return env.classString(ifaces[0]);
else if (clazz == cObject)
return env.classString(clazz);
else
return "{<error>}";
}
}
public boolean isClassType() {
return true;
}
public boolean equals(Object o) {
if (o == this)
return true;

@ -82,14 +82,20 @@ public class RangeType extends Type {
*/
public void useType() {
/* The topType will be printed */
topType.useType();
if (topType.isClassType() || bottomType == tUnknown)
topType.useType();
else
bottomType.useType();
}
public String toString()
{
if (jode.Decompiler.isTypeDebugging)
return "<" + bottomType + "-" + topType + ">";
return topType.toString();
if (topType.isClassType() || bottomType == tUnknown)
return topType.toString();
else
return bottomType.toString();
}
public boolean equals(Object o) {

@ -284,7 +284,7 @@ public class Type {
: (type.typecode <= typecode) ? type
: (type.typecode <= TC_INT
|| type.typecode == TC_BOOLINT) ? this
: (this == tByte && type == tBoolByte) ? this
: (type == tBoolByte) ? tByte
: tError)
: (typecode == TC_BOOLINT)
@ -384,7 +384,7 @@ public class Type {
? tRange(bottomType, this)
: (bottomType.typecode == TC_BOOLBYTE
&& bottomType == tByte)
&& this == tByte)
? tByte
: (bottomType.typecode == TC_BOOLINT
@ -428,6 +428,13 @@ public class Type {
return result;
}
/**
* Checks if this type represents a class or an array of a class
*/
public boolean isClassType() {
return false;
}
/**
* Check if this and &lt;unknown -- type&rt; are not disjunct.
* @param type a simple type; this mustn't be a range type.
@ -439,6 +446,13 @@ public class Type {
// return (getSpecializedType(type).equals(type));
}
/**
* Marks this type as used, so that the class is imported.
*/
public void useType() {
/* No action needed for simple types */
}
public String toString() {
switch (typecode) {
case TC_BOOLINT:

Loading…
Cancel
Save