*** empty log message ***

git-svn-id: https://svn.code.sf.net/p/jode/code/trunk@117 379699f6-c40d-0410-875b-85095c16579e
stable
jochen 26 years ago
parent efbdca398f
commit 0192af7705
  1. 44
      jode/jode/decompiler/ClassAnalyzer.java
  2. 19
      jode/jode/decompiler/CodeAnalyzer.java
  3. 18
      jode/jode/decompiler/FieldAnalyzer.java
  4. 91
      jode/jode/decompiler/ImportHandler.java
  5. 25
      jode/jode/decompiler/LocalInfo.java
  6. 39
      jode/jode/decompiler/MethodAnalyzer.java
  7. 17
      jode/jode/expr/ComplexExpression.java
  8. 23
      jode/jode/expr/ConstOperator.java
  9. 11
      jode/jode/expr/ConstantArrayOperator.java
  10. 7
      jode/jode/expr/Expression.java
  11. 2
      jode/jode/expr/GetFieldOperator.java
  12. 4
      jode/jode/expr/LocalLoadOperator.java
  13. 10
      jode/jode/expr/PutFieldOperator.java
  14. 6
      jode/jode/expr/StoreInstruction.java
  15. 1
      jode/jode/flow/CaseBlock.java
  16. 38
      jode/jode/flow/CompleteSynchronized.java
  17. 12
      jode/jode/flow/InstructionBlock.java
  18. 12
      jode/jode/flow/SequentialBlock.java
  19. 17
      jode/jode/flow/StructuredBlock.java
  20. 7
      jode/jode/flow/SynchronizedBlock.java
  21. 4
      jode/jode/flow/TransformExceptionHandlers.java
  22. 10
      jode/jode/flow/VariableSet.java

