Applied more patches from Jode-1.1 branch.

git-svn-id: https://svn.code.sf.net/p/jode/code/trunk@1328 379699f6-c40d-0410-875b-85095c16579e
master
hoenicke 24 years ago
parent c30ac484c5
commit 676e21257f
  1. 67
      jode/ChangeLog
  2. 2
      jode/acinclude.m4
  3. 2
      jode/configure.in
  4. 4
      jode/jode/GlobalOptions.java
  5. 15
      jode/jode/bytecode/BasicBlockReader.java
  6. 2
      jode/jode/decompiler/Main.java
  7. 72
      jode/jode/expr/IfThenElseOperator.java
  8. 12
      jode/jode/flow/CatchBlock.java
  9. 11
      jode/jode/flow/EmptyBlock.java
  10. 12
      jode/jode/flow/StructuredBlock.java
  11. 30
      jode/jode/flow/TransformConstructors.java
  12. 367
      jode/jode/flow/TransformExceptionHandlers.java
  13. 36
      jode/jode/jvm/CodeVerifier.java
  14. 19
      jode/jode/swingui/Main.java
  15. 16
      jode/jode/type/ArrayType.java
  16. 2
      jode/jode/type/ClassType.java
  17. 5
      jode/jode/util/UnifyHash.java

@ -1,12 +1,67 @@
2001-07-15 Jochen Hoenicke <jochen@gnu.org>
Applied patches from 2001-02-27 of Jode 1.1 tree:
* acinclude.m4 (JODE_CHECK_CLASS): Changed "test -e" to "-f" since
-e is not supported on all architectures (Solaris) and -f is more
correct anyway.
Reported by Erik Modén.
* jode/swingui/Main.java.in (AreaWriter): Convert all kinds of
line breaks (CR+LF, CR, LF) to a LF character, which a JTextArea
understands.
2001-07-15 Jochen Hoenicke <jochen@gnu.org>
Applied patch from 2001-02-04 of Jode 1.1 tree:
* jode/expr/IfThenElseOperator.java (simplify): Allow in the class$
simplification the then and else part to be swapped.
* jode/type/ClassType.java (keywords): Added the package
and import keywords.
* jode/flow/TransformExceptionHandlers.java:
(getPredecessor): New function.
(getMonitorExitSlot): New function.
(skipFinExitChain): New function.
(removeJSR): Replaced by ...
(removeBadJSR): ... this.
(checkAndRemoveJSR): Use the new functions. Much simpler and
handles nested synchronized blocks. It now traces the whole JSR
and monitorexit chain before a jump to the first entry via
skipFinExitChain, then checks and remove the first JSR
resp. monitorexit. JSR jumps are simply ignored now.
(checkAndRemoveMonitorExit): likewise.
* jode/flow/StructuredBlock.java (prependBlock): New function.
* jode/flow/CatchBlock.java (makeDeclaration): Generate name
of dummyLocal, since nobody else will generate it.
* jode/bytecode/BasicBlockReader.java (readCode): Remove bogus
exceptionHandlers, whose catchers just throw the exception again.
This kind of entries are inserted by an obfuscator and would break
JODE.
* jode/util/UnifyHash.java (iterateHashCode): Call cleanUp,
to clean unneeded references.
* jode/flow/TransformConstructors.java (transformOneField):
Changed to private. Take field number as parameter. Check that
expression doesn't contain a FieldOperator for a later field of
the same class or a PutFieldOperator. Changed all callers.
2001-07-15 Jochen Hoenicke <jochen@gnu.org>
Applied patch from 2001-02-01 of Jode 1.1 tree:
* jode/jvm/CodeVerifier.java (Type.mergeType): If array elem
types can't be merged, return tObject as common super type.
* jode/type/ArrayType.java (getGeneralizedType): If array elem
type can't be intersected, return tObject as common super type.
2001-07-15 Jochen Hoenicke <jochen@gnu.org> 2001-07-15 Jochen Hoenicke <jochen@gnu.org>
Applied patch from Java 1.1 tree: Applied patch from Java 1.1 tree:
* jode/expr/Expression.java.in (updateParentTypes): Call setType, * jode/expr/Expression.java (updateParentTypes): Call setType,
instead of merging the types. Other childs want to know about the instead of merging the types. Other childs want to know about the
type change as well. type change as well.
* jode/decompiler/LocalInfo.java (combineWith): Reorganized a bit, * jode/decompiler/LocalInfo.java (combineWith): Reorganized a bit,
but no changes. but no changes.
* jode/expr/InvokeOperator.java.in (dumpExpression): Always print * jode/expr/InvokeOperator.java (dumpExpression): Always print
the ThisOperator if a field is from a parent class of an outer the ThisOperator if a field is from a parent class of an outer
class is used. And always qualify the this operator if not class is used. And always qualify the this operator if not
innermost. innermost.
@ -22,11 +77,11 @@
(printOptionalSpace): Print space for GNU_SPACING. (printOptionalSpace): Print space for GNU_SPACING.
* jode/decompiler/Options.java (setOptions): changed gnu style * jode/decompiler/Options.java (setOptions): changed gnu style
to include GNU_SPACING. to include GNU_SPACING.
* jode/decompiler/ClassAnalyzer.java.in (dumpSource): Use * jode/decompiler/ClassAnalyzer.java (dumpSource): Use
open/closeBraceClass. open/closeBraceClass.
* jode/decompiler/MethodAnalyzer.java.in (dumpSource): Use * jode/decompiler/MethodAnalyzer.java (dumpSource): Use
open/closeBraceNoIndent. Call printOptionalSpace. open/closeBraceNoIndent. Call printOptionalSpace.
* jode/decompiler/InvokeOperator.java.in (dumpExpression): * jode/decompiler/InvokeOperator.java (dumpExpression):
Call printOptionalSpace, use open/closeBraceClass for inner Call printOptionalSpace, use open/closeBraceClass for inner
classes. classes.
* jode/decompiler/UnaryOperator.java (dumpExpression): Call * jode/decompiler/UnaryOperator.java (dumpExpression): Call
@ -43,7 +98,7 @@
version in ReferenceType is more correct. Before version in ReferenceType is more correct. Before
tNull.isOfType(tRange(X,tNull)) returned false, which lead to tNull.isOfType(tRange(X,tNull)) returned false, which lead to
incorrect behaviour in InvokeOperator.needsCast. incorrect behaviour in InvokeOperator.needsCast.
* jode/decompiler/FieldAnalyzer.java.in (dumpSource): Removed the * jode/decompiler/FieldAnalyzer.java (dumpSource): Removed the
"= null" hack for final fields; it was not correct, since the "= null" hack for final fields; it was not correct, since the
field could be initialized in a constructor. field could be initialized in a constructor.
* jode/decompiler/TabbedPrintWriter.java (BreakPoint.endOp): * jode/decompiler/TabbedPrintWriter.java (BreakPoint.endOp):

