diff --git a/jode/ChangeLog b/jode/ChangeLog index 6789a6b..7ee8d6e 100644 --- a/jode/ChangeLog +++ b/jode/ChangeLog @@ -1,3 +1,38 @@ +2001-07-28 Jochen Hoenicke + + * jode/AssertError.java: removed, all uses are now replaced + by java.lang.InternalError. + * jode/Makefile.am: removed AssertError.java + * jode/bytecode/ClassInfo.java: reworked handling of inner + classes. + (extraClasses): removed, they are calculated automatically. + (hasInnerClassesAttr): new variable. + (readInnerClassesAttribute): Mark all classes in the constant + pool as having OUTERCLASS info filled. Don't handle extraClasses + specially. + (prepareWriting): Change for automatically generating outer + class info. + (getKnownAttributes): dito. + (writeKnownAttributes): dito. + (getExtraClasses): removed. + (setExtraClasses): removed. + + * jode/bytecode/ClassAnalyzer.java (conflicts): load or guess + declarations of info before getting inner classes. + * jode/decompiler/TabbedPrintWriter.java (BreakPoint.endOp): + Set options correctly. + * jode/expr/InvokeOperator.java (getMethodInfo): load or guess + declarations before accessing methods. + * jode/flow/FlowBlock.java (resolveSomeJumps): When creating a + if-then-else move the jump from the then branch to the if, before + restarting analysis. + (doT1): handle the case when lastModified.jump is null. Throw + statements have no jump now. + * jode/jvm/SyntheticAnalyzer (checkAccess): Fix the detection for + PUTDUPSTATIC/FIELD. + * jode/type/ClassType.java (getCastHelper): More checks when + cast is not needed: interfaces and null pointer. + 2001-07-15 Jochen Hoenicke * jode/decompiler/Decompiler.java (decompile): removed setClassPath call. ClassInfo.forName() is no longer used. diff --git a/jode/jode/AssertError.java b/jode/jode/AssertError.java deleted file mode 100644 index 1557f8d..0000000 --- a/jode/jode/AssertError.java +++ /dev/null @@ -1,29 +0,0 @@ -/* AssertError Copyright (C) 1998-1999 Jochen Hoenicke. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; see the file COPYING. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * - * $Id$ - */ - -package jode; - -public class AssertError extends Error { - public AssertError() { - } - - public AssertError(String detail) { - super(detail); - } -} diff --git a/jode/jode/Makefile.am b/jode/jode/Makefile.am index 5507214..6b58cac 100644 --- a/jode/jode/Makefile.am +++ b/jode/jode/Makefile.am @@ -11,7 +11,6 @@ SUBSTCP = @SUBSTCP@ FULL_CLASSPATH := $(shell $(SUBSTCP) $(top_srcdir):$(top_builddir):$(CLASSPATH):$(CLASSLIB)) MY_JAVA_FILES = \ - AssertError.java \ GlobalOptions.java noinst_DATA = $(MY_JAVA_FILES:.java=.class) diff --git a/jode/jode/bytecode/ClassInfo.java b/jode/jode/bytecode/ClassInfo.java index 3e9ddca..6298d8e 100644 --- a/jode/jode/bytecode/ClassInfo.java +++ b/jode/jode/bytecode/ClassInfo.java @@ -34,8 +34,9 @@ import java.security.NoSuchAlgorithmException; ///#def COLLECTIONS java.util import java.util.Arrays; import java.util.Iterator; -import java.util.LinkedList; import java.util.ListIterator; +import java.util.List; +import java.util.ArrayList; ///#enddef ///#def COLLECTIONEXTRA java.lang import java.lang.Comparable; @@ -239,10 +240,10 @@ public final class ClassInfo extends BinaryInfo implements Comparable { private ClassInfo outerClass; private ClassInfo[] interfaces; private ClassInfo[] innerClasses; - private ClassInfo[] extraClasses; private FieldInfo[] fields; private MethodInfo[] methods; private String sourceFile; + private boolean hasInnerClassesAttr; /** * This constant can be used as parameter to drop. It specifies @@ -469,6 +470,8 @@ public final class ClassInfo extends BinaryInfo implements Comparable { * * doesn't work. */ + + hasInnerClassesAttr = true; int count = input.readUnsignedShort(); if (length != 2 + 8 * count) @@ -559,12 +562,21 @@ public final class ClassInfo extends BinaryInfo implements Comparable { } else innerClasses = null; - if (extraCount > 0) { - extraClasses = new ClassInfo[extraCount]; - for (int i = 0; i < extraCount; i++) - extraClasses[i] = innerExtra[count - i - 1]; - } else - extraClasses = null; + /* All remaining classes that are mentioned in the constant + * pool must have an empty outer class info. This is + * specified in the 2nd edition of the JVM specification. + */ + for (int i = 1; i < cp.size(); i++) { + if (cp.tags[i] == cp.CLASS) { + String clName = cp.getUTF8(cp.indices1[i]); + if (clName.charAt(0) != '[') { + ClassInfo ci = classpath.getClassInfo + (clName.replace('/','.')); + if (ci.status < OUTERCLASS) + ci.mergeOuterInfo(null, null, -1, false); + } + } + } } void readAttribute(String name, int length, @@ -810,9 +822,9 @@ public final class ClassInfo extends BinaryInfo implements Comparable { private void prepareWriting(GrowableConstantPool gcp) { gcp.putClassName(name); - gcp.putClassName(superclass.getName()); + gcp.putClassName(superclass.name); for (int i=0; i < interfaces.length; i++) - gcp.putClassName(interfaces[i].getName()); + gcp.putClassName(interfaces[i].name); for (int i=0; i < fields.length; i++) fields[i].prepareWriting(gcp); @@ -820,52 +832,46 @@ public final class ClassInfo extends BinaryInfo implements Comparable { for (int i=0; i < methods.length; i++) methods[i].prepareWriting(gcp); + for (int i=0; i < innerClasses.length; i++) + gcp.putClassName(innerClasses[i].name); + if (sourceFile != null) { gcp.putUTF8("SourceFile"); gcp.putUTF8(sourceFile); } - if (outerClass != null || methodScoped - || innerClasses != null || extraClasses != null) { - gcp.putUTF8("InnerClasses"); - - ClassInfo outer = this; - while (outer.outerClass != null || outer.methodScoped) { - if (outer.status <= OUTERCLASS) - throw new IllegalStateException - (outer.name + "'s state is " + outer.status); - if (outer.className != null) - gcp.putClassName(outer.className); - if (outer.outerClass == null) - break; - gcp.putClassName(outer.outerClass.name); - outer = outer.outerClass; - } - int innerCount = innerClasses != null ? innerClasses.length : 0; - for (int i = innerCount; i-- > 0; i++) { - if (innerClasses[i].status <= OUTERCLASS) - throw new IllegalStateException - (innerClasses[i].name + "'s state is " - + innerClasses[i].status); - if (innerClasses[i].outerClass != this) - throw new IllegalStateException - (innerClasses[i].name + "'s outer is " + - innerClasses[i].outerClass.name); - - gcp.putClassName(innerClasses[i].name); - if (innerClasses[i].className != null) - gcp.putUTF8(innerClasses[i].className); - } - int extraCount = extraClasses != null ? extraClasses.length : 0; - for (int i=extraCount; i-- >= 0; ) { - if (extraClasses[i].status <= OUTERCLASS) - throw new IllegalStateException - (extraClasses[i].name + "'s state is " - + extraClasses[i].status); - gcp.putClassName(extraClasses[i].name); - if (extraClasses[i].outerClass != null) - gcp.putClassName(extraClasses[i].outerClass.name); - if (extraClasses[i].className != null) - gcp.putUTF8(extraClasses[i].className); + + /* All classes mentioned in the constant pool must have an + * outer class info. This is clearly specified in the 2nd + * edition of the JVM specification. + */ + hasInnerClassesAttr = false; + for (int i = 1; i < gcp.size(); i++) { + if (gcp.tags[i] == gcp.CLASS) { + String clName; + try { + clName = gcp.getUTF8(gcp.indices1[i]); + } catch (ClassFormatException ex) { + throw new InternalError(ex.getMessage()); + } + if (clName.charAt(0) != '[') { + ClassInfo ci = classpath.getClassInfo + (clName.replace('/','.')); + if (ci.status < OUTERCLASS) { + GlobalOptions.err.println + ("WARNING: "+ ci.name + + "'s outer class isn't known."); + } else { + if ((ci.outerClass != null || ci.methodScoped) + && ! hasInnerClassesAttr) { + gcp.putUTF8("innerClasses"); + hasInnerClassesAttr = true; + } + if (ci.outerClass != null) + gcp.putClassName(ci.outerClass.name); + if (ci.className != null) + gcp.putUTF8(ci.className); + } + } } } prepareAttributes(gcp); @@ -875,8 +881,7 @@ public final class ClassInfo extends BinaryInfo implements Comparable { int count = 0; if (sourceFile != null) count++; - if (outerClass != null || methodScoped - || innerClasses != null || extraClasses != null) + if (hasInnerClassesAttr) count++; return count; } @@ -889,71 +894,48 @@ public final class ClassInfo extends BinaryInfo implements Comparable { output.writeInt(2); output.writeShort(gcp.putUTF8(sourceFile)); } - if (outerClass != null || methodScoped - || innerClasses != null || extraClasses != null) { - // XXX TODO: Closeness of extra outer information. - gcp.putUTF8("InnerClasses"); - - ClassInfo outer; - LinkedList outerExtraClasses = new LinkedList(); - - outer = this; - while (outer.outerClass != null || outer.methodScoped) { - /* Outers must be written in backward order, so we - * add them to the beginning of the list. - */ - outerExtraClasses.add(0, outer); - if (outer.outerClass == null) - break; - outer = outer.outerClass; - } - if (extraClasses != null) { - int extraCount = extraClasses.length; - for (int i = 0; i < extraCount; i++) { - outer = extraClasses[i]; - ListIterator insertIter - = outerExtraClasses.listIterator - (outerExtraClasses.size()); - int insertPos = outerExtraClasses.size(); - while (outer.outerClass != null || outer.methodScoped) { - if (outerExtraClasses.contains(outer)) - break; - /* We have to add outers in reverse order to the - * end of the list. We use the insertIter to do - * this trick. + + List outers = new ArrayList(); + for (int i = 0; i < gcp.size(); i++) { + if (gcp.tags[i] == gcp.CLASS) { + String clName; + try { + clName = gcp.getUTF8(gcp.indices1[i]); + } catch (ClassFormatException ex) { + throw new InternalError(ex.getMessage()); + } + if (clName.charAt(0) != '[') { + ClassInfo ci = classpath.getClassInfo + (clName.replace('/','.')); + while (ci.status >= OUTERCLASS + && ci.outerClass != null || ci.methodScoped) { + /* Order is important so remove ci if it + * already exists and add it to the end. This + * way the outermost classes go to the end. */ - insertIter.add(outer); - insertIter.previous(); - if (outer.outerClass == null) - break; - outer = outer.outerClass; + outers.remove(ci); + outers.add(ci); + ci = ci.outerClass; } } } - - int innerCount = (innerClasses != null) ? innerClasses.length : 0; - int count = outerExtraClasses.size() + innerCount; + } + if (hasInnerClassesAttr) { + int count = outers.size(); + output.writeShort(gcp.putUTF8("InnerClasses")); output.writeInt(2 + count * 8); output.writeShort(count); - for (Iterator i = outerExtraClasses.iterator(); i.hasNext(); ) { - outer = (ClassInfo) i.next(); + ListIterator iter = outers.listIterator(count); + while (iter.hasPrevious()) { + ClassInfo ci = (ClassInfo) iter.previous(); - output.writeShort(gcp.putClassName(outer.name)); - output.writeShort(outer.outerClass == null ? 0 : - gcp.putClassName(outer.outerClass.name)); - output.writeShort(outer.className == null ? 0 : - gcp.putUTF8(outer.className)); - output.writeShort(outer.modifiers); - } - for (int i = innerCount; i-- > 0; i++) { - output.writeShort(gcp.putClassName(innerClasses[i].name)); - output.writeShort(innerClasses[i].outerClass != null ? - gcp.putClassName(innerClasses[i] - .outerClass.name) : 0); - output.writeShort(innerClasses[i].className != null ? - gcp.putUTF8(innerClasses[i].className) : 0); - output.writeShort(innerClasses[i].modifiers); + output.writeShort(gcp.putClassName(ci.name)); + output.writeShort(ci.outerClass == null ? 0 : + gcp.putClassName(ci.outerClass.name)); + output.writeShort(ci.className == null ? 0 : + gcp.putUTF8(ci.className)); + output.writeShort(ci.modifiers); } } } @@ -1122,7 +1104,6 @@ public final class ClassInfo extends BinaryInfo implements Comparable { methodScoped = false; outerClass = null; innerClasses = null; - extraClasses = null; } if (keep < PUBLICDECLARATIONS) { @@ -1285,12 +1266,6 @@ public final class ClassInfo extends BinaryInfo implements Comparable { return innerClasses; } - public ClassInfo[] getExtraClasses() { - if (status < OUTERCLASS) - throw new IllegalStateException("status is "+status); - return extraClasses; - } - public String getSourceFile() { return sourceFile; } @@ -1340,11 +1315,6 @@ public final class ClassInfo extends BinaryInfo implements Comparable { modified = true; } - public void setExtraClasses(ClassInfo[] ec) { - extraClasses = ec; - modified = true; - } - public void setSourceFile(String newSource) { sourceFile = newSource; modified = true; diff --git a/jode/jode/bytecode/TypeSignature.java b/jode/jode/bytecode/TypeSignature.java index 566fba6..e633c44 100644 --- a/jode/jode/bytecode/TypeSignature.java +++ b/jode/jode/bytecode/TypeSignature.java @@ -18,7 +18,6 @@ */ package jode.bytecode; -import jode.AssertError; import jode.util.UnifyHash; /** @@ -51,7 +50,7 @@ public class TypeSignature { else if (javaType == Void.TYPE) return sb.append('V'); else - throw new AssertError("Unknown primitive type: "+javaType); + throw new InternalError("Unknown primitive type: "+javaType); } else if (javaType.isArray()) { return appendSignature(sb.append('['), javaType.getComponentType()); diff --git a/jode/jode/decompiler/ClassAnalyzer.java b/jode/jode/decompiler/ClassAnalyzer.java index 7a638a8..e2b1f07 100644 --- a/jode/jode/decompiler/ClassAnalyzer.java +++ b/jode/jode/decompiler/ClassAnalyzer.java @@ -705,6 +705,11 @@ public class ClassAnalyzer } } if (usageType == CLASSNAME || usageType == AMBIGUOUSNAME) { + try { + info.load(info.DECLARATIONS); + } catch (IOException ex) { + info.guess(info.DECLARATIONS); + } ClassInfo[] iinfos = info.getClasses(); if (iinfos != null) { for (int i=0; i < iinfos.length; i++) { diff --git a/jode/jode/decompiler/LocalInfo.java b/jode/jode/decompiler/LocalInfo.java index 9e2df66..7cedffe 100644 --- a/jode/jode/decompiler/LocalInfo.java +++ b/jode/jode/decompiler/LocalInfo.java @@ -141,7 +141,7 @@ public class LocalInfo implements Declarable { shadow.name = name; if (constExpr != null) { if (shadow.constExpr != null) - throw new jode.AssertError + throw new InternalError ("local has multiple constExpr"); shadow.constExpr = constExpr; } diff --git a/jode/jode/decompiler/MethodAnalyzer.java b/jode/jode/decompiler/MethodAnalyzer.java index 7ed3c39..9423c63 100644 --- a/jode/jode/decompiler/MethodAnalyzer.java +++ b/jode/jode/decompiler/MethodAnalyzer.java @@ -18,7 +18,6 @@ */ package jode.decompiler; -import jode.AssertError; import jode.GlobalOptions; import jode.bytecode.BasicBlocks; import jode.bytecode.Block; @@ -572,7 +571,7 @@ public class MethodAnalyzer implements Scope, ClassDeclarer { verifier.verify(); } catch (VerifyException ex) { ex.printStackTrace(GlobalOptions.err); - throw new jode.AssertError("Verification error"); + throw new InternalError("Verification error"); } } } diff --git a/jode/jode/decompiler/Opcodes.java b/jode/jode/decompiler/Opcodes.java index 29b99a5..86de104 100644 --- a/jode/jode/decompiler/Opcodes.java +++ b/jode/jode/decompiler/Opcodes.java @@ -425,7 +425,7 @@ public abstract class Opcodes implements jode.bytecode.Opcodes { opcode - (opc_ifnull-Operator.COMPARE_OP)))); break; default: - throw new jode.AssertError("Invalid opcode "+opcode); + throw new InternalError("Invalid opcode "+opcode); } } } diff --git a/jode/jode/decompiler/TabbedPrintWriter.java b/jode/jode/decompiler/TabbedPrintWriter.java index 3769fdd..33ec13e 100644 --- a/jode/jode/decompiler/TabbedPrintWriter.java +++ b/jode/jode/decompiler/TabbedPrintWriter.java @@ -22,7 +22,6 @@ import java.io.*; import java.util.Stack; import java.util.Vector; import java.util.Enumeration; -import jode.AssertError; import jode.GlobalOptions; import jode.bytecode.ClassInfo; import jode.type.*; @@ -131,9 +130,8 @@ public class TabbedPrintWriter { * our child, if possible. */ BreakPoint child = (BreakPoint) childBPs.elementAt(0); - options = child.options; + options = Math.min(options, child.options); startPos = child.startPos; - options = child.options; endPos = child.endPos; breakPenalty = child.breakPenalty; childBPs = child.childBPs; diff --git a/jode/jode/expr/ConstOperator.java b/jode/jode/expr/ConstOperator.java index c7fa123..ea779b0 100644 --- a/jode/jode/expr/ConstOperator.java +++ b/jode/jode/expr/ConstOperator.java @@ -123,7 +123,7 @@ public class ConstOperator extends NoArgOperator { else if (intVal == 1) return "true"; else - throw new jode.AssertError + throw new InternalError ("boolean is neither false nor true"); } if (type.getHint().equals(Type.tChar)) { diff --git a/jode/jode/expr/FieldOperator.java b/jode/jode/expr/FieldOperator.java index ac55209..a42a78b 100644 --- a/jode/jode/expr/FieldOperator.java +++ b/jode/jode/expr/FieldOperator.java @@ -132,7 +132,7 @@ public abstract class FieldOperator extends Operator { else if (ana.getParent() instanceof ClassAnalyzer) ana = (ClassAnalyzer) ana.getParent(); else - throw new jode.AssertError("Unknown parent"); + throw new InternalError("Unknown parent"); } } return null; diff --git a/jode/jode/expr/IIncOperator.java b/jode/jode/expr/IIncOperator.java index 0d1f5ee..f0e4b92 100644 --- a/jode/jode/expr/IIncOperator.java +++ b/jode/jode/expr/IIncOperator.java @@ -61,7 +61,7 @@ public class IIncOperator extends Operator */ public void makeNonVoid() { if (type != Type.tVoid) - throw new jode.AssertError("already non void"); + throw new InternalError("already non void"); type = subExpressions[0].getType(); } diff --git a/jode/jode/expr/InvokeOperator.java b/jode/jode/expr/InvokeOperator.java index ad92ef3..aa4a040 100644 --- a/jode/jode/expr/InvokeOperator.java +++ b/jode/jode/expr/InvokeOperator.java @@ -213,6 +213,11 @@ public final class InvokeOperator extends Operator private static MethodInfo getMethodInfo(ClassInfo clazz, String name, String type) { while (clazz != null) { + try { + clazz.load(clazz.DECLARATIONS); + } catch (IOException ex) { + clazz.guess(clazz.DECLARATIONS); + } MethodInfo method = clazz.findMethod(name, type); if (method != null) return method; @@ -268,7 +273,7 @@ public final class InvokeOperator extends Operator */ public void makeNonVoid() { if (type != Type.tVoid) - throw new jode.AssertError("already non void"); + throw new InternalError("already non void"); ClassInfo clazz = classInfo; if (clazz != null && clazz.isMethodScoped() && clazz.getClassName() == null) { @@ -340,7 +345,7 @@ public final class InvokeOperator extends Operator & Options.OPTION_INNER) != 0) ana = (ClassAnalyzer) ana.getParent(); else - throw new jode.AssertError + throw new InternalError ("Unknown parent: "+ana+": "+ana.getParent()); } } @@ -379,7 +384,7 @@ public final class InvokeOperator extends Operator & Options.OPTION_INNER) != 0) ana = (ClassAnalyzer) ana.getParent(); else - throw new jode.AssertError + throw new InternalError ("Unknown parent: "+ana+": "+ana.getParent()); } } diff --git a/jode/jode/expr/NoArgOperator.java b/jode/jode/expr/NoArgOperator.java index ab03f0b..0d493fe 100644 --- a/jode/jode/expr/NoArgOperator.java +++ b/jode/jode/expr/NoArgOperator.java @@ -19,7 +19,6 @@ package jode.expr; import jode.type.Type; -import jode.AssertError; import jode.decompiler.TabbedPrintWriter; public abstract class NoArgOperator extends Operator { diff --git a/jode/jode/expr/Operator.java b/jode/jode/expr/Operator.java index f1c5cee..ac41b99 100644 --- a/jode/jode/expr/Operator.java +++ b/jode/jode/expr/Operator.java @@ -71,7 +71,7 @@ public abstract class Operator extends Expression { super(type); this.operatorIndex = op; if (type == null) - throw new jode.AssertError("type == null"); + throw new InternalError("type == null"); } public void initOperands(int opcount) { @@ -118,7 +118,7 @@ public abstract class Operator extends Expression { return this; } } - throw new jode.AssertError("addOperand called, but no operand needed"); + throw new InternalError("addOperand called, but no operand needed"); } public Operator getOperator() { diff --git a/jode/jode/expr/StoreInstruction.java b/jode/jode/expr/StoreInstruction.java index 1870977..feccc88 100644 --- a/jode/jode/expr/StoreInstruction.java +++ b/jode/jode/expr/StoreInstruction.java @@ -49,7 +49,7 @@ public class StoreInstruction extends Operator */ public void makeNonVoid() { if (type != Type.tVoid) - throw new jode.AssertError("already non void"); + throw new InternalError("already non void"); type = subExpressions[0].getType(); } diff --git a/jode/jode/flow/CaseBlock.java b/jode/jode/flow/CaseBlock.java index b21712d..c9d43f2 100644 --- a/jode/jode/flow/CaseBlock.java +++ b/jode/jode/flow/CaseBlock.java @@ -67,7 +67,7 @@ public class CaseBlock extends StructuredBlock { public void checkConsistent() { if (!(outer instanceof SwitchBlock)) - throw new jode.AssertError("Inconsistency"); + throw new InternalError("Inconsistency"); super.checkConsistent(); } diff --git a/jode/jode/flow/ConditionalBlock.java b/jode/jode/flow/ConditionalBlock.java index a223d3d..de1c0ac 100644 --- a/jode/jode/flow/ConditionalBlock.java +++ b/jode/jode/flow/ConditionalBlock.java @@ -37,7 +37,7 @@ public class ConditionalBlock extends InstructionContainer { public void checkConsistent() { super.checkConsistent(); if (!(trueBlock instanceof EmptyBlock)) - throw new jode.AssertError("Inconsistency"); + throw new InternalError("Inconsistency"); } /** @@ -84,7 +84,7 @@ public class ConditionalBlock extends InstructionContainer { */ public boolean replaceSubBlock(StructuredBlock oldBlock, StructuredBlock newBlock) { - throw new jode.AssertError("replaceSubBlock on ConditionalBlock"); + throw new InternalError("replaceSubBlock on ConditionalBlock"); } /** diff --git a/jode/jode/flow/FlowBlock.java b/jode/jode/flow/FlowBlock.java index 083ab05..17b031a 100644 --- a/jode/jode/flow/FlowBlock.java +++ b/jode/jode/flow/FlowBlock.java @@ -19,7 +19,6 @@ package jode.flow; import jode.GlobalOptions; -import jode.AssertError; import jode.decompiler.TabbedPrintWriter; import jode.decompiler.MethodAnalyzer; import jode.decompiler.LocalInfo; @@ -427,7 +426,7 @@ public class FlowBlock { } - /* Now find the real outer block, that is ascend the + /* Now find the real outer block, i.e. traverse the * chain of SequentialBlocks. * * Note that only the last instr in a SequentialBlock chain @@ -511,10 +510,13 @@ public class FlowBlock { } lastModified = ifBlock; } + + ifBlock.moveJump(jump); /* Consider all jumps again, since the ones that moved * into the thenBlock may be obsolete now. * XXX only jumps in then should be considered. + * XXX I'm not sure if this is complete. */ if (remainingJumps == null) jumps = jump; @@ -525,9 +527,6 @@ public class FlowBlock { remainingJumps.next = jump; remainingJumps = null; } - /* consider this jump again */ -// ifBlock.moveJump(jump); -// jumps = jump; continue; } } @@ -806,7 +805,7 @@ public class FlowBlock { try { if (block.outer != null || block.flowBlock != this) { - throw new AssertError("Inconsistency: outer:"+block.outer+" block.flow"+block.flowBlock +" this: "+this); + throw new InternalError("Inconsistency: outer:"+block.outer+" block.flow"+block.flowBlock +" this: "+this); } block.checkConsistent(); @@ -816,7 +815,7 @@ public class FlowBlock { /* The special start marker */ continue; if (!pred.successors.containsKey(this)) - throw new AssertError("Inconsistency"); + throw new InternalError("Inconsistency"); } StructuredBlock last = lastModified; @@ -824,28 +823,28 @@ public class FlowBlock { || last.outer instanceof TryBlock) last = last.outer; if (last.outer != null) - throw new AssertError("Inconsistency"); + throw new InternalError("Inconsistency"); Iterator iter = successors.entrySet().iterator(); while (iter.hasNext()) { Map.Entry entry = (Map.Entry) iter.next(); FlowBlock dest = (FlowBlock) entry.getKey(); if (dest.predecessors.contains(this) == (dest == END_OF_METHOD)) - throw new AssertError("Inconsistency"); + throw new InternalError("Inconsistency"); Jump jumps = ((SuccessorInfo) entry.getValue()).jumps; if (jumps == null) - throw new AssertError("Inconsistency"); + throw new InternalError("Inconsistency"); for (; jumps != null; jumps = jumps.next) { if (jumps.destination != dest) - throw new AssertError("Inconsistency"); + throw new InternalError("Inconsistency"); if (jumps.prev == null || jumps.prev.flowBlock != this || jumps.prev.jump != jumps) - throw new AssertError("Inconsistency"); + throw new InternalError("Inconsistency"); prev_loop: for (StructuredBlock prev = jumps.prev; prev != block; @@ -858,11 +857,11 @@ public class FlowBlock { if (blocks[i] == prev) continue prev_loop; - throw new AssertError("Inconsistency"); + throw new InternalError("Inconsistency"); } } } - } catch (AssertError err) { + } catch (InternalError err) { GlobalOptions.err.println("Inconsistency in: "+this); throw err; } @@ -1267,7 +1266,8 @@ public class FlowBlock { /* Now remove the jump of lastModified if it points to this. */ - if (lastModified.jump.destination == this) + if (lastModified.jump != null + && lastModified.jump.destination == this) lastModified.removeJump(); } @@ -1634,7 +1634,7 @@ public class FlowBlock { */ public void mapStackToLocal(VariableStack initialStack) { if (initialStack == null) - throw new jode.AssertError("initial stack is null"); + throw new InternalError("initial stack is null"); stackMap = initialStack; block.mapStackToLocal(initialStack); Iterator iter = successors.values().iterator(); diff --git a/jode/jode/flow/SequentialBlock.java b/jode/jode/flow/SequentialBlock.java index d4caac5..2722924 100644 --- a/jode/jode/flow/SequentialBlock.java +++ b/jode/jode/flow/SequentialBlock.java @@ -57,7 +57,7 @@ public class SequentialBlock extends StructuredBlock { if (subBlocks[0].jump != null || subBlocks[0] instanceof SequentialBlock || jump != null) - throw new jode.AssertError("Inconsistency"); + throw new InternalError("Inconsistency"); } /** diff --git a/jode/jode/flow/SlotSet.java b/jode/jode/flow/SlotSet.java index f5bc852..d617ad0 100644 --- a/jode/jode/flow/SlotSet.java +++ b/jode/jode/flow/SlotSet.java @@ -165,7 +165,7 @@ public final class SlotSet extends AbstractSet implements Cloneable { } return other; } catch (CloneNotSupportedException ex) { - throw new jode.AssertError("Clone?"); + throw new InternalError("Clone?"); } } diff --git a/jode/jode/flow/StructuredBlock.java b/jode/jode/flow/StructuredBlock.java index 9168032..47fde5d 100644 --- a/jode/jode/flow/StructuredBlock.java +++ b/jode/jode/flow/StructuredBlock.java @@ -18,7 +18,6 @@ */ package jode.flow; -import jode.AssertError; import jode.GlobalOptions; import jode.decompiler.TabbedPrintWriter; import jode.decompiler.LocalInfo; @@ -277,7 +276,7 @@ public abstract class StructuredBlock { */ public void moveJump(Jump jump) { if (this.jump != null) - throw new AssertError("overriding with moveJump()"); + throw new InternalError("overriding with moveJump()"); this.jump = jump; if (jump != null) { jump.prev.jump = null; @@ -292,7 +291,7 @@ public abstract class StructuredBlock { */ public void copyJump(Jump jump) { if (this.jump != null) - throw new AssertError("overriding with moveJump()"); + throw new InternalError("overriding with moveJump()"); if (jump != null) { this.jump = new Jump(jump); this.jump.prev = this; @@ -546,7 +545,7 @@ public abstract class StructuredBlock { for (int i=0; i end || handler <= end) - throw new AssertError + throw new InternalError ("ExceptionHandler order failed: not " + start + " < " + end + " <= " + handler); if (last != null @@ -840,7 +839,7 @@ public class TransformExceptionHandlers { */ if (end >= last.start.getBlockNr() && end < last.end.getBlockNr()) - throw new AssertError + throw new InternalError ("Exception handlers ranges are intersecting: [" + last.start.getBlockNr()+", " + last.end.getBlockNr()+"] and [" @@ -894,7 +893,7 @@ public class TransformExceptionHandlers { ("Warning: Can't completely analyze try."); TryBlock tryBlock = new TryBlock(tryFlow); } else if (!(tryFlow.block instanceof TryBlock)) - throw new AssertError("no TryBlock"); + throw new InternalError("no TryBlock"); FlowBlock catchFlow = exc.handler; boolean isMultiUsed = catchFlow.predecessors.size() != 0; diff --git a/jode/jode/flow/VariableSet.java b/jode/jode/flow/VariableSet.java index 1e3d872..14bb715 100644 --- a/jode/jode/flow/VariableSet.java +++ b/jode/jode/flow/VariableSet.java @@ -181,7 +181,7 @@ public final class VariableSet extends AbstractSet implements Cloneable { } return other; } catch (CloneNotSupportedException ex) { - throw new jode.AssertError("Clone?"); + throw new InternalError("Clone?"); } } diff --git a/jode/jode/flow/VariableStack.java b/jode/jode/flow/VariableStack.java index b465663..1b6c4b7 100644 --- a/jode/jode/flow/VariableStack.java +++ b/jode/jode/flow/VariableStack.java @@ -161,7 +161,7 @@ public class VariableStack { newStack[stackMap.length-1] = stackMap[stackMap.length-2]; return new VariableStack(newStack); } else - throw new jode.AssertError("Unknown SpecialBlock"); + throw new InternalError("Unknown SpecialBlock"); } public String toString() { diff --git a/jode/jode/jvm/CodeVerifier.java b/jode/jode/jvm/CodeVerifier.java index f5ccbc0..0138240 100644 --- a/jode/jode/jvm/CodeVerifier.java +++ b/jode/jode/jvm/CodeVerifier.java @@ -18,7 +18,6 @@ */ package jode.jvm; -import jode.AssertError; import jode.GlobalOptions; import jode.bytecode.BasicBlocks; import jode.bytecode.Block; @@ -500,7 +499,7 @@ public class CodeVerifier implements Opcodes { result.jsrInfo = new JsrUsedInfo(jsrInfo); return result; } catch(CloneNotSupportedException ex) { - throw new AssertError("Clone not supported?"); + throw new InternalError("Clone not supported?"); } } @@ -1216,7 +1215,7 @@ public class CodeVerifier implements Opcodes { break; } default: - throw new AssertError("Invalid opcode "+opcode); + throw new InternalError("Invalid opcode "+opcode); } } diff --git a/jode/jode/jvm/Interpreter.java b/jode/jode/jvm/Interpreter.java index b3d4315..a4934a6 100644 --- a/jode/jode/jvm/Interpreter.java +++ b/jode/jode/jvm/Interpreter.java @@ -18,7 +18,6 @@ */ package jode.jvm; -import jode.AssertError; import jode.GlobalOptions; import jode.bytecode.BasicBlocks; import jode.bytecode.Block; @@ -747,7 +746,7 @@ public class Interpreter implements Opcodes { break; } default: - throw new AssertError("Invalid opcode "+opcode); + throw new InternalError("Invalid opcode "+opcode); } } catch (InvocationTargetException ex) { iter = null; diff --git a/jode/jode/jvm/SimpleRuntimeEnvironment.java b/jode/jode/jvm/SimpleRuntimeEnvironment.java index a6383f9..a379a47 100644 --- a/jode/jode/jvm/SimpleRuntimeEnvironment.java +++ b/jode/jode/jvm/SimpleRuntimeEnvironment.java @@ -18,7 +18,6 @@ */ package jode.jvm; -import jode.AssertError; import jode.bytecode.Reference; import jode.bytecode.TypeSignature; diff --git a/jode/jode/jvm/SyntheticAnalyzer.java b/jode/jode/jvm/SyntheticAnalyzer.java index 853fd66..f2aa125 100644 --- a/jode/jode/jvm/SyntheticAnalyzer.java +++ b/jode/jode/jvm/SyntheticAnalyzer.java @@ -269,6 +269,9 @@ public class SyntheticAnalyzer implements Opcodes { if ((refField.getModifiers() & modifierMask) != 0) return false; if (dupSeen) { + if (!iter.hasNext()) + return false; + instr = (Instruction) iter.next(); if (instr.getOpcode() < opc_ireturn || instr.getOpcode() > opc_areturn) return false; diff --git a/jode/jode/obfuscator/MethodIdentifier.java b/jode/jode/obfuscator/MethodIdentifier.java index d9cdcd1..0262a5c 100644 --- a/jode/jode/obfuscator/MethodIdentifier.java +++ b/jode/jode/obfuscator/MethodIdentifier.java @@ -18,7 +18,6 @@ */ package jode.obfuscator; -import jode.AssertError; import jode.GlobalOptions; import jode.bytecode.*; @@ -173,7 +172,7 @@ public class MethodIdentifier extends Identifier implements Opcodes { boolean wasTransformed = false; public void doTransformations() { if (wasTransformed) - throw new jode.AssertError + throw new InternalError ("doTransformation called on transformed method"); wasTransformed = true; info.setName(getAlias()); diff --git a/jode/jode/obfuscator/modules/ConstantAnalyzer.java b/jode/jode/obfuscator/modules/ConstantAnalyzer.java index 0b585b9..517e7ea 100644 --- a/jode/jode/obfuscator/modules/ConstantAnalyzer.java +++ b/jode/jode/obfuscator/modules/ConstantAnalyzer.java @@ -19,7 +19,6 @@ package jode.obfuscator.modules; -import jode.AssertError; import jode.GlobalOptions; import jode.bytecode.*; import jode.jvm.InterpreterException; @@ -459,10 +458,10 @@ public class ConstantAnalyzer implements Opcodes, CodeAnalyzer { for (int i=0; i < locals.length; i++) mergeOneLocal(i, other.locals[i]); if (stack.length != other.stack.length) - throw new jode.AssertError("stack length differs"); + throw new InternalError("stack length differs"); for (int i=0; i < stack.length; i++) { if ((other.stack[i] == null) != (stack[i] == null)) - throw new jode.AssertError("stack types differ"); + throw new InternalError("stack types differ"); else if (stack[i] != null) stack[i].merge(other.stack[i]); } @@ -1183,7 +1182,7 @@ public class ConstantAnalyzer implements Opcodes, CodeAnalyzer { % ((Double)value2.value).doubleValue()); break; default: - throw new jode.AssertError("Can't happen."); + throw new InternalError("Can't happen."); } ConstantInfo constInfo = new ConstantInfo(CONSTANT, newValue); constantInfos.put(instr, constInfo); @@ -1218,7 +1217,7 @@ public class ConstantAnalyzer implements Opcodes, CodeAnalyzer { (- ((Double)value.value).doubleValue()); break; default: - throw new jode.AssertError("Can't happen."); + throw new InternalError("Can't happen."); } ConstantInfo constInfo = new ConstantInfo(CONSTANT, newValue); constantInfos.put(instr, constInfo); @@ -1271,7 +1270,7 @@ public class ConstantAnalyzer implements Opcodes, CodeAnalyzer { >>> ((Integer)value2.value).intValue()); break; default: - throw new jode.AssertError("Can't happen."); + throw new InternalError("Can't happen."); } ConstantInfo constInfo = new ConstantInfo(CONSTANT, newValue); constantInfos.put(instr, constInfo); @@ -1316,7 +1315,7 @@ public class ConstantAnalyzer implements Opcodes, CodeAnalyzer { newVal = new Double(((Number)stack.value).doubleValue()); break; default: - throw new jode.AssertError("Can't happen."); + throw new InternalError("Can't happen."); } ConstantInfo constInfo = new ConstantInfo(CONSTANT, newVal); constantInfos.put(instr, constInfo); @@ -1749,7 +1748,7 @@ public class ConstantAnalyzer implements Opcodes, CodeAnalyzer { + opc_pop - 1)); } default: - throw new AssertError("Unexpected opcode"); + throw new InternalError("Unexpected opcode"); } if (replacement != null) newCode.add(replacement); diff --git a/jode/jode/obfuscator/modules/LocalOptimizer.java b/jode/jode/obfuscator/modules/LocalOptimizer.java index c7cd5a5..972245a 100644 --- a/jode/jode/obfuscator/modules/LocalOptimizer.java +++ b/jode/jode/obfuscator/modules/LocalOptimizer.java @@ -21,7 +21,6 @@ package jode.obfuscator.modules; import java.util.*; import jode.bytecode.*; import jode.obfuscator.*; -import jode.AssertError; import jode.GlobalOptions; ///#def COLLECTIONS java.util @@ -302,7 +301,7 @@ public class LocalOptimizer implements Opcodes, CodeTransformer { break; default: - throw new AssertError + throw new InternalError ("Illegal opcode for SlotInstruction"); } } @@ -512,14 +511,14 @@ public class LocalOptimizer implements Opcodes, CodeTransformer { * it is possible to do something else * before putting the ret address into a * local. */ - throw new AssertError("Non standard jsr"); + throw new InternalError("Non standard jsr"); } InstrInfo retInfo = info.nextInfo.nextReads [info.instr.getLocalSlot()]; if (retInfo != null) { if (retInfo.instr.getOpcode() != opc_ret) - throw new AssertError + throw new InternalError ("reading return address"); info.retInfo = retInfo; diff --git a/jode/jode/obfuscator/modules/RemovePopAnalyzer.java b/jode/jode/obfuscator/modules/RemovePopAnalyzer.java index 4b2ae71..08a0724 100644 --- a/jode/jode/obfuscator/modules/RemovePopAnalyzer.java +++ b/jode/jode/obfuscator/modules/RemovePopAnalyzer.java @@ -20,7 +20,6 @@ package jode.obfuscator.modules; import jode.bytecode.*; import jode.obfuscator.*; -import jode.AssertError; import jode.GlobalOptions; import java.util.BitSet; @@ -498,7 +497,7 @@ public class RemovePopAnalyzer implements CodeTransformer, Opcodes { case opc_ldc2_w: case opc_lload: case opc_dload: if (!push_all_popped) - throw new AssertError("pop half of a long"); + throw new InternalError("pop half of a long"); poppedEntries[--stackDepth] = false; poppedEntries[--stackDepth] = false; continue; @@ -543,7 +542,7 @@ public class RemovePopAnalyzer implements CodeTransformer, Opcodes { case opc_multianewarray: if (!push_all_popped) - throw new AssertError("pop half of a long"); + throw new InternalError("pop half of a long"); if (poppush[0] < poppush[1]) { for (int j=0; j < poppush[0] - poppush[1]; j++) poppedEntries[stackDepth++] = true; @@ -558,7 +557,7 @@ public class RemovePopAnalyzer implements CodeTransformer, Opcodes { case opc_invokeinterface: case opc_checkcast: if (!push_all_popped) - throw new AssertError("pop half of a long"); + throw new InternalError("pop half of a long"); if (poppush[1] == 1) { poppedEntries[--stackDepth] = false; newInstructions @@ -571,7 +570,7 @@ public class RemovePopAnalyzer implements CodeTransformer, Opcodes { } newInstructions.addFirst(instr); default: - throw new AssertError("Unexpected opcode!"); + throw new InternalError("Unexpected opcode!"); } } else { // Add the instruction .. diff --git a/jode/jode/type/ClassType.java b/jode/jode/type/ClassType.java index 08f5c4b..27565ba 100644 --- a/jode/jode/type/ClassType.java +++ b/jode/jode/type/ClassType.java @@ -247,7 +247,14 @@ public abstract class ClassType extends ReferenceType { * @return the middle type, or null if it is not necessary. */ public Type getCastHelper(Type fromType) { - if (fromType.getHint().isSubTypeOf(this)) + if (isInterface() || fromType == tNull + || (fromType instanceof RangeType + && ((RangeType)fromType).getBottom() == tNull)) + return null; + Type hint = fromType.getHint(); + if (hint.isSubTypeOf(this) + || (hint instanceof ClassType + && ((ClassType) hint).isInterface())) return null; return tObject; } diff --git a/jode/jode/type/IntegerType.java b/jode/jode/type/IntegerType.java index 1087a0b..3240837 100644 --- a/jode/jode/type/IntegerType.java +++ b/jode/jode/type/IntegerType.java @@ -169,7 +169,7 @@ public class IntegerType extends Type { case IT_I: return "i"; default: - throw new jode.AssertError("Local can't be of constant type!"); + throw new InternalError("Local can't be of constant type!"); } } diff --git a/jode/jode/type/MultiClassType.java b/jode/jode/type/MultiClassType.java index 6f029b6..3ae54e7 100644 --- a/jode/jode/type/MultiClassType.java +++ b/jode/jode/type/MultiClassType.java @@ -56,7 +56,7 @@ public class MultiClassType extends ReferenceType { /* We don't implement the set of types, that are castable to some * of the given classes or interfaces. */ - throw new jode.AssertError + throw new InternalError ("getSubType called on set of classes and interfaces!"); } diff --git a/jode/jode/type/NullType.java b/jode/jode/type/NullType.java index 128b881..c2d309d 100644 --- a/jode/jode/type/NullType.java +++ b/jode/jode/type/NullType.java @@ -18,7 +18,6 @@ */ package jode.type; -import jode.AssertError; import java.util.Stack; ///#def COLLECTIONEXTRA java.lang import java.lang.UnsupportedOperationException; diff --git a/jode/jode/type/RangeType.java b/jode/jode/type/RangeType.java index 0a1f27e..57c7c42 100644 --- a/jode/jode/type/RangeType.java +++ b/jode/jode/type/RangeType.java @@ -18,7 +18,6 @@ */ package jode.type; -import jode.AssertError; import jode.GlobalOptions; import java.util.Hashtable; @@ -80,7 +79,7 @@ public class RangeType extends Type { ReferenceType topType) { super(TC_RANGE); if (bottomType == tNull) - throw new jode.AssertError("bottom is NULL"); + throw new InternalError("bottom is NULL"); this.bottomType = bottomType; this.topType = topType; } @@ -177,7 +176,7 @@ public class RangeType extends Type { } public String getDefaultName() { - throw new AssertError("getDefaultName() called on range"); + throw new InternalError("getDefaultName() called on range"); } public int hashCode() { diff --git a/jode/jode/type/Type.java b/jode/jode/type/Type.java index 334b8ef..9993028 100644 --- a/jode/jode/type/Type.java +++ b/jode/jode/type/Type.java @@ -18,7 +18,6 @@ */ package jode.type; -import jode.AssertError; import jode.GlobalOptions; import jode.bytecode.ClassPath; import jode.bytecode.ClassInfo; @@ -244,7 +243,7 @@ public class Type { case '(': return tMethod(cp, type); } - throw new AssertError("Unknown type signature: "+type); + throw new InternalError("Unknown type signature: "+type); } /** @@ -600,7 +599,7 @@ public class Type { case TC_DOUBLE: return Double.TYPE; default: - throw new AssertError("getTypeClass() called on illegal type"); + throw new InternalError("getTypeClass() called on illegal type"); } } diff --git a/jode/jode/util/SimpleSet.java b/jode/jode/util/SimpleSet.java index 8d5ce57..ddd5fbd 100644 --- a/jode/jode/util/SimpleSet.java +++ b/jode/jode/util/SimpleSet.java @@ -64,7 +64,7 @@ public class SimpleSet extends AbstractSet implements Cloneable other.elementObjects = (Object[]) elementObjects.clone(); return other; } catch (CloneNotSupportedException ex) { - throw new jode.AssertError("Clone?"); + throw new InternalError("Clone?"); } }