@ -27,10 +27,14 @@ import gnu.bytecode.CpoolEntry;
import gnu.bytecode.CpoolValue1; import gnu.bytecode.CpoolValue1;
import gnu.bytecode.CpoolValue2; import gnu.bytecode.CpoolValue2;
import gnu.bytecode.CpoolString; import gnu.bytecode.CpoolString;
import jode.flow.TransformConstructors;
public class ClassAnalyzer implements Analyzer { public class ClassAnalyzer implements Analyzer {
JodeEnvironment env; JodeEnvironment env;
Analyzer[] analyzers; Analyzer[] analyzers;
MethodAnalyzer staticConstructor;
MethodAnalyzer[] constructors;
Class clazz; Class clazz;
gnu.bytecode.ClassType classType; gnu.bytecode.ClassType classType;
ClassAnalyzer parent; ClassAnalyzer parent;
@ -48,7 +52,18 @@ public class ClassAnalyzer implements Analyzer {
ex.printStackTrace(); ex.printStackTrace();
} }
} }
public boolean setFieldInitializer(String fieldName, Expression expr) {
for (int i=0; i< analyzers.length; i++) {
if (analyzers[i] instanceof FieldAnalyzer) {
FieldAnalyzer field = (FieldAnalyzer) analyzers[i];
if (field.getName().equals(fieldName))
return field.setInitializer(expr);
}
}
return false;
}
public void analyze() { public void analyze() {
int numFields = 0; int numFields = 0;
int i = 0; int i = 0;
@ -57,17 +72,34 @@ public class ClassAnalyzer implements Analyzer {
analyzers = new Analyzer[fields.length + analyzers = new Analyzer[fields.length +
classType.getMethodCount()]; classType.getMethodCount()];
for (int j=0; j< fields.length; j++) { for (int j=0; j< fields.length; j++) {
analyzers[i] = new FieldAnalyzer(this, fields[j], env); analyzers[i] = new FieldAnalyzer(this, fields[j], env);
analyzers[i++].analyze(); analyzers[i++].analyze();
} }
staticConstructor = null;
java.util.Vector constrVector = new java.util.Vector();
for (gnu.bytecode.Method method = classType.getMethods(); for (gnu.bytecode.Method method = classType.getMethods();
method != null; method = method.getNext()) { method != null; method = method.getNext()) {
analyzers[i] = new MethodAnalyzer(this, method, env); MethodAnalyzer analyzer = new MethodAnalyzer(this, method, env);
analyzers[i++].analyze(); analyzers[i++] = analyzer;
if (analyzer.isConstructor()) {
if (analyzer.isStatic())
staticConstructor = analyzer;
else
constrVector.addElement(analyzer);
}
analyzer.analyze();
}
constructors = new MethodAnalyzer[constrVector.size()];
if (constructors.length > 0) {
constrVector.copyInto(constructors);
TransformConstructors.transform(this, false, constructors);
} }
if (staticConstructor != null)
TransformConstructors.transform(this, true, new MethodAnalyzer[]
{ staticConstructor });
env.useClass(clazz); env.useClass(clazz);
if (clazz.getSuperclass() != null) if (clazz.getSuperclass() != null)

@ -70,6 +70,10 @@ public class CodeAnalyzer implements Analyzer {
param[i] = getLocalInfo(0, i); param[i] = getLocalInfo(0, i);
} }
public FlowBlock getMethodHeader() {
return methodHeader;
}
private final static int SEQUENTIAL = 1; private final static int SEQUENTIAL = 1;
private final static int PREDECESSORS = 2; private final static int PREDECESSORS = 2;
/** /**
@ -226,12 +230,12 @@ public class CodeAnalyzer implements Analyzer {
if (!li.isShadow()) if (!li.isShadow())
li.getType().useType(); li.getType().useType();
} }
methodHeader.makeDeclaration(new jode.flow.VariableSet(param));
} }
public void dumpSource(TabbedPrintWriter writer) public void dumpSource(TabbedPrintWriter writer)
throws java.io.IOException throws java.io.IOException
{ {
methodHeader.makeDeclaration(new jode.flow.VariableSet(param));
methodHeader.dumpSource(writer); methodHeader.dumpSource(writer);
} }
@ -244,6 +248,19 @@ public class CodeAnalyzer implements Analyzer {
return li; return li;
} }
/**
* Checks if the variable set contains a local with the given name.
*/
public LocalInfo findLocal(String name) {
Enumeration enum = allLocals.elements();
while (enum.hasMoreElements()) {
LocalInfo li = (LocalInfo) enum.nextElement();
if (li.getName().equals(name))
return li;
}
return null;
}
public LocalInfo getParamInfo(int slot) { public LocalInfo getParamInfo(int slot) {
return param[slot]; return param[slot];
} }

@ -29,7 +29,7 @@ public class FieldAnalyzer implements Analyzer {
int modifiers; int modifiers;
Type type; Type type;
String fieldName; String fieldName;
ConstOperator constant; Expression constant;
public FieldAnalyzer(ClassAnalyzer cla, Field fd, JodeEnvironment e) public FieldAnalyzer(ClassAnalyzer cla, Field fd, JodeEnvironment e)
{ {
@ -51,13 +51,25 @@ public class FieldAnalyzer implements Analyzer {
constant = new ConstOperator constant = new ConstOperator
(type.intersection(cla.getConstantType(index)), (type.intersection(cla.getConstantType(index)),
cla.getConstantString(index)); cla.getConstantString(index));
constant.makeInitializer();
} catch (java.io.IOException ex) { } catch (java.io.IOException ex) {
throw new AssertError("attribute too small"); throw new AssertError("attribute too small");
} }
} }
} }
public String getName() {
return fieldName;
}
public boolean setInitializer(Expression expr) {
expr.makeInitializer();
if (constant != null)
return constant.equals(expr);
constant = expr;
return true;
}
public void analyze() { public void analyze() {
type.useType(); type.useType();
} }
@ -71,7 +83,7 @@ public class FieldAnalyzer implements Analyzer {
writer.print(type.toString() + " " + fieldName); writer.print(type.toString() + " " + fieldName);
if (constant != null) { if (constant != null) {
writer.print(" = " + constant.toString()); writer.print(" = " + constant.simplify().toString());
} }
writer.println(";"); writer.println(";");
} }

