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>
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
type change as well.
* jode/decompiler/LocalInfo.java (combineWith): Reorganized a bit,
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
class is used. And always qualify the this operator if not
innermost.
@ -22,11 +77,11 @@
(printOptionalSpace): Print space for GNU_SPACING.
* jode/decompiler/Options.java (setOptions): changed gnu style
to include GNU_SPACING.
* jode/decompiler/ClassAnalyzer.java.in (dumpSource): Use
* jode/decompiler/ClassAnalyzer.java (dumpSource): Use
open/closeBraceClass.
* jode/decompiler/MethodAnalyzer.java.in (dumpSource): Use
* jode/decompiler/MethodAnalyzer.java (dumpSource): Use
open/closeBraceNoIndent. Call printOptionalSpace.
* jode/decompiler/InvokeOperator.java.in (dumpExpression):
* jode/decompiler/InvokeOperator.java (dumpExpression):
Call printOptionalSpace, use open/closeBraceClass for inner
classes.
* jode/decompiler/UnaryOperator.java (dumpExpression): Call
@ -43,7 +98,7 @@
version in ReferenceType is more correct. Before
tNull.isOfType(tRange(X,tNull)) returned false, which lead to
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
field could be initialized in a constructor.
* jode/decompiler/TabbedPrintWriter.java (BreakPoint.endOp):

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

@ -1,7 +1,7 @@
dnl Process this file with autoconf to produce a configure script.
AC_INIT()
AM_INIT_AUTOMAKE(jode, 1.0.93)
AM_INIT_AUTOMAKE(jode, 1.0.94)
dnl Checks for programs.
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
* 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 email = "jochen@gnu.org";
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 static PrintWriter err = new PrintWriter(System.err, true);

@ -828,6 +828,21 @@ class BasicBlockReader implements Opcodes {
int index = input.readUnsignedShort();
handlers[i].type = (index == 0) ? null
: 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++) {

@ -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
* 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();
}
}
if (subExpressions[0] instanceof CompareUnaryOperator
&& (subExpressions[1] instanceof GetFieldOperator)
&& (subExpressions[2] instanceof StoreInstruction)) {
// Check for
// class$classname != null ? class$classname :
// (class$classname = class$("classname"))
// and replace with
// classname.class
if (subExpressions[0] instanceof CompareUnaryOperator
&& ((((CompareUnaryOperator) subExpressions[0])
.getOperatorIndex() & ~1) == Operator.COMPARE_OP)) {
CompareUnaryOperator cmp
= (CompareUnaryOperator) subExpressions[0];
GetFieldOperator get = (GetFieldOperator) subExpressions[1];
StoreInstruction put = (StoreInstruction) subExpressions[2];
FieldAnalyzer field;
if (cmp.getOperatorIndex() == Operator.NOTEQUALS_OP
&& put.getLValue() instanceof PutFieldOperator
&& ((field = ((PutFieldOperator)put.getLValue()).getField())
!= null) && field.isSynthetic()
&& put.lvalueMatches(get)
&& cmp.subExpressions[0] instanceof GetFieldOperator
&& put.lvalueMatches((GetFieldOperator)cmp.subExpressions[0])
&& put.subExpressions[1] instanceof InvokeOperator) {
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));
int cmpType = cmp.getOperatorIndex() & 1;
if ((subExpressions[2 - cmpType] instanceof GetFieldOperator)
&& (subExpressions[1 + cmpType] instanceof StoreInstruction)) {
// Check for
// class$classname != null ? class$classname :
// (class$classname = class$("classname"))
// and replace with
// classname.class
GetFieldOperator get
= (GetFieldOperator) subExpressions[2 - cmpType];
StoreInstruction put
= (StoreInstruction) subExpressions[1 + cmpType];
int opIndex = cmp.getOperatorIndex();
FieldAnalyzer field;
if (put.getLValue() instanceof PutFieldOperator
&& ((field = ((PutFieldOperator)put.getLValue())
.getField()) != null) && field.isSynthetic()
&& put.lvalueMatches(get)
&& (cmp.subExpressions[0] instanceof GetFieldOperator)
&& put.lvalueMatches((GetFieldOperator)
cmp.subExpressions[0])
&& put.subExpressions[1] instanceof InvokeOperator) {
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;
import jode.type.Type;
import jode.decompiler.LocalInfo;
import jode.decompiler.Declarable;
import jode.expr.Expression;
import jode.expr.LocalLoadOperator;
import jode.expr.LocalStoreOperator;
@ -28,6 +29,7 @@ import jode.util.SimpleSet;
///#def COLLECTIONS java.util
import java.util.Collections;
import java.util.Iterator;
import java.util.Set;
///#enddef
@ -162,6 +164,16 @@ public class CatchBlock extends StructuredBlock {
ib.appendBlock(catchBlock);
catchBlock = ib;
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;
}
/**
* 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)
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.
*/

@ -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
* 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
* @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 LocalLoadOperator)) {
if ((GlobalOptions.debuggingFlags
@ -606,11 +607,21 @@ public class TransformConstructors {
+" "+outerValues);
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) {
Operator op = (Operator) expr;
Expression[] subExpr = op.getSubExpressions();
for (int i=0; i< subExpr.length; i++) {
Expression transformed = transformFieldInitializer(subExpr[i]);
Expression transformed
= transformFieldInitializer(fieldSlot, subExpr[i]);
if (transformed == null)
return null;
if (transformed != subExpr[i])
@ -693,7 +704,7 @@ public class TransformConstructors {
break big_loop;
Expression expr = store.getSubExpressions()[1];
expr = transformFieldInitializer(expr);
expr = transformFieldInitializer(field, expr);
if (expr == null)
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];
expr = transformFieldInitializer(expr);
expr = transformFieldInitializer(field, expr);
if (expr == null)
return -1;
@ -790,9 +807,6 @@ public class TransformConstructors {
GlobalOptions.err.println(" field " + pfo.getFieldName()
+ " = " + expr);
int field = clazzAnalyzer.getFieldIndex(pfo.getFieldName(),
pfo.getFieldType());
// if field does not exists: -1 <= lastField.
if (field <= lastField
|| !(clazzAnalyzer.getField(field).setInitializer(expr))) {

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

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

@ -168,6 +168,7 @@ public class Main
public class AreaWriter extends Writer {
boolean initialized = false;
boolean lastCR = false;
private JTextArea area;
public AreaWriter(JTextArea a) {
@ -180,7 +181,23 @@ public class Main
area.setText("");
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() {

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

@ -271,6 +271,8 @@ public abstract class ClassType extends ReferenceType {
private final static Hashtable keywords = new Hashtable();
static {
keywords.put("package", Boolean.TRUE);
keywords.put("import", Boolean.TRUE);
keywords.put("if", Boolean.TRUE);
keywords.put("else", 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
* 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) {
///#ifdef JDK12
cleanUp();
///#endif
return new Iterator() {
private int known = modCount;
private Bucket nextBucket

Loading…
Cancel
Save