From 0192af7705ac9e8f3ae237b6cd39d3199272fc70 Mon Sep 17 00:00:00 2001 From: jochen Date: Mon, 2 Nov 1998 23:14:04 +0000 Subject: [PATCH] *** empty log message *** git-svn-id: https://svn.code.sf.net/p/jode/code/trunk@117 379699f6-c40d-0410-875b-85095c16579e --- jode/jode/decompiler/ClassAnalyzer.java | 44 +++++++-- jode/jode/decompiler/CodeAnalyzer.java | 19 +++- jode/jode/decompiler/FieldAnalyzer.java | 18 +++- jode/jode/decompiler/ImportHandler.java | 91 +++++++++++++------ jode/jode/decompiler/LocalInfo.java | 25 +++-- jode/jode/decompiler/MethodAnalyzer.java | 39 ++++++-- jode/jode/expr/ComplexExpression.java | 17 +++- jode/jode/expr/ConstOperator.java | 23 ++++- jode/jode/expr/ConstantArrayOperator.java | 11 ++- jode/jode/expr/Expression.java | 7 ++ jode/jode/expr/GetFieldOperator.java | 2 + jode/jode/expr/LocalLoadOperator.java | 4 + jode/jode/expr/PutFieldOperator.java | 10 ++ jode/jode/expr/StoreInstruction.java | 6 ++ jode/jode/flow/CaseBlock.java | 1 + jode/jode/flow/CompleteSynchronized.java | 38 +++++--- jode/jode/flow/InstructionBlock.java | 12 ++- jode/jode/flow/SequentialBlock.java | 12 +++ jode/jode/flow/StructuredBlock.java | 17 +++- jode/jode/flow/SynchronizedBlock.java | 7 +- .../jode/flow/TransformExceptionHandlers.java | 4 +- jode/jode/flow/VariableSet.java | 10 ++ 22 files changed, 329 insertions(+), 88 deletions(-) diff --git a/jode/jode/decompiler/ClassAnalyzer.java b/jode/jode/decompiler/ClassAnalyzer.java index 7381560..aeacc1e 100644 --- a/jode/jode/decompiler/ClassAnalyzer.java +++ b/jode/jode/decompiler/ClassAnalyzer.java @@ -27,10 +27,14 @@ import gnu.bytecode.CpoolEntry; import gnu.bytecode.CpoolValue1; import gnu.bytecode.CpoolValue2; import gnu.bytecode.CpoolString; +import jode.flow.TransformConstructors; public class ClassAnalyzer implements Analyzer { JodeEnvironment env; - Analyzer[] analyzers; + Analyzer[] analyzers; + MethodAnalyzer staticConstructor; + MethodAnalyzer[] constructors; + Class clazz; gnu.bytecode.ClassType classType; ClassAnalyzer parent; @@ -48,7 +52,18 @@ public class ClassAnalyzer implements Analyzer { 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() { int numFields = 0; int i = 0; @@ -57,17 +72,34 @@ public class ClassAnalyzer implements Analyzer { analyzers = new Analyzer[fields.length + classType.getMethodCount()]; - for (int j=0; j< fields.length; j++) { analyzers[i] = new FieldAnalyzer(this, fields[j], env); analyzers[i++].analyze(); } - + + staticConstructor = null; + java.util.Vector constrVector = new java.util.Vector(); for (gnu.bytecode.Method method = classType.getMethods(); method != null; method = method.getNext()) { - analyzers[i] = new MethodAnalyzer(this, method, env); - analyzers[i++].analyze(); + MethodAnalyzer analyzer = new MethodAnalyzer(this, method, env); + 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); if (clazz.getSuperclass() != null) diff --git a/jode/jode/decompiler/CodeAnalyzer.java b/jode/jode/decompiler/CodeAnalyzer.java index 9c5e68e..444dfe2 100644 --- a/jode/jode/decompiler/CodeAnalyzer.java +++ b/jode/jode/decompiler/CodeAnalyzer.java @@ -70,6 +70,10 @@ public class CodeAnalyzer implements Analyzer { param[i] = getLocalInfo(0, i); } + public FlowBlock getMethodHeader() { + return methodHeader; + } + private final static int SEQUENTIAL = 1; private final static int PREDECESSORS = 2; /** @@ -226,12 +230,12 @@ public class CodeAnalyzer implements Analyzer { if (!li.isShadow()) li.getType().useType(); } + methodHeader.makeDeclaration(new jode.flow.VariableSet(param)); } public void dumpSource(TabbedPrintWriter writer) throws java.io.IOException { - methodHeader.makeDeclaration(new jode.flow.VariableSet(param)); methodHeader.dumpSource(writer); } @@ -244,6 +248,19 @@ public class CodeAnalyzer implements Analyzer { 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) { return param[slot]; } diff --git a/jode/jode/decompiler/FieldAnalyzer.java b/jode/jode/decompiler/FieldAnalyzer.java index aa41d77..930ded2 100644 --- a/jode/jode/decompiler/FieldAnalyzer.java +++ b/jode/jode/decompiler/FieldAnalyzer.java @@ -29,7 +29,7 @@ public class FieldAnalyzer implements Analyzer { int modifiers; Type type; String fieldName; - ConstOperator constant; + Expression constant; public FieldAnalyzer(ClassAnalyzer cla, Field fd, JodeEnvironment e) { @@ -51,13 +51,25 @@ public class FieldAnalyzer implements Analyzer { constant = new ConstOperator (type.intersection(cla.getConstantType(index)), cla.getConstantString(index)); - + constant.makeInitializer(); } catch (java.io.IOException ex) { 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() { type.useType(); } @@ -71,7 +83,7 @@ public class FieldAnalyzer implements Analyzer { writer.print(type.toString() + " " + fieldName); if (constant != null) { - writer.print(" = " + constant.toString()); + writer.print(" = " + constant.simplify().toString()); } writer.println(";"); } diff --git a/jode/jode/decompiler/ImportHandler.java b/jode/jode/decompiler/ImportHandler.java index d0e04bb..68be986 100644 --- a/jode/jode/decompiler/ImportHandler.java +++ b/jode/jode/decompiler/ImportHandler.java @@ -23,7 +23,7 @@ import java.util.*; public class JodeEnvironment { Hashtable imports; /* Classes that doesn't need to be qualified. */ - Hashtable goodClasses = new Hashtable(); + Hashtable cachedClassNames = null; ClassAnalyzer main; String className; String pkg; @@ -66,7 +66,28 @@ public class JodeEnvironment { if (pkgName.equals(pkg)) 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(); while (enum.hasMoreElements()) { String importName = (String) enum.nextElement(); @@ -75,14 +96,16 @@ public class JodeEnvironment { importName = importName.substring (0, importName.length()-2); if (!importName.equals(pkgName)) { - String checkName = importName + "." + name; try { - Class.forName(checkName); + Class.forName(importName + 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 " +// + importName+name); return true; } catch (ClassNotFoundException ex) { /* BTW: Exception generation is slow. I'm @@ -113,19 +136,20 @@ public class JodeEnvironment { if (pkgvote.intValue() >= Decompiler.importPackageLimit) continue; - /* This is a single Class import. Mark it for importation, - * but don't put it in newImports, yet. + /* This is a single Class import, that is not + * superseeded by a package import. Mark it for + * importation, but don't put it in newImports, yet. */ classImports.addElement(importName); } else { if (vote.intValue() < Decompiler.importPackageLimit) continue; + newImports.put(importName, dummyVote); } - newImports.put(importName, dummyVote); } imports = newImports; - + cachedClassNames = new Hashtable(); /* Now check if the class import conflict with any of the * package imports. */ @@ -135,8 +159,12 @@ public class JodeEnvironment { * the same name, exactly the first (in hash order) will * be imported. */ String className = (String) enum.nextElement(); - if (!conflictsImport(className)) + if (!conflictsImport(className)) { 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('.'); if (pkgdelim != -1) { String pkgName = name.substring(0, pkgdelim); - if (pkgName.equals(pkg) - || pkgName.equals("java.lang")) + if (pkgName.equals(pkg)) return; + + Integer pkgVote = (Integer) imports.get(pkgName+".*"); + if (pkgVote != null + && pkgVote.intValue() >= Decompiler.importPackageLimit) + return; + Integer i = (Integer) imports.get(name); if (i == null) { - /* This class wasn't imported before. Mark the package - * as used. */ - - 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; + /* This class wasn't imported before. Mark the whole package + * as used once more. */ + pkgVote = (pkgVote == null) + ? new Integer(1): new Integer(pkgVote.intValue()+1); + imports.put(pkgName+".*", pkgVote); i = new Integer(1); } else { @@ -250,23 +278,30 @@ public class JodeEnvironment { * @return a legal string representation of clazz. */ 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('.'); if (pkgdelim != -1) { - /* First look in our cache. */ - if (goodClasses.get(name) != null) - return name.substring(pkgdelim+1); String pkgName = name.substring(0, pkgdelim); Integer i; if (pkgName.equals(pkg) - || (( imports.get(pkgName+".*") != null - || imports.get(name) != null) + || (imports.get(pkgName+".*") != null && !conflictsImport(name))) { - goodClasses.put(name, name); - return name.substring(pkgdelim+1); + String result = name.substring(pkgdelim+1); + cachedClassNames.put(name, result); + return result; } } + cachedClassNames.put(name, name); return name; } diff --git a/jode/jode/decompiler/LocalInfo.java b/jode/jode/decompiler/LocalInfo.java index 30243ae..e03e2ed 100644 --- a/jode/jode/decompiler/LocalInfo.java +++ b/jode/jode/decompiler/LocalInfo.java @@ -35,6 +35,7 @@ import java.util.Vector; public class LocalInfo { private static int serialnr = 0; private int slot; + private boolean isUnique; private String name; private Type type; private LocalInfo shadow; @@ -126,8 +127,10 @@ public class LocalInfo { } return shadow.getName(); } - if (name == null) - name = "local_"+slot+"__"+serialnr++; + if (name == null) { + name = "local_"+slot+"__"+serialnr+++"_"; + isUnique = true; + } return name; } @@ -143,10 +146,20 @@ public class LocalInfo { * Set the name of this local. */ public void setName(String name) { - if (shadow != null) - shadow.setName(name); - else - this.name = name; + LocalInfo li = getLocalInfo(); + li.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; + } } /** diff --git a/jode/jode/decompiler/MethodAnalyzer.java b/jode/jode/decompiler/MethodAnalyzer.java index 06bae1a..69b5578 100644 --- a/jode/jode/decompiler/MethodAnalyzer.java +++ b/jode/jode/decompiler/MethodAnalyzer.java @@ -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() { - return (methodType.isStatic() ? 0 : 1) - + methodType.getParameterTypes().length; + int count = isStatic() ? 0 : 1; + Type[] paramTypes = methodType.getParameterTypes(); + for (int i=0; i< paramTypes.length; i++) + count += paramTypes[i].stackSize(); + return count; } public Type getReturnType() { @@ -88,7 +103,7 @@ public class MethodAnalyzer implements Analyzer { return; int offset = 0; - if (!methodType.isStatic()) { + if (!isStatic()) { LocalInfo clazz = code.getParamInfo(0); clazz.setType(Type.tType(this.classAnalyzer.clazz)); clazz.setName("this"); @@ -96,8 +111,10 @@ public class MethodAnalyzer implements Analyzer { } Type[] paramTypes = methodType.getParameterTypes(); - for (int i=0; i< paramTypes.length; i++) - code.getParamInfo(offset+i).setType(paramTypes[i]); + for (int i=0; i< paramTypes.length; i++) { + code.getParamInfo(offset).setType(paramTypes[i]); + offset += paramTypes[i].stackSize(); + } for (int i= 0; i< exceptions.length; i++) exceptions[i].useType(); @@ -128,11 +145,15 @@ public class MethodAnalyzer implements Analyzer { System.err.println(""); } + if (isConstructor() && isStatic() + && getMethodHeader().getBlock() instanceof jode.flow.EmptyBlock) + return; + writer.println(""); String modif = Modifier.toString(modifiers); if (modif.length() > 0) writer.print(modif+" "); - if (isConstructor && methodType.isStatic()) + if (isConstructor && isStatic()) writer.print(""); /* static block */ else { if (isConstructor) @@ -148,11 +169,13 @@ public class MethodAnalyzer implements Analyzer { writer.print(", "); LocalInfo li; if (code == null) { - li = new LocalInfo(i+offset); + li = new LocalInfo(offset); li.setType(paramTypes[i]); + li.makeNameUnique(); } else - li = code.getParamInfo(i+offset); + li = code.getParamInfo(offset); writer.print(li.getType().toString()+" "+li.getName()); + offset += paramTypes[i].stackSize(); } writer.print(")"); } diff --git a/jode/jode/expr/ComplexExpression.java b/jode/jode/expr/ComplexExpression.java index a74a618..d3cfda7 100644 --- a/jode/jode/expr/ComplexExpression.java +++ b/jode/jode/expr/ComplexExpression.java @@ -250,6 +250,8 @@ public class ComplexExpression extends Expression { else if (subExpressions[i].getType() == Type.tError) expr[i] = "(/*type error */" + expr[i]+")"; } + if (Decompiler.isTypeDebugging && parent != null) + return "[("+type+") "+ operator.toString(expr)+"]"; return operator.toString(expr); } @@ -426,5 +428,18 @@ public class ComplexExpression extends Expression { } 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; + } + +} diff --git a/jode/jode/expr/ConstOperator.java b/jode/jode/expr/ConstOperator.java index b6d352c..db6cc4d 100644 --- a/jode/jode/expr/ConstOperator.java +++ b/jode/jode/expr/ConstOperator.java @@ -22,6 +22,8 @@ package jode; public class ConstOperator extends NoArgOperator { String value; + boolean isInitializer = false; + public ConstOperator(Type type, String value) { super(type); this.value = value; @@ -40,7 +42,12 @@ public class ConstOperator extends NoArgOperator { ((ConstOperator)o).value.equals(value); } + public void makeInitializer() { + isInitializer = true; + } + public String toString(String[] operands) { + String value = this.value; if (type.isOfType(Type.tBoolean)) { if (value.equals("0")) return "false"; @@ -86,15 +93,15 @@ public class ConstOperator extends NoArgOperator { if (type.isOfType(Type.tUInt)) { int i = Integer.parseInt(value); if (i < -1) - return "~0x"+Integer.toHexString(-i-1); + value = "~0x"+Integer.toHexString(-i-1); else - return "0x"+Integer.toHexString(i); + value = "0x"+Integer.toHexString(i); } else if (type.equals(Type.tLong)) { long l = Long.parseLong(value); if (l < -1) - return "~0x"+Long.toHexString(-l-1)+"L"; + value = "~0x"+Long.toHexString(-l-1); else - return "0x"+Long.toHexString(l)+"L"; + value = "0x"+Long.toHexString(l); } } } @@ -102,6 +109,14 @@ public class ConstOperator extends NoArgOperator { return value+"L"; if (type.isOfType(Type.tFloat)) 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; } } diff --git a/jode/jode/expr/ConstantArrayOperator.java b/jode/jode/expr/ConstantArrayOperator.java index ae9bc39..b6dca4f 100644 --- a/jode/jode/expr/ConstantArrayOperator.java +++ b/jode/jode/expr/ConstantArrayOperator.java @@ -24,6 +24,7 @@ public class ConstantArrayOperator extends NoArgOperator { ConstOperator empty; Expression[] values; Type argType; + boolean isInitializer; public ConstantArrayOperator(Type type, int size) { super(type); @@ -31,6 +32,7 @@ public class ConstantArrayOperator extends NoArgOperator { argType = (type instanceof ArrayType) ? Type.tSubType(((ArrayType)type).getElementType()) : Type.tError; empty = new ConstOperator(argType, "0"); + empty.makeInitializer(); } public void setType(Type newtype) { @@ -54,6 +56,7 @@ public class ConstantArrayOperator extends NoArgOperator { setType(Type.tSuperType(Type.tArray(value.getType()))); values[index] = value; value.parent = this; + value.makeInitializer(); return true; } @@ -61,9 +64,13 @@ public class ConstantArrayOperator extends NoArgOperator { return 200; } + public void makeInitializer() { + isInitializer = true; + } + public String toString(String[] operands) { - StringBuffer result - = new StringBuffer("new ").append(type).append(" { "); + StringBuffer result = isInitializer ? new StringBuffer("{ ") + : new StringBuffer("new ").append(type).append(" { "); for (int i=0; i< values.length; i++) { if (i>0) result.append(", "); diff --git a/jode/jode/expr/Expression.java b/jode/jode/expr/Expression.java index b3596b4..07c394b 100644 --- a/jode/jode/expr/Expression.java +++ b/jode/jode/expr/Expression.java @@ -128,6 +128,13 @@ public abstract class Expression { public abstract Operator getOperator(); + public void makeInitializer() { + } + + public boolean isConstant() { + return true; + } + public abstract String toString(); String toString(int minPriority) { diff --git a/jode/jode/expr/GetFieldOperator.java b/jode/jode/expr/GetFieldOperator.java index 24268b2..ce4366e 100644 --- a/jode/jode/expr/GetFieldOperator.java +++ b/jode/jode/expr/GetFieldOperator.java @@ -59,9 +59,11 @@ public class GetFieldOperator extends Operator { public String toString(String[] operands) { return staticFlag ? (classType.equals(Type.tType(codeAnalyzer.getClazz())) + && codeAnalyzer.findLocal(fieldName) == null ? fieldName : classType.toString() + "." + fieldName) : (operands[0].equals("this") + && codeAnalyzer.findLocal(fieldName) == null ? fieldName : operands[0] + "." + fieldName); } diff --git a/jode/jode/expr/LocalLoadOperator.java b/jode/jode/expr/LocalLoadOperator.java index fb74613..4fe55fa 100644 --- a/jode/jode/expr/LocalLoadOperator.java +++ b/jode/jode/expr/LocalLoadOperator.java @@ -38,6 +38,10 @@ implements LocalVarOperator { return false; } + public boolean isConstant() { + return false; + } + // public void setLocalInfo(LocalInfo local) { // local.setType(type); // this.local = local; diff --git a/jode/jode/expr/PutFieldOperator.java b/jode/jode/expr/PutFieldOperator.java index a8bb80e..a065d4c 100644 --- a/jode/jode/expr/PutFieldOperator.java +++ b/jode/jode/expr/PutFieldOperator.java @@ -37,6 +37,14 @@ public class PutFieldOperator extends StoreInstruction { classType.useType(); } + public boolean isStatic() { + return staticFlag; + } + + public String getFieldName() { + return fieldName; + } + public boolean matches(Operator loadop) { return loadop instanceof GetFieldOperator && ((GetFieldOperator)loadop).classType.equals(classType) @@ -61,9 +69,11 @@ public class PutFieldOperator extends StoreInstruction { public String getLValueString(String[] operands) { return staticFlag ? (classType.equals(Type.tType(codeAnalyzer.getClazz())) + && codeAnalyzer.findLocal(fieldName) == null ? fieldName : classType.toString() + "." + fieldName) : (operands[0].equals("this") + && codeAnalyzer.findLocal(fieldName) == null ? fieldName : operands[0] + "." + fieldName); } diff --git a/jode/jode/expr/StoreInstruction.java b/jode/jode/expr/StoreInstruction.java index 8770451..5b6ae32 100644 --- a/jode/jode/expr/StoreInstruction.java +++ b/jode/jode/expr/StoreInstruction.java @@ -30,6 +30,10 @@ public abstract class StoreInstruction extends Operator { lvCasts = lvalueType.toString(); } + public Type getType() { + return type == Type.tVoid ? type : getLValueType(); + } + public Type getLValueType() { return lvalueType; } @@ -41,6 +45,8 @@ public abstract class StoreInstruction extends Operator { if (type != Type.tVoid) throw new AssertError("already non void"); type = lvalueType; + if (parent != null && parent.getOperator() == this) + parent.type = lvalueType; } public abstract boolean matches(Operator loadop); diff --git a/jode/jode/flow/CaseBlock.java b/jode/jode/flow/CaseBlock.java index 1e41162..a671cc0 100644 --- a/jode/jode/flow/CaseBlock.java +++ b/jode/jode/flow/CaseBlock.java @@ -136,6 +136,7 @@ public class CaseBlock extends StructuredBlock { ConstOperator constOp = new ConstOperator (((SwitchBlock)outer).getInstruction().getType(), Integer.toString(value)); + constOp.makeInitializer(); writer.println("case " + constOp.toString() + ":" + (wantBraces ? " {" : "")); } diff --git a/jode/jode/flow/CompleteSynchronized.java b/jode/jode/flow/CompleteSynchronized.java index 99c3f9a..8869f71 100644 --- a/jode/jode/flow/CompleteSynchronized.java +++ b/jode/jode/flow/CompleteSynchronized.java @@ -27,59 +27,67 @@ import jode.Expression; public class CompleteSynchronized { /** - * This combines the monitorenter and the initial expression - * into a synchronized statement + * This combines the monitorenter into a synchronized statement * @param flow The FlowBlock that is transformed */ - public static boolean transform(SynchronizedBlock synBlock, - StructuredBlock last) { + public static boolean enter(SynchronizedBlock synBlock, + StructuredBlock last) { if (!(last.outer instanceof SequentialBlock)) return false; - + /* If the program is well formed, the following succeed */ try { SequentialBlock sequBlock = (SequentialBlock) synBlock.outer; ComplexExpression monenter = (ComplexExpression) ((InstructionBlock) sequBlock.subBlocks[0]).getInstruction(); - + if (!(monenter.getOperator() instanceof MonitorEnterOperator) || ((LocalLoadOperator) monenter.getSubExpressions()[0]). getLocalInfo() != synBlock.local.getLocalInfo()) return false; - + } catch (ClassCastException ex) { return false; } - + if (jode.Decompiler.isVerbose) System.err.print('s'); - + synBlock.isEntered = true; synBlock.moveDefinitions(last.outer,last); 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? */ - if (!(last.outer instanceof SynchronizedBlock)) + if (!(last.outer instanceof SequentialBlock)) return false; Expression object; try { - SequentialBlock sequBlock = - (SequentialBlock) synBlock.outer; + SequentialBlock sequBlock = (SequentialBlock) last.outer; ComplexExpression assign = (ComplexExpression) ((InstructionBlock) sequBlock.subBlocks[0]).getInstruction(); if (((LocalStoreOperator) assign.getOperator()). getLocalInfo() != synBlock.local.getLocalInfo()) - return true; - + return false; + object = assign.getSubExpressions()[0]; } catch (ClassCastException ex) { - return true; + return false; } synBlock.object = object; diff --git a/jode/jode/flow/InstructionBlock.java b/jode/jode/flow/InstructionBlock.java index f314535..5d9a3d8 100644 --- a/jode/jode/flow/InstructionBlock.java +++ b/jode/jode/flow/InstructionBlock.java @@ -20,6 +20,7 @@ import jode.Expression; import jode.TabbedPrintWriter; import jode.LocalInfo; import jode.LocalStoreOperator; +import jode.ComplexExpression; /** * This is the structured block for atomic instructions. @@ -69,10 +70,13 @@ public class InstructionBlock extends InstructionContainer { throws java.io.IOException { if (isDeclaration) { - writer.println - (((LocalStoreOperator) instr.getOperator()) - .getLocalInfo().getType().toString() - + " " + instr.simplify().toString() + ";"); + LocalInfo local = ((LocalStoreOperator) instr.getOperator()) + .getLocalInfo(); + Expression expr = + ((ComplexExpression) instr).getSubExpressions()[0]; + expr.makeInitializer(); + writer.println(local.getType() + " " + local.getName() + " = " + + expr.simplify().toString() + ";"); } else { if (instr.getType() != jode.Type.tVoid) writer.print("PUSH "); diff --git a/jode/jode/flow/SequentialBlock.java b/jode/jode/flow/SequentialBlock.java index 064d0d7..17184bb 100644 --- a/jode/jode/flow/SequentialBlock.java +++ b/jode/jode/flow/SequentialBlock.java @@ -100,10 +100,22 @@ public class SequentialBlock extends StructuredBlock { * any local Variable, but lets the first sub block do this. */ 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].makeDeclaration(done); + /* Now add the variables to the done set, since the first + * sub block has declared them. + */ done.unionExact(used); 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) diff --git a/jode/jode/flow/StructuredBlock.java b/jode/jode/flow/StructuredBlock.java index dc8c6dc..1cb3d07 100644 --- a/jode/jode/flow/StructuredBlock.java +++ b/jode/jode/flow/StructuredBlock.java @@ -341,16 +341,23 @@ public abstract class StructuredBlock { declare = new VariableSet(); java.util.Enumeration enum = used.elements(); while (enum.hasMoreElements()) { - LocalInfo local = ((LocalInfo) enum.nextElement()).getLocalInfo(); - if (!declare.contains(local)) + LocalInfo local = (LocalInfo) enum.nextElement(); + LocalInfo previous = done.findLocal(local.getName()); + if (previous == null) 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(); for (int i=0; i