@ -28,7 +28,7 @@ AC_DEFUN(JODE_CHECK_CLASS,
myclasspath=$2; myclasspath=$2;
for path in $myclasspath; do for path in $myclasspath; do
if test -d $path; then if test -d $path; then
if test -e $path/$clazz; then if test -f $path/$clazz; then
exit 0 exit 0
fi fi
elif CLASS_CHECK $path $clazz ; then elif CLASS_CHECK $path $clazz ; then

@ -1,7 +1,7 @@
dnl Process this file with autoconf to produce a configure script. dnl Process this file with autoconf to produce a configure script.
AC_INIT() AC_INIT()
AM_INIT_AUTOMAKE(jode, 1.0.93) AM_INIT_AUTOMAKE(jode, 1.0.94)
dnl Checks for programs. dnl Checks for programs.
dnl AC_PROG_CXX dnl AC_PROG_CXX

@ -1,4 +1,4 @@
/* GlobalOptions Copyright (C) 1999-2000 Jochen Hoenicke. /* GlobalOptions Copyright (C) 1999-2001 Jochen Hoenicke.
* *
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by
@ -25,7 +25,7 @@ public class GlobalOptions {
public final static String version = "@VERSION@"; public final static String version = "@VERSION@";
public final static String email = "jochen@gnu.org"; public final static String email = "jochen@gnu.org";
public final static String copyright = public final static String copyright =
"Jode (c) 1998-2000 Jochen Hoenicke <"+email+">"; "Jode (c) 1998-2001 Jochen Hoenicke <"+email+">";
public final static String URL = "http://jode.sourceforge.net/"; public final static String URL = "http://jode.sourceforge.net/";
public static PrintWriter err = new PrintWriter(System.err, true); public static PrintWriter err = new PrintWriter(System.err, true);

@ -828,6 +828,21 @@ class BasicBlockReader implements Opcodes {
int index = input.readUnsignedShort(); int index = input.readUnsignedShort();
handlers[i].type = (index == 0) ? null handlers[i].type = (index == 0) ? null
: cp.getClassName(index); : cp.getClassName(index);
if (infos[handlers[i].catcher].instr.getOpcode() == opc_athrow) {
/* There is an obfuscator, which inserts bogus
* exception entries jumping directly to a throw
* instruction. Remove those handlers.
*/
handlersLength--;
i--;
}
}
if (handlersLength < handlers.length) {
HandlerEntry[] newHandlers = new HandlerEntry[handlersLength];
System.arraycopy(handlers, 0, newHandlers, 0,
handlersLength);
handlers = newHandlers;
} }
for (int i=0; i< infos.length; i++) { for (int i=0; i< infos.length; i++) {

@ -1,4 +1,4 @@
/* Main Copyright (C) 1998-1999 Jochen Hoenicke. /* Main Copyright (C) 1998-2001 Jochen Hoenicke.
* *
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by

@ -59,39 +59,49 @@ public class IfThenElseOperator extends Operator {
return subExpressions[0].negate().simplify(); return subExpressions[0].negate().simplify();
} }
} }
if (subExpressions[0] instanceof CompareUnaryOperator if (subExpressions[0] instanceof CompareUnaryOperator
&& (subExpressions[1] instanceof GetFieldOperator) && ((((CompareUnaryOperator) subExpressions[0])
&& (subExpressions[2] instanceof StoreInstruction)) { .getOperatorIndex() & ~1) == Operator.COMPARE_OP)) {
// Check for
// class$classname != null ? class$classname :
// (class$classname = class$("classname"))
// and replace with
// classname.class
CompareUnaryOperator cmp CompareUnaryOperator cmp
= (CompareUnaryOperator) subExpressions[0]; = (CompareUnaryOperator) subExpressions[0];
GetFieldOperator get = (GetFieldOperator) subExpressions[1]; int cmpType = cmp.getOperatorIndex() & 1;
StoreInstruction put = (StoreInstruction) subExpressions[2]; if ((subExpressions[2 - cmpType] instanceof GetFieldOperator)
FieldAnalyzer field; && (subExpressions[1 + cmpType] instanceof StoreInstruction)) {
if (cmp.getOperatorIndex() == Operator.NOTEQUALS_OP // Check for
&& put.getLValue() instanceof PutFieldOperator // class$classname != null ? class$classname :
&& ((field = ((PutFieldOperator)put.getLValue()).getField()) // (class$classname = class$("classname"))
!= null) && field.isSynthetic() // and replace with
&& put.lvalueMatches(get) // classname.class
&& cmp.subExpressions[0] instanceof GetFieldOperator GetFieldOperator get
&& put.lvalueMatches((GetFieldOperator)cmp.subExpressions[0]) = (GetFieldOperator) subExpressions[2 - cmpType];
&& put.subExpressions[1] instanceof InvokeOperator) { StoreInstruction put
InvokeOperator invoke = (InvokeOperator) put.subExpressions[1]; = (StoreInstruction) subExpressions[1 + cmpType];
if (invoke.isGetClass() int opIndex = cmp.getOperatorIndex();
&& invoke.subExpressions[0] instanceof ConstOperator FieldAnalyzer field;
&& (invoke.subExpressions[0].getType() if (put.getLValue() instanceof PutFieldOperator
.equals(Type.tString))) { && ((field = ((PutFieldOperator)put.getLValue())
String clazz = (String) .getField()) != null) && field.isSynthetic()
((ConstOperator)invoke.subExpressions[0]).getValue(); && put.lvalueMatches(get)
ClassPath cp = field.getClassAnalyzer().getClassPath(); && (cmp.subExpressions[0] instanceof GetFieldOperator)
if (field.setClassConstant(clazz)) && put.lvalueMatches((GetFieldOperator)
return new ClassFieldOperator cmp.subExpressions[0])
(clazz.charAt(0) == '[' && put.subExpressions[1] instanceof InvokeOperator) {
? Type.tType(cp, clazz) : Type.tClass(cp, clazz)); InvokeOperator invoke = (InvokeOperator)
put.subExpressions[1];
if (invoke.isGetClass()
&& invoke.subExpressions[0] instanceof ConstOperator
&& (invoke.subExpressions[0].getType()
.equals(Type.tString))) {
String clazz = (String)
((ConstOperator)invoke.subExpressions[0])
.getValue();
ClassPath cp = field.getClassAnalyzer().getClassPath();
if (field.setClassConstant(clazz))
return new ClassFieldOperator
(clazz.charAt(0) == '['
? Type.tType(cp, clazz)
: Type.tClass(cp, clazz));
}
} }
} }
} }

@ -20,6 +20,7 @@
package jode.flow; package jode.flow;
import jode.type.Type; import jode.type.Type;
import jode.decompiler.LocalInfo; import jode.decompiler.LocalInfo;
import jode.decompiler.Declarable;
import jode.expr.Expression; import jode.expr.Expression;
import jode.expr.LocalLoadOperator; import jode.expr.LocalLoadOperator;
import jode.expr.LocalStoreOperator; import jode.expr.LocalStoreOperator;
@ -28,6 +29,7 @@ import jode.util.SimpleSet;
///#def COLLECTIONS java.util ///#def COLLECTIONS java.util
import java.util.Collections; import java.util.Collections;
import java.util.Iterator;
import java.util.Set; import java.util.Set;
///#enddef ///#enddef
@ -162,6 +164,16 @@ public class CatchBlock extends StructuredBlock {
ib.appendBlock(catchBlock); ib.appendBlock(catchBlock);
catchBlock = ib; catchBlock = ib;
exceptionLocal = dummyLocal; exceptionLocal = dummyLocal;
String localName = dummyLocal.guessName();
Iterator doneIter = done.iterator();
while (doneIter.hasNext()) {
Declarable previous = (Declarable) doneIter.next();
if (localName.equals(previous.getName())) {
/* A name conflict happened. */
dummyLocal.makeNameUnique();
break;
}
}
} }
} }
} }