@ -23,7 +23,7 @@ import java.util.*;
public class JodeEnvironment { public class JodeEnvironment {
Hashtable imports; Hashtable imports;
/* Classes that doesn't need to be qualified. */ /* Classes that doesn't need to be qualified. */
Hashtable goodClasses = new Hashtable(); Hashtable cachedClassNames = null;
ClassAnalyzer main; ClassAnalyzer main;
String className; String className;
String pkg; String pkg;
@ -66,7 +66,28 @@ public class JodeEnvironment {
if (pkgName.equals(pkg)) if (pkgName.equals(pkg))
return false; return false;
name = name.substring(pkgdelim+1); // name without package, but _including_ leading dot.
name = name.substring(pkgdelim);
if (pkg.length() != 0) {
try {
Class.forName(pkg + name);
/* UGLY: If class doesn't conflict, above
* Instruction throws an exception and we
* doesn't reach here.
* XXX - Is there a better way to do it ???
*/
// System.err.println(""+pkgName+name
// + " conflicts with "
// + pkg+name);
return true;
} catch (ClassNotFoundException ex) {
/* BTW: Exception generation is slow. I'm
* really sad that this is the default.
*/
}
}
Enumeration enum = imports.keys(); Enumeration enum = imports.keys();
while (enum.hasMoreElements()) { while (enum.hasMoreElements()) {
String importName = (String) enum.nextElement(); String importName = (String) enum.nextElement();
@ -75,14 +96,16 @@ public class JodeEnvironment {
importName = importName.substring importName = importName.substring
(0, importName.length()-2); (0, importName.length()-2);
if (!importName.equals(pkgName)) { if (!importName.equals(pkgName)) {
String checkName = importName + "." + name;
try { try {
Class.forName(checkName); Class.forName(importName + name);
/* UGLY: If class doesn't conflict, above /* UGLY: If class doesn't conflict, above
* Instruction throws an exception and we * Instruction throws an exception and we
* doesn't reach here. * doesn't reach here.
* XXX - Is there a better way to do it ??? * XXX - Is there a better way to do it ???
*/ */
// System.err.println(""+pkgName+name
// + " conflicts with "
// + importName+name);
return true; return true;
} catch (ClassNotFoundException ex) { } catch (ClassNotFoundException ex) {
/* BTW: Exception generation is slow. I'm /* BTW: Exception generation is slow. I'm
@ -113,19 +136,20 @@ public class JodeEnvironment {
if (pkgvote.intValue() >= Decompiler.importPackageLimit) if (pkgvote.intValue() >= Decompiler.importPackageLimit)
continue; continue;
/* This is a single Class import. Mark it for importation, /* This is a single Class import, that is not
* but don't put it in newImports, yet. * superseeded by a package import. Mark it for
* importation, but don't put it in newImports, yet.
*/ */
classImports.addElement(importName); classImports.addElement(importName);
} else { } else {
if (vote.intValue() < Decompiler.importPackageLimit) if (vote.intValue() < Decompiler.importPackageLimit)
continue; continue;
newImports.put(importName, dummyVote);
} }
newImports.put(importName, dummyVote);
} }
imports = newImports; imports = newImports;
cachedClassNames = new Hashtable();
/* Now check if the class import conflict with any of the /* Now check if the class import conflict with any of the
* package imports. * package imports.
*/ */
@ -135,8 +159,12 @@ public class JodeEnvironment {
* the same name, exactly the first (in hash order) will * the same name, exactly the first (in hash order) will
* be imported. */ * be imported. */
String className = (String) enum.nextElement(); String className = (String) enum.nextElement();
if (!conflictsImport(className)) if (!conflictsImport(className)) {
imports.put(className, dummyVote); imports.put(className, dummyVote);
String name =
className.substring(className.lastIndexOf('.')+1);
cachedClassNames.put(className, name);
}
} }
} }
@ -201,22 +229,22 @@ public class JodeEnvironment {
int pkgdelim = name.lastIndexOf('.'); int pkgdelim = name.lastIndexOf('.');
if (pkgdelim != -1) { if (pkgdelim != -1) {
String pkgName = name.substring(0, pkgdelim); String pkgName = name.substring(0, pkgdelim);
if (pkgName.equals(pkg) if (pkgName.equals(pkg))
|| pkgName.equals("java.lang"))
return; return;
Integer pkgVote = (Integer) imports.get(pkgName+".*");
if (pkgVote != null
&& pkgVote.intValue() >= Decompiler.importPackageLimit)
return;
Integer i = (Integer) imports.get(name); Integer i = (Integer) imports.get(name);
if (i == null) { if (i == null) {
/* This class wasn't imported before. Mark the package /* This class wasn't imported before. Mark the whole package
* as used. */ * as used once more. */
i = (Integer) imports.get(pkgName+".*");
if (i != null && i.intValue() >= Decompiler.importPackageLimit)
return;
i = (i == null)? new Integer(1): new Integer(i.intValue()+1);
imports.put(pkgName+".*", i);
if (i.intValue() >= Decompiler.importPackageLimit)
return;
pkgVote = (pkgVote == null)
? new Integer(1): new Integer(pkgVote.intValue()+1);
imports.put(pkgName+".*", pkgVote);
i = new Integer(1); i = new Integer(1);
} else { } else {
@ -250,23 +278,30 @@ public class JodeEnvironment {
* @return a legal string representation of clazz. * @return a legal string representation of clazz.
*/ */
public String classString(String name) { public String classString(String name) {
if (cachedClassNames == null)
/* We are not yet clean, return the full name */
return name;
/* First look in our cache. */
String cached = (String) cachedClassNames.get(name);
if (cached != null)
return cached;
int pkgdelim = name.lastIndexOf('.'); int pkgdelim = name.lastIndexOf('.');
if (pkgdelim != -1) { if (pkgdelim != -1) {
/* First look in our cache. */
if (goodClasses.get(name) != null)
return name.substring(pkgdelim+1);
String pkgName = name.substring(0, pkgdelim); String pkgName = name.substring(0, pkgdelim);
Integer i; Integer i;
if (pkgName.equals(pkg) if (pkgName.equals(pkg)
|| (( imports.get(pkgName+".*") != null || (imports.get(pkgName+".*") != null
|| imports.get(name) != null)
&& !conflictsImport(name))) { && !conflictsImport(name))) {
goodClasses.put(name, name); String result = name.substring(pkgdelim+1);
return name.substring(pkgdelim+1); cachedClassNames.put(name, result);
return result;
} }
} }
cachedClassNames.put(name, name);
return name; return name;
} }

@ -35,6 +35,7 @@ import java.util.Vector;
public class LocalInfo { public class LocalInfo {
private static int serialnr = 0; private static int serialnr = 0;
private int slot; private int slot;
private boolean isUnique;
private String name; private String name;
private Type type; private Type type;
private LocalInfo shadow; private LocalInfo shadow;
@ -126,8 +127,10 @@ public class LocalInfo {
} }
return shadow.getName(); return shadow.getName();
} }
if (name == null) if (name == null) {
name = "local_"+slot+"__"+serialnr++; name = "local_"+slot+"__"+serialnr+++"_";
isUnique = true;
}
return name; return name;
} }
@ -143,10 +146,20 @@ public class LocalInfo {
* Set the name of this local. * Set the name of this local.
*/ */
public void setName(String name) { public void setName(String name) {
if (shadow != null) LocalInfo li = getLocalInfo();
shadow.setName(name); li.name = name;
else }
this.name = name;
/**
* Set the name of this local.
*/
public void makeNameUnique() {
LocalInfo li = getLocalInfo();
String name = li.getName();
if (!li.isUnique) {
li.name = name + "__"+serialnr+++"_";
li.isUnique = true;
}
} }
/** /**

@ -72,9 +72,24 @@ public class MethodAnalyzer implements Analyzer {
} }
} }
public jode.flow.FlowBlock getMethodHeader() {
return code != null ? code.getMethodHeader() : null;
}
public boolean isConstructor() {
return isConstructor;
}
public boolean isStatic() {
return methodType.isStatic();
}
public int getParamCount() { public int getParamCount() {
return (methodType.isStatic() ? 0 : 1) int count = isStatic() ? 0 : 1;
+ methodType.getParameterTypes().length; Type[] paramTypes = methodType.getParameterTypes();
for (int i=0; i< paramTypes.length; i++)
count += paramTypes[i].stackSize();
return count;
} }
public Type getReturnType() { public Type getReturnType() {
@ -88,7 +103,7 @@ public class MethodAnalyzer implements Analyzer {
return; return;
int offset = 0; int offset = 0;
if (!methodType.isStatic()) { if (!isStatic()) {
LocalInfo clazz = code.getParamInfo(0); LocalInfo clazz = code.getParamInfo(0);
clazz.setType(Type.tType(this.classAnalyzer.clazz)); clazz.setType(Type.tType(this.classAnalyzer.clazz));
clazz.setName("this"); clazz.setName("this");
@ -96,8 +111,10 @@ public class MethodAnalyzer implements Analyzer {
} }
Type[] paramTypes = methodType.getParameterTypes(); Type[] paramTypes = methodType.getParameterTypes();
for (int i=0; i< paramTypes.length; i++) for (int i=0; i< paramTypes.length; i++) {
code.getParamInfo(offset+i).setType(paramTypes[i]); code.getParamInfo(offset).setType(paramTypes[i]);
offset += paramTypes[i].stackSize();
}
for (int i= 0; i< exceptions.length; i++) for (int i= 0; i< exceptions.length; i++)
exceptions[i].useType(); exceptions[i].useType();
@ -128,11 +145,15 @@ public class MethodAnalyzer implements Analyzer {
System.err.println(""); System.err.println("");
} }
if (isConstructor() && isStatic()
&& getMethodHeader().getBlock() instanceof jode.flow.EmptyBlock)
return;
writer.println(""); writer.println("");
String modif = Modifier.toString(modifiers); String modif = Modifier.toString(modifiers);
if (modif.length() > 0) if (modif.length() > 0)
writer.print(modif+" "); writer.print(modif+" ");
if (isConstructor && methodType.isStatic()) if (isConstructor && isStatic())
writer.print(""); /* static block */ writer.print(""); /* static block */
else { else {
if (isConstructor) if (isConstructor)
@ -148,11 +169,13 @@ public class MethodAnalyzer implements Analyzer {
writer.print(", "); writer.print(", ");
LocalInfo li; LocalInfo li;
if (code == null) { if (code == null) {
li = new LocalInfo(i+offset); li = new LocalInfo(offset);
li.setType(paramTypes[i]); li.setType(paramTypes[i]);
li.makeNameUnique();
} else } else
li = code.getParamInfo(i+offset); li = code.getParamInfo(offset);
writer.print(li.getType().toString()+" "+li.getName()); writer.print(li.getType().toString()+" "+li.getName());
offset += paramTypes[i].stackSize();
} }
writer.print(")"); writer.print(")");
} }

@ -250,6 +250,8 @@ public class ComplexExpression extends Expression {
else if (subExpressions[i].getType() == Type.tError) else if (subExpressions[i].getType() == Type.tError)
expr[i] = "(/*type error */" + expr[i]+")"; expr[i] = "(/*type error */" + expr[i]+")";
} }
if (Decompiler.isTypeDebugging && parent != null)
return "[("+type+") "+ operator.toString(expr)+"]";
return operator.toString(expr); return operator.toString(expr);
} }
@ -426,5 +428,18 @@ public class ComplexExpression extends Expression {
} }
return this; return this;
} }
}
public void makeInitializer() {
operator.makeInitializer();
}
public boolean isConstant() {
if (!operator.isConstant())
return false;
for (int i=0; i< subExpressions.length; i++)
if (!subExpressions[i].isConstant())
return false;
return true;
}
}

