*** empty log message ***

git-svn-id: https://svn.code.sf.net/p/jode/code/trunk@115 379699f6-c40d-0410-875b-85095c16579e
stable
jochen 26 years ago
parent acaa45ed8d
commit 394e733b1c
  1. 12
      jode/jode/bytecode/Opcodes.java
  2. 2
      jode/jode/decompiler/ClassAnalyzer.java
  3. 155
      jode/jode/decompiler/ImportHandler.java
  4. 8
      jode/jode/expr/ConstOperator.java
  5. 42
      jode/jode/flow/CaseBlock.java
  6. 11
      jode/jode/flow/CreateForInitializer.java
  7. 1
      jode/jode/flow/FlowBlock.java
  8. 63
      jode/jode/flow/LoopBlock.java
  9. 225
      jode/jode/flow/TransformExceptionHandlers.java
  10. 4
      jode/jode/type/ClassInterfacesType.java
  11. 8
      jode/jode/type/Type.java

@ -475,7 +475,7 @@ public abstract class Opcodes {
return createNormal
(ca, addr, 1, new ConstOperator
(FLOAT_TYPE,
Integer.toString(opcode - opc_fconst_0) + ".0F"));
Integer.toString(opcode - opc_fconst_0) + ".0"));
case opc_dconst_0: case opc_dconst_1:
return createNormal
(ca, addr, 1, new ConstOperator
@ -485,11 +485,15 @@ public abstract class Opcodes {
return createNormal
(ca, addr, 2, new ConstOperator
(ALL_INT_TYPE, Integer.toString(stream.readByte())));
case opc_sipush:
case opc_sipush: {
short value = stream.readShort();
return createNormal
(ca, addr, 3, new ConstOperator
(Type.tRange(Type.tInt, Type.tChar),
Integer.toString(stream.readShort())));
((value < Byte.MIN_VALUE || value > Byte.MAX_VALUE)
/* yes javac codes -128 with sipush :-( */
? Type.tRange(Type.tInt, Type.tChar) : ALL_INT_TYPE,
Integer.toString(value)));
}
case opc_ldc: {
int index = stream.readUnsignedByte();
return createNormal

@ -97,7 +97,7 @@ public class ClassAnalyzer implements Analyzer {
}
Class[] interfaces = clazz.getInterfaces();
if (interfaces.length > 0) {
writer.print("implements ");
writer.print(clazz.isInterface() ? "extends " : "implements ");
for (int i=0; i < interfaces.length; i++) {
if (i > 0)
writer.print(", ");

@ -21,7 +21,9 @@ package jode;
import java.util.*;
public class JodeEnvironment {
Hashtable imports = new Hashtable();
Hashtable imports;
/* Classes that doesn't need to be qualified. */
Hashtable goodClasses = new Hashtable();
ClassAnalyzer main;
String className;
String pkg;
@ -31,6 +33,9 @@ public class JodeEnvironment {
JodeEnvironment() {
Type.setEnvironment(this);
classPath = new SearchPath(System.getProperty("java.class.path"));
imports = new Hashtable();
/* java.lang is always imported */
imports.put("java.lang.*", new Integer(Integer.MAX_VALUE));
}
public java.io.InputStream getClassStream(Class clazz)
@ -40,13 +45,61 @@ public class JodeEnvironment {
+".class");
}
public void dumpHeader(TabbedPrintWriter writer)
throws java.io.IOException
{
writer.println("/* "+ className + " - Decompiled by JoDe (Jochen's Decompiler)\n * Send comments or bug reports to Jochen Hoenicke <jochenh@bigfoot.com>\n */");
if (pkg.length() != 0)
writer.println("package "+pkg+";");
/**
* Checks if the className conflicts with a class imported from
* another package and must be fully qualified therefore.
* The imports must should have been cleaned up before.
* <p>
* Known Bug: If a class, local, field or method with the same
* name as the package of className exists, using the fully
* qualified name is no solution. This sometimes can't be fixed
* at all (except by renaming the package). It happens only in
* ambigous contexts, namely static field/method access.
* @param name The full qualified class name.
* @return true if this className must be printed fully qualified.
*/
private boolean conflictsImport(String name) {
int pkgdelim = name.lastIndexOf('.');
if (pkgdelim != -1) {
String pkgName = name.substring(0, pkgdelim);
/* All classes in this package doesn't conflict */
if (pkgName.equals(pkg))
return false;
name = name.substring(pkgdelim+1);
Enumeration enum = imports.keys();
while (enum.hasMoreElements()) {
String importName = (String) enum.nextElement();
if (importName.endsWith(".*")) {
/* strip the "*" */
importName = importName.substring
(0, importName.length()-2);
if (!importName.equals(pkgName)) {
String checkName = importName + "." + name;
try {
Class.forName(checkName);
/* 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 ???
*/
return true;
} catch (ClassNotFoundException ex) {
/* BTW: Exception generation is slow. I'm
* really sad that this is the default.
*/
}
}
}
}
}
return false;
}
private void cleanUpImports() {
Integer dummyVote = new Integer(Integer.MAX_VALUE);
Hashtable newImports = new Hashtable();
Vector classImports = new Vector();
Enumeration enum = imports.keys();
while (enum.hasMoreElements()) {
String importName = (String) enum.nextElement();
@ -60,11 +113,46 @@ 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.
*/
classImports.addElement(importName);
} else {
if (vote.intValue() < Decompiler.importPackageLimit)
continue;
}
writer.println("import "+importName+";");
newImports.put(importName, dummyVote);
}
imports = newImports;
/* Now check if the class import conflict with any of the
* package imports.
*/
enum = classImports.elements();
while (enum.hasMoreElements()) {
/* If there are more than one single class imports with
* the same name, exactly the first (in hash order) will
* be imported. */
String className = (String) enum.nextElement();
if (!conflictsImport(className))
imports.put(className, dummyVote);
}
}
private void dumpHeader(TabbedPrintWriter writer)
throws java.io.IOException
{
writer.println("/* "+ className + " - Decompiled by JoDe (Jochen's Decompiler)\n * Send comments or bug reports to Jochen Hoenicke <jochenh@bigfoot.com>\n */");
if (pkg.length() != 0)
writer.println("package "+pkg+";");
cleanUpImports();
Enumeration enum = imports.keys();
while (enum.hasMoreElements()) {
String pkgName = (String)enum.nextElement();
if (!pkgName.equals("java.lang.*"))
writer.println("import "+pkgName+";");
}
writer.println("");
}
@ -109,8 +197,7 @@ public class JodeEnvironment {
/* Marks the clazz as used, so that it will be imported if used often
* enough.
*/
public void useClass(Class clazz) {
String name = clazz.getName();
public void useClass(String name) {
int pkgdelim = name.lastIndexOf('.');
if (pkgdelim != -1) {
String pkgName = name.substring(0, pkgdelim);
@ -118,9 +205,13 @@ public class JodeEnvironment {
|| pkgName.equals("java.lang"))
return;
Integer i = (Integer) imports.get(name);
if (i== null) {
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)
@ -128,39 +219,61 @@ public class JodeEnvironment {
i = new Integer(1);
} else
} else {
if (i.intValue() >= Decompiler.importClassLimit)
return;
i = new Integer(i.intValue()+1);
}
imports.put(name, i);
}
}
/* Marks the clazz as used, so that it will be imported if used often
* enough.
*/
public void useClass(Class clazz) {
useClass(clazz.getName());
}
/**
* Check if clazz is imported and maybe remove package delimiter from
* full qualified class name.
* <p>
* Known Bug: If the same class name is in more than one imported package
* the name should be qualified, but isn't.
* Known Bug 1: If this is called before the imports are cleaned up,
* (that is only for debugging messages), the result is unpredictable.
* <p>
* Known Bug 2: It is not checked if the class name conflicts with
* a local variable, field or method name. This is very unlikely
* since the java standard has different naming convention for those
* names. (But maybe a intelligent obfuscator may use this fact.)
* This can only happen with static fields or static methods.
* @return a legal string representation of clazz.
*/
public String classString(Class clazz) {
String name = clazz.getName();
public String classString(String name) {
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)
|| pkgName.equals("java.lang")
|| ( (i = (Integer)imports.get(pkgName+".*")) != null
&& i.intValue() >= Decompiler.importPackageLimit )
|| ( (i = (Integer)imports.get(name)) != null
&& i.intValue() >= Decompiler.importClassLimit )) {
|| (( imports.get(pkgName+".*") != null
|| imports.get(name) != null)
&& !conflictsImport(name))) {
goodClasses.put(name, name);
return name.substring(pkgdelim+1);
}
}
return name;
}
public String classString(Class clazz) {
return classString(clazz.getName());
}
protected int loadFileFlags()
{
return 1;

@ -92,12 +92,16 @@ public class ConstOperator extends NoArgOperator {
} else if (type.equals(Type.tLong)) {
long l = Long.parseLong(value);
if (l < -1)
return "~0x"+Long.toHexString(-l-1);
return "~0x"+Long.toHexString(-l-1)+"L";
else
return "0x"+Long.toHexString(l);
return "0x"+Long.toHexString(l)+"L";
}
}
}
if (type.isOfType(Type.tLong))
return value+"L";
if (type.isOfType(Type.tFloat))
return value+"F";
return value;
}
}

@ -47,6 +47,16 @@ public class CaseBlock extends StructuredBlock {
*/
boolean isLastBlock;
/**
* All variables used somewhere inside this block.
*/
VariableSet allUsed;
/**
* Do we want braces around the case block (if a sub block
* declares a variable).
*/
boolean wantBraces;
public CaseBlock(int value) {
this.value = value;
subBlock = null;
@ -79,6 +89,31 @@ public class CaseBlock extends StructuredBlock {
return true;
}
public VariableSet propagateUsage() {
/* We remember if this sub block uses some variables, to introduce
* braces around this block in that case.
*/
return (allUsed = super.propagateUsage());
}
/**
* Make the declarations, i.e. initialize the declare variable
* to correct values. This will declare every variable that
* is marked as used, but not done.
* @param done The set of the already declare variables.
*/
public void makeDeclaration(VariableSet done) {
java.util.Enumeration enum = allUsed.elements();
while (enum.hasMoreElements()) {
jode.LocalInfo li = (jode.LocalInfo) enum.nextElement();
if (!done.contains(li)) {
wantBraces = true;
break;
}
}
super.makeDeclaration(done);
}
/**
* Returns all sub block of this structured block.
*/
@ -96,18 +131,21 @@ public class CaseBlock extends StructuredBlock {
&& subBlock instanceof EmptyBlock
&& subBlock.jump == null)
return;
writer.println("default:");
writer.println("default:" + (wantBraces ? " {" : ""));
} else {
ConstOperator constOp = new ConstOperator
(((SwitchBlock)outer).getInstruction().getType(),
Integer.toString(value));
writer.println("case " + constOp.toString()+":");
writer.println("case " + constOp.toString() + ":"
+ (wantBraces ? " {" : ""));
}
if (subBlock != null) {
writer.tab();
subBlock.dumpSource(writer);
writer.untab();
}
if (wantBraces)
writer.println("}");
}
/**

@ -38,19 +38,16 @@ public class CreateForInitializer {
if (!(sequBlock.subBlocks[0] instanceof InstructionBlock))
return false;
Expression initializer =
((InstructionBlock) sequBlock.subBlocks[0]).getInstruction();
InstructionBlock init = (InstructionBlock) sequBlock.subBlocks[0];
if (!initializer.getOperator().isVoid()
|| (forBlock.cond != forBlock.TRUE
&& !forBlock.cond.containsMatchingLoad(initializer)))
if (!init.getInstruction().isVoid()
|| !forBlock.conditionMatches(init))
return false;
if (jode.Decompiler.isVerbose)
System.err.print('f');
forBlock.init = (InstructionBlock) sequBlock.subBlocks[0];
last.replace(sequBlock);
forBlock.setInit((InstructionBlock) sequBlock.subBlocks[0]);
return true;
}
}

@ -799,7 +799,6 @@ public class FlowBlock {
forBlock.replace(bodyBlock);
forBlock.setBody(bodyBlock);
forBlock.incr = (InstructionBlock) lastModified;
lastModified.removeBlock();
createdForBlock = true;
}

@ -95,45 +95,42 @@ public class LoopBlock extends StructuredBlock implements BreakableBlock {
body.setFlowBlock(flowBlock);
}
public Expression getCondition() {
return cond;
public void setInit(InstructionBlock init) {
this.init = init;
if (type == FOR)
init.removeBlock();
}
public void putBackInit() {
StructuredBlock last =
(outer instanceof SequentialBlock
&& outer.getSubBlocks()[0] == this) ? outer : this;
public boolean conditionMatches(InstructionBlock instr) {
return (type == POSSFOR ||
cond.containsMatchingLoad(instr.getInstruction()));
}
SequentialBlock sequBlock = new SequentialBlock();
sequBlock.replace(last);
sequBlock.setFirst(init);
sequBlock.setSecond(last);
init = null;
public Expression getCondition() {
return cond;
}
public void setCondition(Expression cond) {
this.cond = cond;
if (type == POSSFOR) {
/* canCombine returns 1 if cond contains a sub expression
* that matches the store in incr */
/* We can now say, if this is a for block or not.
*/
if (cond.containsMatchingLoad(incr.getInstruction())) {
type = FOR;
if (init != null
&& !cond.containsMatchingLoad(init.getInstruction())) {
/* This is a for, but the init instruction doesn't
* match. Put the init back to its old place.
*/
putBackInit();
incr.removeBlock();
if (init != null) {
if (cond.containsMatchingLoad(init.getInstruction()))
init.removeBlock();
else
init = null;
}
} else {
/* This is not a for block, as it seems first. Make
* it a while block again, and forget about init and
* incr. */
type = WHILE;
StructuredBlock last = bodyBlock;
while (last instanceof SequentialBlock)
last = last.getSubBlocks()[1];
last.appendBlock(incr);
incr = null;
if (init != null)
putBackInit();
init = incr = null;
}
}
mayChangeJump = false;
@ -148,9 +145,9 @@ public class LoopBlock extends StructuredBlock implements BreakableBlock {
}
public VariableSet propagateUsage() {
if (init != null)
if (type == FOR && init != null)
used.unionExact(init.used);
if (incr != null)
if (type == FOR && incr != null)
used.unionExact(incr.used);
VariableSet allUse = (VariableSet) used.clone();
allUse.unionExact(bodyBlock.propagateUsage());
@ -211,6 +208,8 @@ public class LoopBlock extends StructuredBlock implements BreakableBlock {
}
boolean needBrace = bodyBlock.needsBraces();
switch (type) {
case POSSFOR:
/* a possible for is now treated like a WHILE */
case WHILE:
if (cond == TRUE)
/* special syntax for endless loops: */
@ -222,7 +221,6 @@ public class LoopBlock extends StructuredBlock implements BreakableBlock {
writer.print("do");
break;
case FOR:
case POSSFOR:
writer.print("for (");
if (init != null) {
if (isDeclaration)
@ -231,7 +229,8 @@ public class LoopBlock extends StructuredBlock implements BreakableBlock {
.getLocalInfo().getType().toString()
+ " ");
writer.print(init.getInstruction().simplify().toString());
}
} else
writer.print("/**/");
writer.print("; "+cond.simplify().toString()+"; "
+incr.getInstruction().simplify().toString()+")");
break;
@ -278,7 +277,9 @@ public class LoopBlock extends StructuredBlock implements BreakableBlock {
}
/**
* Replace all breaks to this block with a continue to this block.
* Replace all breaks to block with a continue to this.
* @param block the breakable block where the breaks originally
* breaked to (Have a break now, if you didn't understand that :-).
*/
public void replaceBreakContinue(BreakableBlock block) {
java.util.Stack todo = new java.util.Stack();

@ -209,23 +209,28 @@ public class TransformExceptionHandlers {
* This transforms a sub routine, that is checks if the beginning
* local assignment matches the final ret and then returns.
*/
boolean transformSubRoutine(FlowBlock subRoutine) {
try {
SequentialBlock sequBlock = (SequentialBlock) subRoutine.block;
LocalStoreOperator store = (LocalStoreOperator)
((InstructionBlock)sequBlock.subBlocks[0]).instr.getOperator();
while (sequBlock.subBlocks[1] instanceof SequentialBlock)
sequBlock = (SequentialBlock) sequBlock.subBlocks[1];
RetBlock retBlock = (RetBlock)sequBlock.subBlocks[1];
if (! retBlock.local.equals(store.getLocalInfo()))
/* Ret doesn't match */
return false;
subRoutine.block.getSubBlocks()[0].removeBlock();
retBlock.removeBlock();
return true;
} catch (ClassCastException ex) {
boolean transformSubRoutine(StructuredBlock subRoutine) {
if (!(subRoutine instanceof SequentialBlock)
|| !(subRoutine.getSubBlocks()[0] instanceof InstructionBlock))
return false;
}
SequentialBlock sequBlock = (SequentialBlock) subRoutine;
InstructionBlock instr = (InstructionBlock)sequBlock.subBlocks[0];
if (! (instr.getInstruction() instanceof LocalStoreOperator))
return false;
LocalStoreOperator store = (LocalStoreOperator) instr.getInstruction();
while (sequBlock.subBlocks[1] instanceof SequentialBlock)
sequBlock = (SequentialBlock) sequBlock.subBlocks[1];
if (! (sequBlock.subBlocks[1] instanceof RetBlock)
|| !(((RetBlock)sequBlock.subBlocks[1])
.local.equals(store.getLocalInfo())))
return false;
instr.removeBlock();
sequBlock.subBlocks[1].removeBlock();
return true;
}
/**
@ -351,7 +356,10 @@ public class TransformExceptionHandlers {
/* Now we have a jump with a wrong destination.
* Complain!
*/
System.err.println("non well formed try-finally block");
DescriptionBlock msg
= new DescriptionBlock("ERROR: NO JSR TO FINALLY");
prev.appendBlock(msg);
msg.moveJump(jumps);
}
}
removeJSR(tryFlow, subRoutine);
@ -386,7 +394,7 @@ public class TransformExceptionHandlers {
subRoutine = jumps.destination;
subRoutine.analyze(startMonExit, endMonExit);
transformSubRoutine(subRoutine);
transformSubRoutine(subRoutine.block);
if (subRoutine.block instanceof InstructionBlock) {
Expression instr =
@ -466,7 +474,10 @@ public class TransformExceptionHandlers {
/* Now we have a jump that is not preceded by a monitorexit.
* Complain!
*/
System.err.println("non well formed synchronized block");
DescriptionBlock msg
= new DescriptionBlock("ERROR: NO MONITOREXIT");
prev.appendBlock(msg);
msg.moveJump(jumps);
}
}
@ -548,72 +559,144 @@ public class TransformExceptionHandlers {
private boolean analyzeFinally(FlowBlock tryFlow, FlowBlock catchFlow,
int end) {
if (!(catchFlow.block instanceof SequentialBlock
&& catchFlow.block.getSubBlocks()[0]
instanceof InstructionBlock))
/* Layout of a try-finally block:
*
* tryFlow:
* |- first instruction
* | ...
* | every jump to outside is preceded by jsr finally
* | ...
* | jsr finally -----------------,
* `- jump after finally |
* |
* catchFlow: (already checked) |
* local_n = stack v
* jsr finally ---------------->|
* throw local_n; |
* finally: <-----------------------'
* astore_n
* ...
* return_n
*/
if (!(catchFlow.block instanceof SequentialBlock)
|| !(catchFlow.block.getSubBlocks()[0]
instanceof InstructionBlock)
|| !(catchFlow.block.getSubBlocks()[1]
instanceof SequentialBlock))
return false;
StructuredBlock finallyBlock = null;
SequentialBlock catchBlock = (SequentialBlock) catchFlow.block;
Expression instr =
((InstructionBlock)catchBlock.subBlocks[0]).getInstruction();
catchBlock = (SequentialBlock)catchBlock.subBlocks[1];
if (catchBlock.subBlocks[1] instanceof SequentialBlock
&& catchBlock.subBlocks[1].getSubBlocks()[0]
instanceof JsrBlock
if (catchBlock.subBlocks[0] instanceof LoopBlock) {
/* In case the try block has no exit (that means, it throws
* an exception), the finallyBlock was already merged with
* the catchBlock. We have to check for this case separately:
*
* do {
* JSR
* break;
* throw local_x
* } while(false);
* finallyBlock;
*/
LoopBlock doWhileFalse = (LoopBlock)catchBlock.subBlocks[0];
if (doWhileFalse.type == LoopBlock.DOWHILE
&& doWhileFalse.cond == LoopBlock.FALSE
&& doWhileFalse.bodyBlock instanceof SequentialBlock) {
finallyBlock = catchBlock.subBlocks[1];
catchBlock = (SequentialBlock) doWhileFalse.bodyBlock;
}
}
if (catchBlock instanceof SequentialBlock
&& catchBlock.getSubBlocks()[0] instanceof JsrBlock
&& instr instanceof LocalStoreOperator
&& catchBlock.subBlocks[1].getSubBlocks()[1]
instanceof ThrowBlock
&& ((ThrowBlock)catchBlock.subBlocks[1]
.getSubBlocks()[1]).instr
instanceof LocalLoadOperator
&& ((LocalStoreOperator) instr)
.matches((LocalLoadOperator)
((ThrowBlock)catchBlock.subBlocks[1]
.getSubBlocks()[1]).instr)) {
&& catchBlock.getSubBlocks()[1] instanceof ThrowBlock
&& (((ThrowBlock)catchBlock.getSubBlocks()[1]).instr
instanceof LocalLoadOperator)
&& (((LocalStoreOperator) instr).matches
((LocalLoadOperator)
((ThrowBlock)catchBlock.getSubBlocks()[1]).instr))) {
/* Wow that was complicated :-)
* But now we know that the catch block looks
* exactly like an try finally block:
* exactly like it should:
*
* tryFlow:
* |- first instruction
* | ...
* | every jump to outside is preceded by jsr finally
* | ...
* | jsr finally -----------------,
* `- jump after finally |
* |
* catchFlow: (already checked) |
* local_n = stack v
* jsr finally ---------------->|
* throw local_n; |
* finally: <-----------------------'
* astore_n
* ...
* return_n
* catchBlock:
* JSR
* finally
* throw local_n <- matches the local in instr.
*/
FlowBlock subRoutine =
((JsrBlock)catchBlock.subBlocks[1].getSubBlocks()[0])
.innerBlock.jump.destination;
if (finallyBlock != null) {
/* Check if the jsr breaks (see two comments above). We don't
* need to check if it breaks to the right block, because
* we know that there is only one Block around the jsr.
*/
if (!(((JsrBlock)catchBlock.getSubBlocks()[0]).innerBlock
instanceof BreakBlock))
return false;
/* Check if the try block has no exit (except throws)
*/
Jump throwJumps = (Jump)
tryFlow.successors.get(FlowBlock.END_OF_METHOD);
if (tryFlow.successors.size() > 1
|| (tryFlow.successors.size() > 0 && throwJumps == null))
return false;
/* Now remove the two jumps of the catch block
* so that we can forget about them.
* This are the jsr and the throw.
*/
catchBlock.subBlocks[1].getSubBlocks()[0].getSubBlocks()[0]
.jump.destination.predecessors.removeElement(catchFlow);
catchBlock.subBlocks[1].getSubBlocks()[1]
.jump.destination.predecessors.removeElement(catchFlow);
for (/**/; throwJumps != null; throwJumps = throwJumps.next) {
if (!(throwJumps.prev instanceof ThrowBlock))
/* There is a return exit in the try block */
return false;
}
/* Remove the jump of the throw instruction.
*/
catchBlock.getSubBlocks()[1]
.jump.destination.predecessors.removeElement(catchFlow);
subRoutine.analyze(catchFlow.addr+catchFlow.length, end);
if (!transformSubRoutine(subRoutine))
return false;
/* Replace the catchBlock with the finallyBlock.
*/
finallyBlock.replace(catchFlow.block);
transformSubRoutine(finallyBlock);
updateInOutCatch(tryFlow, subRoutine);
updateInOutCatch(tryFlow, catchFlow);
tryFlow.length += catchFlow.length;
finallyBlock = catchFlow.block;
tryFlow.mergeSuccessors(catchFlow);
tryFlow.length += catchFlow.length;
checkAndRemoveJSR(tryFlow, subRoutine);
} else {
FlowBlock subRoutine =
((JsrBlock)catchBlock.getSubBlocks()[0])
.innerBlock.jump.destination;
subRoutine.analyze(catchFlow.addr+catchFlow.length, end);
if (!transformSubRoutine(subRoutine.block))
return false;
tryFlow.length += catchFlow.length;
checkAndRemoveJSR(tryFlow, subRoutine);
updateInOutCatch(tryFlow, subRoutine);
tryFlow.length += subRoutine.length;
tryFlow.mergeSuccessors(subRoutine);
finallyBlock = subRoutine.block;
/* Now remove the jump to the JSR from the catch block
* and the jump of the throw instruction.
*/
catchBlock.getSubBlocks()[0].getSubBlocks()[0]
.jump.destination.predecessors.removeElement(catchFlow);
catchBlock.getSubBlocks()[1]
.jump.destination.predecessors.removeElement(catchFlow);
}
TryBlock tryBlock = (TryBlock)tryFlow.block;
if (tryBlock.getSubBlocks()[0] instanceof TryBlock) {
@ -625,10 +708,8 @@ public class TransformExceptionHandlers {
tryFlow.lastModified = innerTry;
}
FinallyBlock newBlock = new FinallyBlock();
newBlock.setCatchBlock(subRoutine.block);
newBlock.setCatchBlock(finallyBlock);
tryBlock.addCatchBlock(newBlock);
tryFlow.mergeSuccessors(subRoutine);
tryFlow.length += subRoutine.length;
return true;
}
return false;
@ -660,7 +741,7 @@ public class TransformExceptionHandlers {
Object key = keys.nextElement();
if (key == succ)
continue;
if (key != tryFlow.END_OF_METHOD) {
if (key != FlowBlock.END_OF_METHOD) {
/* There is another exit in the try block, bad */
return false;
}

@ -209,7 +209,7 @@ public class ClassInterfacesType extends Type {
int code = type.typecode;
if (code == TC_UNKNOWN)
return this;
if (code == TC_ARRAY && this == tObject)
if ((code == TC_ARRAY || code == TC_UCLASS) && this == tObject)
return type;
if (code != TC_CLASS)
return tError;
@ -297,7 +297,7 @@ public class ClassInterfacesType extends Type {
int code = type.typecode;
if (code == TC_UNKNOWN)
return this;
if (code == TC_ARRAY)
if (code == TC_ARRAY || code == TC_UCLASS)
return tObject;
if (code != TC_CLASS)
return tError;

@ -85,6 +85,7 @@ public class Type {
public static final int TC_RANGE = 103;
public static final int TC_BOOLBYTE = 105;
public static final int TC_BOOLINT = 106;
public static final int TC_UCLASS = 107;
protected static JodeEnvironment env;
@ -165,7 +166,12 @@ public class Type {
clazzname = clazzname.replace(java.io.File.separatorChar, '.');
Object result = classHash.get(clazzname);
if (result == null) {
result = new ClassInterfacesType(clazzname);
try {
Class clazz = Class.forName(clazzname);
result = new ClassInterfacesType(clazzname);
} catch (ClassNotFoundException ex) {
result = new UnfoundClassType(clazzname);
}
classHash.put(clazzname, result);
}
return (Type) result;

Loading…
Cancel
Save