@ -56,6 +56,17 @@ public class EmptyBlock extends StructuredBlock {
return block; return block;
} }
/**
* Prepends a block to this block.
* @return the new combined block.
*/
public StructuredBlock prependBlock(StructuredBlock block) {
/* For empty blocks: append == prepend modulo jump */
block = appendBlock(block);
block.moveJump(this.jump);
return block;
}
public void dumpInstruction(TabbedPrintWriter writer) public void dumpInstruction(TabbedPrintWriter writer)
throws java.io.IOException throws java.io.IOException
{ {

@ -316,6 +316,18 @@ public abstract class StructuredBlock {
} }
} }
/**
* Prepends a block to this block.
* @return the new combined block.
*/
public StructuredBlock prependBlock(StructuredBlock block) {
SequentialBlock sequBlock = new SequentialBlock();
sequBlock.replace(this);
sequBlock.setFirst(block);
sequBlock.setSecond(this);
return sequBlock;
}
/** /**
* Removes this block, or replaces it with an EmptyBlock. * Removes this block, or replaces it with an EmptyBlock.
*/ */

@ -1,4 +1,4 @@
/* TransformConstructors Copyright (C) 1998-1999 Jochen Hoenicke. /* TransformConstructors Copyright (C) 1998-2001 Jochen Hoenicke.
* *
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by
@ -585,7 +585,8 @@ public class TransformConstructors {
* @param expr the initializer to check * @param expr the initializer to check
* @return the transformed initializer or null if expr is not valid. * @return the transformed initializer or null if expr is not valid.
*/ */
private Expression transformFieldInitializer(Expression expr) { private Expression transformFieldInitializer(int fieldSlot,
Expression expr) {
if (expr instanceof LocalVarOperator) { if (expr instanceof LocalVarOperator) {
if (!(expr instanceof LocalLoadOperator)) { if (!(expr instanceof LocalLoadOperator)) {
if ((GlobalOptions.debuggingFlags if ((GlobalOptions.debuggingFlags
@ -606,11 +607,21 @@ public class TransformConstructors {
+" "+outerValues); +" "+outerValues);
return null; return null;
} }
if (expr instanceof FieldOperator) {
if (expr instanceof PutFieldOperator)
return null;
FieldOperator fo = (FieldOperator) expr;
if (fo.getClassInfo() == clazzAnalyzer.getClazz()
&& clazzAnalyzer.getFieldIndex(fo.getFieldName(),
fo.getFieldType()) >= fieldSlot)
return null;
}
if (expr instanceof Operator) { if (expr instanceof Operator) {
Operator op = (Operator) expr; Operator op = (Operator) expr;
Expression[] subExpr = op.getSubExpressions(); Expression[] subExpr = op.getSubExpressions();
for (int i=0; i< subExpr.length; i++) { for (int i=0; i< subExpr.length; i++) {
Expression transformed = transformFieldInitializer(subExpr[i]); Expression transformed
= transformFieldInitializer(fieldSlot, subExpr[i]);
if (transformed == null) if (transformed == null)
return null; return null;
if (transformed != subExpr[i]) if (transformed != subExpr[i])
@ -693,7 +704,7 @@ public class TransformConstructors {
break big_loop; break big_loop;
Expression expr = store.getSubExpressions()[1]; Expression expr = store.getSubExpressions()[1];
expr = transformFieldInitializer(expr); expr = transformFieldInitializer(field, expr);
if (expr == null) if (expr == null)
break big_loop; break big_loop;
@ -780,8 +791,14 @@ public class TransformConstructors {
} }
} }
int field = clazzAnalyzer.getFieldIndex(pfo.getFieldName(),
pfo.getFieldType());
if (field <= lastField)
return -1;
Expression expr = store.getSubExpressions()[1]; Expression expr = store.getSubExpressions()[1];
expr = transformFieldInitializer(expr); expr = transformFieldInitializer(field, expr);
if (expr == null) if (expr == null)
return -1; return -1;
@ -790,9 +807,6 @@ public class TransformConstructors {
GlobalOptions.err.println(" field " + pfo.getFieldName() GlobalOptions.err.println(" field " + pfo.getFieldName()
+ " = " + expr); + " = " + expr);
int field = clazzAnalyzer.getFieldIndex(pfo.getFieldName(),
pfo.getFieldType());
// if field does not exists: -1 <= lastField. // if field does not exists: -1 <= lastField.
if (field <= lastField if (field <= lastField
|| !(clazzAnalyzer.getField(field).setInitializer(expr))) { || !(clazzAnalyzer.getField(field).setInitializer(expr))) {

@ -185,11 +185,7 @@ public class TransformExceptionHandlers {
* @param ret the ReturnBlock. * @param ret the ReturnBlock.
*/ */
private void removeReturnLocal(ReturnBlock ret) { private void removeReturnLocal(ReturnBlock ret) {
if (ret.outer == null StructuredBlock pred = getPredecessor(ret);
|| !(ret.outer instanceof SequentialBlock))
return;
StructuredBlock pred = ret.outer.getSubBlocks()[0];
if (!(pred instanceof InstructionBlock)) if (!(pred instanceof InstructionBlock))
return; return;
Expression instr = ((InstructionBlock) pred).getInstruction(); Expression instr = ((InstructionBlock) pred).getInstruction();
@ -208,15 +204,13 @@ public class TransformExceptionHandlers {
} }
/** /**
* Remove the JSR's jumping to the specified subRoutine. It * Remove the wrongly placed JSRs jumping to the specified
* is checked if the next block is a leaving instruction, and * subRoutine. The right JSRs are already removed, but we have to
* otherwise the JsrBlock is not removed (to give the user a * replace the wrong ones with a warning.
* hint that something went wrong). This will also remove the
* local javac generates for returns.
* @param tryFlow the FlowBLock of the try block. * @param tryFlow the FlowBLock of the try block.
* @param subRoutine the FlowBlock of the sub routine. * @param subRoutine the FlowBlock of the sub routine.
*/ */
private void removeJSR(FlowBlock tryFlow, StructuredBlock catchBlock, private void removeBadJSR(FlowBlock tryFlow, StructuredBlock catchBlock,
FlowBlock subRoutine) { FlowBlock subRoutine) {
Jump nextJump; Jump nextJump;
for (Jump jumps = tryFlow.getJumps(subRoutine); for (Jump jumps = tryFlow.getJumps(subRoutine);
@ -230,105 +224,130 @@ public class TransformExceptionHandlers {
/* This is the mandatory jsr in the catch block */ /* This is the mandatory jsr in the catch block */
continue; continue;
} }
if (prev.outer.getNextFlowBlock() != null) { /* We have a JSR to the subroutine, which is badly placed.
/* The jsr is directly before a jump, okay. */ * We complain here.
tryFlow.removeSuccessor(jumps); */
prev.removeJump(); DescriptionBlock msg
prev.outer.removeBlock(); = new DescriptionBlock("ERROR: JSR FINALLY BLOCK!");
continue; tryFlow.removeSuccessor(jumps);
} prev.removeJump();
if (prev.outer.outer instanceof SequentialBlock msg.replace(prev.outer);
&& prev.outer.outer.getSubBlocks()[0] == prev.outer) { } else {
SequentialBlock seq = (SequentialBlock) prev.outer.outer; /* We have a jump to the subroutine, that is wrong.
if (seq.subBlocks[1] instanceof JsrBlock * We complain here.
|| (seq.subBlocks[1] instanceof SequentialBlock */
&& seq.subBlocks[1].getSubBlocks()[0] DescriptionBlock msg
instanceof JsrBlock)) { = new DescriptionBlock("ERROR: GOTO FINALLY BLOCK!");
/* The jsr is followed by a jsr, okay. */ tryFlow.removeSuccessor(jumps);
tryFlow.removeSuccessor(jumps); prev.removeJump();
prev.removeJump(); prev.appendBlock(msg);
prev.outer.removeBlock(); }
continue; }
} }
if (seq.subBlocks[1] instanceof ReturnBlock
&& !(seq.subBlocks[1] instanceof ThrowBlock)) { private static StructuredBlock getPredecessor(StructuredBlock stmt)
{
/* The jsr is followed by a return, okay. */ if (stmt.outer instanceof SequentialBlock) {
tryFlow.removeSuccessor(jumps); SequentialBlock seq = (SequentialBlock) stmt.outer;
prev.removeJump(); if (seq.subBlocks[1] == stmt)
ReturnBlock ret = (ReturnBlock) seq.subBlocks[1]; return seq.subBlocks[0];
prev.outer.removeBlock(); else if (seq.outer instanceof SequentialBlock)
return seq.outer.getSubBlocks()[0];
removeReturnLocal(ret); }
continue; return null;
} }
}
/**
* Gets the slot of the monitorexit instruction instr in the
* stmt, or -1 if stmt isn't a InstructionBlock with a
* monitorexit instruction.
* @param stmt the stmt, may be null.
*/
private static int getMonitorExitSlot(StructuredBlock stmt) {
if (stmt instanceof InstructionBlock) {
Expression instr = ((InstructionBlock) stmt).getInstruction();
if (instr instanceof MonitorExitOperator) {
MonitorExitOperator monExit = (MonitorExitOperator)instr;
if (monExit.getFreeOperandCount() == 0
&& (monExit.getSubExpressions()[0]
instanceof LocalLoadOperator))
return ((LocalLoadOperator) monExit.getSubExpressions()[0])
.getLocalInfo().getSlot();
} }
/* Now we have a jump to the subroutine, that is wrong.
* We complain here.
*/
DescriptionBlock msg
= new DescriptionBlock("ERROR: GOTO FINALLY BLOCK!");
tryFlow.removeSuccessor(jumps);
prev.removeJump();
prev.appendBlock(msg);
} }
return -1;
}
private boolean isMonitorExitSubRoutine(FlowBlock subRoutine,
LocalInfo local) {
if (transformSubRoutine(subRoutine.block)
&& getMonitorExitSlot(subRoutine.block) == local.getSlot())
return true;
return false;
} }
public void checkAndRemoveJSR(FlowBlock tryFlow, private static StructuredBlock skipFinExitChain(StructuredBlock block)
StructuredBlock catchBlock, {
FlowBlock subRoutine, StructuredBlock pred, result;
int startOutExit, int endOutExit) { if (block instanceof ReturnBlock)
boolean foundSub = false; pred = getPredecessor(block);
else
pred = block;
result = null;
while (pred instanceof JsrBlock
|| getMonitorExitSlot(pred) >= 0) {
result = pred;
pred = getPredecessor(pred);
}
return result;
}
private void checkAndRemoveJSR(FlowBlock tryFlow,
StructuredBlock catchBlock,
FlowBlock subRoutine,
int startOutExit, int endOutExit) {
Iterator iter = tryFlow.getSuccessors().iterator(); Iterator iter = tryFlow.getSuccessors().iterator();
dest_loop: dest_loop:
while (iter.hasNext()) { while (iter.hasNext()) {
FlowBlock dest = (FlowBlock) iter.next(); FlowBlock dest = (FlowBlock) iter.next();
if (dest == subRoutine) { if (dest == subRoutine)
foundSub = true;
continue dest_loop; continue dest_loop;
}
boolean isFirstJump = true; boolean isFirstJump = true;
for (Jump jumps = tryFlow.getJumps(dest); for (Jump jumps = tryFlow.getJumps(dest);
jumps != null; jumps = jumps.next, isFirstJump = false) { jumps != null; jumps = jumps.next, isFirstJump = false) {
StructuredBlock prev = jumps.prev; StructuredBlock prev = jumps.prev;
if (prev instanceof JsrBlock) {
/* The jump is directly preceeded by a jsr.
* Everything okay.
*/
continue;
}
if (prev instanceof EmptyBlock if (prev instanceof EmptyBlock
&& prev.outer instanceof JsrBlock) { && prev.outer instanceof JsrBlock) {
/* If jump is a jsr check the outer /* This jump is really a jsr, since it doesn't
* block instead. * leave the block forever, we can ignore it.
*/ */
prev = prev.outer; continue;
}
if ((prev instanceof ReturnBlock
|| prev instanceof JsrBlock)
&& prev.outer instanceof SequentialBlock) {
SequentialBlock seq = (SequentialBlock) prev.outer;
if (seq.subBlocks[1] == prev
&& (seq.subBlocks[0] instanceof JsrBlock)) {
/* The jump is preceeded by another jsr, okay.
*/
continue;
}
if (seq.subBlocks[0] == prev
&& seq.outer instanceof SequentialBlock
&& (seq.outer.getSubBlocks()[0] instanceof JsrBlock)) {
/* Again the jump is preceeded by another jsr, okay.
*/
continue;
}
} }
if (isFirstJump) { StructuredBlock pred = skipFinExitChain(prev);
/* Now we have a jump that is not preceded by the if (pred instanceof JsrBlock) {
StructuredBlock jsrInner = ((JsrBlock) pred).innerBlock;
if (jsrInner instanceof EmptyBlock
&& jsrInner.jump != null
&& jsrInner.jump.destination == subRoutine) {
/* The jump is preceeded by the right jsr. Remove
* the jsr.
*/
tryFlow.removeSuccessor(jsrInner.jump);
jsrInner.removeJump();
pred.removeBlock();
if (prev instanceof ReturnBlock)
removeReturnLocal((ReturnBlock) prev);
continue;
}
}
if (pred == null && isFirstJump) {
/* Now we have a jump that is not preceded by any
* jsr. There's a last chance: the jump jumps * jsr. There's a last chance: the jump jumps
* directly to a correct jsr instruction, which * directly to a correct jsr instruction, which
* lies outside the try/catch block. * lies outside the try/catch block.
@ -359,45 +378,21 @@ public class TransformExceptionHandlers {
*/ */
DescriptionBlock msg DescriptionBlock msg
= new DescriptionBlock("ERROR: NO JSR TO FINALLY"); = new DescriptionBlock("ERROR: NO JSR TO FINALLY");
prev.appendBlock(msg); if (pred != null)
msg.moveJump(jumps); pred.prependBlock(msg);
} else {
} prev.appendBlock(msg);
if (foundSub) msg.moveJump(prev.jump);
removeJSR(tryFlow, catchBlock, subRoutine); }
}
static boolean isMonitorExit(Expression instr, LocalInfo local) {
if (instr instanceof MonitorExitOperator) {
MonitorExitOperator monExit = (MonitorExitOperator)instr;
if (monExit.getFreeOperandCount() == 0
&& monExit.getSubExpressions()[0] instanceof LocalLoadOperator
&& (((LocalLoadOperator) monExit.getSubExpressions()[0])
.getLocalInfo().getSlot() == local.getSlot())) {
return true;
} }
} }
return false; removeBadJSR(tryFlow, catchBlock, subRoutine);
}
boolean isMonitorExitSubRoutine(FlowBlock subRoutine, LocalInfo local) {
if (transformSubRoutine(subRoutine.block)) {
if (subRoutine.block instanceof InstructionBlock) {
Expression instr =
((InstructionBlock)subRoutine.block)
.getInstruction();
if (isMonitorExit(instr, local)) {
return true;
}
}
}
return false;
} }
public void checkAndRemoveMonitorExit(FlowBlock tryFlow, private void checkAndRemoveMonitorExit(FlowBlock tryFlow,
StructuredBlock catchBlock, StructuredBlock catchBlock,
LocalInfo local, LocalInfo local,
int start, int end) { int start, int end) {
FlowBlock subRoutine = null; FlowBlock subRoutine = null;
Iterator succs = tryFlow.getSuccessors().iterator(); Iterator succs = tryFlow.getSuccessors().iterator();
dest_loop: dest_loop:
@ -408,85 +403,51 @@ public class TransformExceptionHandlers {
jumps != null; jumps = jumps.next, isFirstJump = false) { jumps != null; jumps = jumps.next, isFirstJump = false) {
StructuredBlock prev = jumps.prev; StructuredBlock prev = jumps.prev;
if (prev instanceof JsrBlock) {
/* The jump is directly preceeded by a jsr.
*/
continue;
}
if (prev instanceof EmptyBlock if (prev instanceof EmptyBlock
&& prev.outer instanceof JsrBlock) { && prev.outer instanceof JsrBlock) {
/* If jump is a jsr check the outer /* This jump is really a jsr, since it doesn't
* block instead. * leave the block forever, we can ignore it.
*/
prev = prev.outer;
}
/* If the block is a jsr or a return block, check if
* it is preceeded by another jsr.
*/
if ((prev instanceof JsrBlock
|| prev instanceof ReturnBlock)
&& prev.outer instanceof SequentialBlock) {
SequentialBlock seq = (SequentialBlock) prev.outer;
StructuredBlock pred = null;
if (seq.subBlocks[1] == prev)
pred = seq.subBlocks[0];
else if (seq.outer instanceof SequentialBlock)
pred = seq.outer.getSubBlocks()[0];
if (pred != null) {
if (pred instanceof JsrBlock)
/* The jump is preceeded by another jsr, okay.
*/
continue;
if (pred instanceof InstructionBlock) {
Expression instr =
((InstructionBlock)pred).getInstruction();
if (isMonitorExit(instr, local)) {
pred.removeBlock();
if (prev instanceof ReturnBlock)
removeReturnLocal((ReturnBlock) prev);
continue;
}
}
}
}
if (prev instanceof InstructionBlock
&& isMonitorExit(((InstructionBlock)prev).instr, local)) {
/* This is probably the last expression in the
* synchronized block, and has the right monitor exit
* attached. Remove this block.
*/
prev.removeBlock();
continue;
}
if (isFirstJump) {
/* This is the first jump to that destination.
* Check if the destination does the monitorExit
*/ */
continue;
}
StructuredBlock pred = skipFinExitChain(prev);
if (pred instanceof JsrBlock) {
StructuredBlock jsrInner = ((JsrBlock) pred).innerBlock;
if (jsrInner instanceof EmptyBlock
&& jsrInner.jump != null) {
FlowBlock dest = jsrInner.jump.destination;
/* The block is a jsr that is not preceeded by
* another jsr. This must be the monitorexit
* subroutine.
*/
if (prev instanceof JsrBlock) {
if (subRoutine == null if (subRoutine == null
&& successor.getBlockNr() >= start && dest.getBlockNr() >= start
&& successor.getNextBlockNr() <= end) { && dest.getNextBlockNr() <= end) {
successor.analyze(start, end); dest.analyze(start, end);
if (isMonitorExitSubRoutine(dest, local))
if (isMonitorExitSubRoutine(successor, local)) subRoutine = dest;
subRoutine = successor;
} }
if (subRoutine == successor) if (dest == subRoutine) {
continue dest_loop; /* The jump is preceeded by the right jsr. Remove
* the jsr.
*/
tryFlow.removeSuccessor(jsrInner.jump);
jsrInner.removeJump();
pred.removeBlock();
if (prev instanceof ReturnBlock)
removeReturnLocal((ReturnBlock) prev);
continue;
}
} }
} else if (getMonitorExitSlot(pred) == local.getSlot()) {
/* The jump is preceeded by the right monitor
* exit instruction.
*/
pred.removeBlock();
if (prev instanceof ReturnBlock)
removeReturnLocal((ReturnBlock) prev);
continue;
}
if (pred == null && isFirstJump) {
/* Now we have a jump that is not preceded by a /* Now we have a jump that is not preceded by a
* monitorexit. There's a last chance: the jump * monitorexit. There's a last chance: the jump
* jumps directly to the correct monitorexit * jumps directly to the correct monitorexit
@ -514,17 +475,15 @@ public class TransformExceptionHandlers {
} }
if (subRoutine == dest) { if (subRoutine == dest) {
successor.removeSuccessor(jsrInner.jump);
jsrInner.removeJump();
sb.removeBlock(); sb.removeBlock();
continue dest_loop; continue dest_loop;
} }
} }
if (sb instanceof InstructionBlock) { if (getMonitorExitSlot(sb) == local.getSlot()) {
Expression instr = ((InstructionBlock)sb) sb.removeBlock();
.getInstruction(); continue dest_loop;
if (isMonitorExit(instr, local)) {
sb.removeBlock();
continue dest_loop;
}
} }
} }
} }
@ -539,7 +498,7 @@ public class TransformExceptionHandlers {
} }
if (subRoutine != null) { if (subRoutine != null) {
removeJSR(tryFlow, catchBlock, subRoutine); removeBadJSR(tryFlow, catchBlock, subRoutine);
tryFlow.mergeBlockNr(subRoutine); tryFlow.mergeBlockNr(subRoutine);
} }
} }

@ -286,19 +286,17 @@ public class CodeVerifier implements Opcodes {
dimensions++; dimensions++;
} }
if (c1 == '[' || c2 == '[') { // One of them is array now, the other is an object,
// Only one of them is array now, the other must be an // the common super is tObject
// object, the common super is tObject if ((c1 == '[' && c2 == 'L')
if (c1 == 'L' || c2 == 'L') { || (c1 == 'L' && c2 == '[')) {
if (dimensions == 0) if (dimensions == 0)
return cv.tObject; return cv.tObject;
StringBuffer result = new StringBuffer(dimensions + 18); StringBuffer result = new StringBuffer(dimensions + 18);
for (int i=0; i< dimensions; i++) for (int i=0; i< dimensions; i++)
result.append("["); result.append("[");
result.append("Ljava/lang/Object;"); result.append("Ljava/lang/Object;");
return cv.tType(result.toString()); return cv.tType(result.toString());
}
return cv.tNone;
} }
if (c1 == 'L' && c2 == 'L') { if (c1 == 'L' && c2 == 'L') {
@ -338,6 +336,18 @@ public class CodeVerifier implements Opcodes {
result.append("L"); result.append("L");
return cv.tType(result.toString(), clazz1); return cv.tType(result.toString(), clazz1);
} }
// Both were arrays, but of different primitive types. The
// common super is tObject with one dimension less.
if (dimensions > 0) {
if (dimensions == 1)
return cv.tObject;
StringBuffer result = new StringBuffer(dimensions + 17);
for (int i=0; i< dimensions - 1; i++)
result.append("[");
result.append("Ljava/lang/Object;");
return cv.tType(result.toString());
}
return cv.tNone; return cv.tNone;
} }

@ -168,6 +168,7 @@ public class Main
public class AreaWriter extends Writer { public class AreaWriter extends Writer {
boolean initialized = false; boolean initialized = false;
boolean lastCR = false;
private JTextArea area; private JTextArea area;
public AreaWriter(JTextArea a) { public AreaWriter(JTextArea a) {
@ -180,7 +181,23 @@ public class Main
area.setText(""); area.setText("");
initialized = true; initialized = true;
} }
area.append(new String(b, off, len)); String str = new String(b, off, len);
StringBuffer sb = new StringBuffer(len);
while (str != null && str.length() > 0) {
if (lastCR && str.charAt(0) == '\n')
str = str.substring(1);
int crIndex = str.indexOf('\r');
if (crIndex >= 0) {
sb.append(str.substring(0, crIndex));
sb.append("\n");
str = str.substring(crIndex+1);
lastCR = true;
} else {
sb.append(str);
str = null;
}
}
area.append(sb.toString());
} }
public void flush() { public void flush() {

@ -122,8 +122,9 @@ public class ArrayType extends ClassType {
if (type == tNull) if (type == tNull)
return this; return this;
if (type.getTypeCode() == TC_ARRAY) { if (type.getTypeCode() == TC_ARRAY) {
return tArray(elementType.intersection Type elType = elementType.intersection
(((ArrayType)type).elementType)); (((ArrayType)type).elementType);
return elType != tError ? tArray(elType) : tError;
} }
if (type.isSubTypeOf(this)) if (type.isSubTypeOf(this))
return this; return this;
@ -138,7 +139,7 @@ public class ArrayType extends ClassType {
public Type getGeneralizedType(Type type) { public Type getGeneralizedType(Type type) {
/* tArray(x), tNull -> tArray(x) /* tArray(x), tNull -> tArray(x)
* tArray(x), tClass(y) -> common ifaces of tArray and tClass * tArray(x), tClass(y) -> common ifaces of tArray and tClass
* tArray(x), tArray(y) -> tArray(x.intersection(y)) * tArray(x), tArray(y) -> tArray(x.intersection(y)) or tObject
* tArray(x), other -> tError * tArray(x), other -> tError
*/ */
if (type.getTypeCode() == TC_RANGE) { if (type.getTypeCode() == TC_RANGE) {
@ -146,10 +147,11 @@ public class ArrayType extends ClassType {
} }
if (type == tNull) if (type == tNull)
return this; return this;
if (type instanceof ArrayType) if (type.getTypeCode() == TC_ARRAY) {
return tArray(elementType.intersection Type elType = elementType.intersection
(((ArrayType)type).elementType)); (((ArrayType)type).elementType);
return elType != tError ? tArray(elType) : tObject;
}
if (!(type instanceof ReferenceType)) if (!(type instanceof ReferenceType))
return tError; return tError;

@ -271,6 +271,8 @@ public abstract class ClassType extends ReferenceType {
private final static Hashtable keywords = new Hashtable(); private final static Hashtable keywords = new Hashtable();
static { static {
keywords.put("package", Boolean.TRUE);
keywords.put("import", Boolean.TRUE);
keywords.put("if", Boolean.TRUE); keywords.put("if", Boolean.TRUE);
keywords.put("else", Boolean.TRUE); keywords.put("else", Boolean.TRUE);
keywords.put("for", Boolean.TRUE); keywords.put("for", Boolean.TRUE);

@ -1,4 +1,4 @@
/* UnifyHash Copyright (C) 1999 Jochen Hoenicke. /* UnifyHash Copyright (C) 1999-2001 Jochen Hoenicke.
* *
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by
@ -186,6 +186,9 @@ public class UnifyHash extends AbstractCollection {
} }
public Iterator iterateHashCode(final int hash) { public Iterator iterateHashCode(final int hash) {
///#ifdef JDK12
cleanUp();
///#endif
return new Iterator() { return new Iterator() {
private int known = modCount; private int known = modCount;
private Bucket nextBucket private Bucket nextBucket

Loading…
Cancel
Save