@ -22,6 +22,8 @@ package jode;
public class ConstOperator extends NoArgOperator { public class ConstOperator extends NoArgOperator {
String value; String value;
boolean isInitializer = false;
public ConstOperator(Type type, String value) { public ConstOperator(Type type, String value) {
super(type); super(type);
this.value = value; this.value = value;
@ -40,7 +42,12 @@ public class ConstOperator extends NoArgOperator {
((ConstOperator)o).value.equals(value); ((ConstOperator)o).value.equals(value);
} }
public void makeInitializer() {
isInitializer = true;
}
public String toString(String[] operands) { public String toString(String[] operands) {
String value = this.value;
if (type.isOfType(Type.tBoolean)) { if (type.isOfType(Type.tBoolean)) {
if (value.equals("0")) if (value.equals("0"))
return "false"; return "false";
@ -86,15 +93,15 @@ public class ConstOperator extends NoArgOperator {
if (type.isOfType(Type.tUInt)) { if (type.isOfType(Type.tUInt)) {
int i = Integer.parseInt(value); int i = Integer.parseInt(value);
if (i < -1) if (i < -1)
return "~0x"+Integer.toHexString(-i-1); value = "~0x"+Integer.toHexString(-i-1);
else else
return "0x"+Integer.toHexString(i); value = "0x"+Integer.toHexString(i);
} else if (type.equals(Type.tLong)) { } else if (type.equals(Type.tLong)) {
long l = Long.parseLong(value); long l = Long.parseLong(value);
if (l < -1) if (l < -1)
return "~0x"+Long.toHexString(-l-1)+"L"; value = "~0x"+Long.toHexString(-l-1);
else else
return "0x"+Long.toHexString(l)+"L"; value = "0x"+Long.toHexString(l);
} }
} }
} }
@ -102,6 +109,14 @@ public class ConstOperator extends NoArgOperator {
return value+"L"; return value+"L";
if (type.isOfType(Type.tFloat)) if (type.isOfType(Type.tFloat))
return value+"F"; return value+"F";
if (!type.isOfType(Type.tInt) && type.isOfType(Type.tUInt)
&& !isInitializer)
/* One of the strange things in java. All constants
* are int and must be explicitly casted to byte,...,short.
* But in initializers this cast is unnecessary.
*/
return "("+type+") "+value;
return value; return value;
} }
} }

@ -24,6 +24,7 @@ public class ConstantArrayOperator extends NoArgOperator {
ConstOperator empty; ConstOperator empty;
Expression[] values; Expression[] values;
Type argType; Type argType;
boolean isInitializer;
public ConstantArrayOperator(Type type, int size) { public ConstantArrayOperator(Type type, int size) {
super(type); super(type);
@ -31,6 +32,7 @@ public class ConstantArrayOperator extends NoArgOperator {
argType = (type instanceof ArrayType) argType = (type instanceof ArrayType)
? Type.tSubType(((ArrayType)type).getElementType()) : Type.tError; ? Type.tSubType(((ArrayType)type).getElementType()) : Type.tError;
empty = new ConstOperator(argType, "0"); empty = new ConstOperator(argType, "0");
empty.makeInitializer();
} }
public void setType(Type newtype) { public void setType(Type newtype) {
@ -54,6 +56,7 @@ public class ConstantArrayOperator extends NoArgOperator {
setType(Type.tSuperType(Type.tArray(value.getType()))); setType(Type.tSuperType(Type.tArray(value.getType())));
values[index] = value; values[index] = value;
value.parent = this; value.parent = this;
value.makeInitializer();
return true; return true;
} }
@ -61,9 +64,13 @@ public class ConstantArrayOperator extends NoArgOperator {
return 200; return 200;
} }
public void makeInitializer() {
isInitializer = true;
}
public String toString(String[] operands) { public String toString(String[] operands) {
StringBuffer result StringBuffer result = isInitializer ? new StringBuffer("{ ")
= new StringBuffer("new ").append(type).append(" { "); : new StringBuffer("new ").append(type).append(" { ");
for (int i=0; i< values.length; i++) { for (int i=0; i< values.length; i++) {
if (i>0) if (i>0)
result.append(", "); result.append(", ");

@ -128,6 +128,13 @@ public abstract class Expression {
public abstract Operator getOperator(); public abstract Operator getOperator();
public void makeInitializer() {
}
public boolean isConstant() {
return true;
}
public abstract String toString(); public abstract String toString();
String toString(int minPriority) { String toString(int minPriority) {

@ -59,9 +59,11 @@ public class GetFieldOperator extends Operator {
public String toString(String[] operands) { public String toString(String[] operands) {
return staticFlag return staticFlag
? (classType.equals(Type.tType(codeAnalyzer.getClazz())) ? (classType.equals(Type.tType(codeAnalyzer.getClazz()))
&& codeAnalyzer.findLocal(fieldName) == null
? fieldName ? fieldName
: classType.toString() + "." + fieldName) : classType.toString() + "." + fieldName)
: (operands[0].equals("this") : (operands[0].equals("this")
&& codeAnalyzer.findLocal(fieldName) == null
? fieldName ? fieldName
: operands[0] + "." + fieldName); : operands[0] + "." + fieldName);
} }

@ -38,6 +38,10 @@ implements LocalVarOperator {
return false; return false;
} }
public boolean isConstant() {
return false;
}
// public void setLocalInfo(LocalInfo local) { // public void setLocalInfo(LocalInfo local) {
// local.setType(type); // local.setType(type);
// this.local = local; // this.local = local;

@ -37,6 +37,14 @@ public class PutFieldOperator extends StoreInstruction {
classType.useType(); classType.useType();
} }
public boolean isStatic() {
return staticFlag;
}
public String getFieldName() {
return fieldName;
}
public boolean matches(Operator loadop) { public boolean matches(Operator loadop) {
return loadop instanceof GetFieldOperator return loadop instanceof GetFieldOperator
&& ((GetFieldOperator)loadop).classType.equals(classType) && ((GetFieldOperator)loadop).classType.equals(classType)
@ -61,9 +69,11 @@ public class PutFieldOperator extends StoreInstruction {
public String getLValueString(String[] operands) { public String getLValueString(String[] operands) {
return staticFlag return staticFlag
? (classType.equals(Type.tType(codeAnalyzer.getClazz())) ? (classType.equals(Type.tType(codeAnalyzer.getClazz()))
&& codeAnalyzer.findLocal(fieldName) == null
? fieldName ? fieldName
: classType.toString() + "." + fieldName) : classType.toString() + "." + fieldName)
: (operands[0].equals("this") : (operands[0].equals("this")
&& codeAnalyzer.findLocal(fieldName) == null
? fieldName ? fieldName
: operands[0] + "." + fieldName); : operands[0] + "." + fieldName);
} }

@ -30,6 +30,10 @@ public abstract class StoreInstruction extends Operator {
lvCasts = lvalueType.toString(); lvCasts = lvalueType.toString();
} }
public Type getType() {
return type == Type.tVoid ? type : getLValueType();
}
public Type getLValueType() { public Type getLValueType() {
return lvalueType; return lvalueType;
} }
@ -41,6 +45,8 @@ public abstract class StoreInstruction extends Operator {
if (type != Type.tVoid) if (type != Type.tVoid)
throw new AssertError("already non void"); throw new AssertError("already non void");
type = lvalueType; type = lvalueType;
if (parent != null && parent.getOperator() == this)
parent.type = lvalueType;
} }
public abstract boolean matches(Operator loadop); public abstract boolean matches(Operator loadop);

@ -136,6 +136,7 @@ public class CaseBlock extends StructuredBlock {
ConstOperator constOp = new ConstOperator ConstOperator constOp = new ConstOperator
(((SwitchBlock)outer).getInstruction().getType(), (((SwitchBlock)outer).getInstruction().getType(),
Integer.toString(value)); Integer.toString(value));
constOp.makeInitializer();
writer.println("case " + constOp.toString() + ":" writer.println("case " + constOp.toString() + ":"
+ (wantBraces ? " {" : "")); + (wantBraces ? " {" : ""));
} }

@ -27,59 +27,67 @@ import jode.Expression;
public class CompleteSynchronized { public class CompleteSynchronized {
/** /**
* This combines the monitorenter and the initial expression * This combines the monitorenter into a synchronized statement
* into a synchronized statement
* @param flow The FlowBlock that is transformed * @param flow The FlowBlock that is transformed
*/ */
public static boolean transform(SynchronizedBlock synBlock, public static boolean enter(SynchronizedBlock synBlock,
StructuredBlock last) { StructuredBlock last) {
if (!(last.outer instanceof SequentialBlock)) if (!(last.outer instanceof SequentialBlock))
return false; return false;
/* If the program is well formed, the following succeed */ /* If the program is well formed, the following succeed */
try { try {
SequentialBlock sequBlock = (SequentialBlock) synBlock.outer; SequentialBlock sequBlock = (SequentialBlock) synBlock.outer;
ComplexExpression monenter = (ComplexExpression) ComplexExpression monenter = (ComplexExpression)
((InstructionBlock) sequBlock.subBlocks[0]).getInstruction(); ((InstructionBlock) sequBlock.subBlocks[0]).getInstruction();
if (!(monenter.getOperator() instanceof MonitorEnterOperator) if (!(monenter.getOperator() instanceof MonitorEnterOperator)
|| ((LocalLoadOperator) monenter.getSubExpressions()[0]). || ((LocalLoadOperator) monenter.getSubExpressions()[0]).
getLocalInfo() != synBlock.local.getLocalInfo()) getLocalInfo() != synBlock.local.getLocalInfo())
return false; return false;
} catch (ClassCastException ex) { } catch (ClassCastException ex) {
return false; return false;
} }
if (jode.Decompiler.isVerbose) if (jode.Decompiler.isVerbose)
System.err.print('s'); System.err.print('s');
synBlock.isEntered = true; synBlock.isEntered = true;
synBlock.moveDefinitions(last.outer,last); synBlock.moveDefinitions(last.outer,last);
last.replace(last.outer); last.replace(last.outer);
return true;
}
/**
* This combines the initial expression describing the object
* into a synchronized statement
* @param flow The FlowBlock that is transformed
*/
public static boolean combineObject(SynchronizedBlock synBlock,
StructuredBlock last) {
/* Is there another expression? */ /* Is there another expression? */
if (!(last.outer instanceof SynchronizedBlock)) if (!(last.outer instanceof SequentialBlock))
return false; return false;
Expression object; Expression object;
try { try {
SequentialBlock sequBlock = SequentialBlock sequBlock = (SequentialBlock) last.outer;
(SequentialBlock) synBlock.outer;
ComplexExpression assign = (ComplexExpression) ComplexExpression assign = (ComplexExpression)
((InstructionBlock) sequBlock.subBlocks[0]).getInstruction(); ((InstructionBlock) sequBlock.subBlocks[0]).getInstruction();
if (((LocalStoreOperator) assign.getOperator()). if (((LocalStoreOperator) assign.getOperator()).
getLocalInfo() != synBlock.local.getLocalInfo()) getLocalInfo() != synBlock.local.getLocalInfo())
return true; return false;
object = assign.getSubExpressions()[0]; object = assign.getSubExpressions()[0];
} catch (ClassCastException ex) { } catch (ClassCastException ex) {
return true; return false;
} }
synBlock.object = object; synBlock.object = object;

@ -20,6 +20,7 @@ import jode.Expression;
import jode.TabbedPrintWriter; import jode.TabbedPrintWriter;
import jode.LocalInfo; import jode.LocalInfo;
import jode.LocalStoreOperator; import jode.LocalStoreOperator;
import jode.ComplexExpression;
/** /**
* This is the structured block for atomic instructions. * This is the structured block for atomic instructions.
@ -69,10 +70,13 @@ public class InstructionBlock extends InstructionContainer {
throws java.io.IOException throws java.io.IOException
{ {
if (isDeclaration) { if (isDeclaration) {
writer.println LocalInfo local = ((LocalStoreOperator) instr.getOperator())
(((LocalStoreOperator) instr.getOperator()) .getLocalInfo();
.getLocalInfo().getType().toString() Expression expr =
+ " " + instr.simplify().toString() + ";"); ((ComplexExpression) instr).getSubExpressions()[0];
expr.makeInitializer();
writer.println(local.getType() + " " + local.getName() + " = "
+ expr.simplify().toString() + ";");
} else { } else {
if (instr.getType() != jode.Type.tVoid) if (instr.getType() != jode.Type.tVoid)
writer.print("PUSH "); writer.print("PUSH ");

@ -100,10 +100,22 @@ public class SequentialBlock extends StructuredBlock {
* any local Variable, but lets the first sub block do this. * any local Variable, but lets the first sub block do this.
*/ */
declare = new VariableSet(); declare = new VariableSet();
/* First we can forget any variable that is already declared.
*/
used.subtractExact(done);
/* Second, tell the first sub block that he must declare all
* variables _we_ use. */
subBlocks[0].used.unionExact(used); subBlocks[0].used.unionExact(used);
subBlocks[0].makeDeclaration(done); subBlocks[0].makeDeclaration(done);
/* Now add the variables to the done set, since the first
* sub block has declared them.
*/
done.unionExact(used); done.unionExact(used);
subBlocks[1].makeDeclaration(done); subBlocks[1].makeDeclaration(done);
/* Now undo the change to done. Note that the second instruction
* made done and used disjunct.
*/
done.subtractExact(used);
} }
public void dumpInstruction(TabbedPrintWriter writer) public void dumpInstruction(TabbedPrintWriter writer)

@ -341,16 +341,23 @@ public abstract class StructuredBlock {
declare = new VariableSet(); declare = new VariableSet();
java.util.Enumeration enum = used.elements(); java.util.Enumeration enum = used.elements();
while (enum.hasMoreElements()) { while (enum.hasMoreElements()) {
LocalInfo local = ((LocalInfo) enum.nextElement()).getLocalInfo(); LocalInfo local = (LocalInfo) enum.nextElement();
if (!declare.contains(local)) LocalInfo previous = done.findLocal(local.getName());
if (previous == null)
declare.addElement(local); declare.addElement(local);
else if (!previous.equals(local)) {
/* A name conflict happened. */
local.makeNameUnique();
declare.addElement(local);
}
} }
declare.subtractExact(done); done.unionExact(declare);
done.unionExact(declare);
StructuredBlock[] subs = getSubBlocks(); StructuredBlock[] subs = getSubBlocks();
for (int i=0; i<subs.length; i++) for (int i=0; i<subs.length; i++)
subs[i].makeDeclaration(done); subs[i].makeDeclaration(done);
/* remove the variables again, since we leave the scope.
*/
done.subtractExact(declare);
} }
public void checkConsistent() { public void checkConsistent() {

@ -81,7 +81,7 @@ public class SynchronizedBlock extends StructuredBlock {
throws java.io.IOException throws java.io.IOException
{ {
if (!isEntered) if (!isEntered)
writer.print("/* missing monitorenter */"); writer.println("MISSING MONITORENTER");
writer.println("synchronized (" writer.println("synchronized ("
+ (object != null + (object != null
? object.simplify().toString() ? object.simplify().toString()
@ -93,6 +93,9 @@ public class SynchronizedBlock extends StructuredBlock {
} }
public boolean doTransformations() { public boolean doTransformations() {
return CompleteSynchronized.transform(this, flowBlock.lastModified); StructuredBlock last = flowBlock.lastModified;
return (!isEntered && CompleteSynchronized.enter(this, last))
|| (isEntered && object == null
&& CompleteSynchronized.combineObject(this, last));
} }
} }

@ -162,8 +162,6 @@ public class TransformExceptionHandlers {
* | ... * | ...
* `- catch block * `- catch block
*/ */
static int serialno=0;
static void analyzeCatchBlock(Type type, static void analyzeCatchBlock(Type type,
FlowBlock tryFlow, FlowBlock catchFlow) { FlowBlock tryFlow, FlowBlock catchFlow) {
@ -179,7 +177,7 @@ public class TransformExceptionHandlers {
&& ((PopOperator) instr).getCount() == 1) { && ((PopOperator) instr).getCount() == 1) {
/* The exception is ignored. Create a dummy local for it */ /* The exception is ignored. Create a dummy local for it */
local = new LocalInfo(-1); local = new LocalInfo(-1);
local.setName("exception_"+(serialno++)+"_"); local.setName("exception");
firstInstr.removeBlock(); firstInstr.removeBlock();
} else if (instr instanceof jode.LocalStoreOperator) { } else if (instr instanceof jode.LocalStoreOperator) {

@ -84,6 +84,16 @@ public class VariableSet implements Cloneable {
return false; return false;
} }
/**
* Checks if the variable set contains a local with the given name.
*/
public LocalInfo findLocal(String name) {
for (int i=0; i<count;i++)
if (locals[i].getName().equals(name))
return locals[i];
return null;
}
/** /**
* Removes a local info from this variable set. * Removes a local info from this variable set.
*/ */

Loading…
Cancel
Save